1479bb0035664516a85cf167fcb79ca5b3fcd126
[snaps.git] / snaps / openstack / create_flavor.py
1 # Copyright (c) 2016 Cable Television Laboratories, Inc. ("CableLabs")
2 #                    and others.  All rights reserved.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 import logging
16
17 from novaclient.exceptions import NotFound
18
19 from snaps.openstack.openstack_creator import OpenStackComputeObject
20 from snaps.openstack.utils import nova_utils
21
22 __author__ = 'spisarski'
23
24 logger = logging.getLogger('create_flavor')
25
26 MEM_PAGE_SIZE_ANY = {'hw:mem_page_size': 'any'}
27 MEM_PAGE_SIZE_LARGE = {'hw:mem_page_size': 'large'}
28
29
30 class OpenStackFlavor(OpenStackComputeObject):
31     """
32     Class responsible for creating a user in OpenStack
33     """
34
35     def __init__(self, os_creds, flavor_settings):
36         """
37         Constructor
38         :param os_creds: The OpenStack connection credentials
39         :param flavor_settings: The flavor settings
40         :return:
41         """
42         super(self.__class__, self).__init__(os_creds)
43
44         self.flavor_settings = flavor_settings
45         self.__flavor = None
46
47     def initialize(self):
48         """
49         Loads the existing OpenStack flavor
50         :return: The Flavor domain object or None
51         """
52         super(self.__class__, self).initialize()
53
54         self.__flavor = nova_utils.get_flavor_by_name(
55             self._nova, self.flavor_settings.name)
56         if self.__flavor:
57             logger.info('Found flavor with name - %s',
58                         self.flavor_settings.name)
59         return self.__flavor
60
61     def create(self):
62         """
63         Creates the image in OpenStack if it does not already exist
64         :return: The OpenStack flavor object
65         """
66         self.initialize()
67         if not self.__flavor:
68             self.__flavor = nova_utils.create_flavor(
69                 self._nova, self.flavor_settings)
70             if self.flavor_settings.metadata:
71                 nova_utils.set_flavor_keys(self._nova, self.__flavor,
72                                            self.flavor_settings.metadata)
73         else:
74             logger.info('Did not create flavor due to cleanup mode')
75
76         return self.__flavor
77
78     def clean(self):
79         """
80         Cleanse environment of all artifacts
81         :return: void
82         """
83         if self.__flavor:
84             try:
85                 nova_utils.delete_flavor(self._nova, self.__flavor)
86             except NotFound:
87                 pass
88
89             self.__flavor = None
90
91     def get_flavor(self):
92         """
93         Returns the OpenStack flavor object
94         :return:
95         """
96         return self.__flavor
97
98
99 class FlavorSettings:
100     """
101     Configuration settings for OpenStack flavor creation
102     """
103
104     def __init__(self, **kwargs):
105         """
106         Constructor
107         :param config: dict() object containing the configuration settings
108                        using the attribute names below as each member's the
109                        key and overrides any of the other parameters.
110         :param name: the flavor's name (required)
111         :param flavor_id: the string ID (default 'auto')
112         :param ram: the required RAM in MB (required)
113         :param disk: the size of the root disk in GB (required)
114         :param vcpus: the number of virtual CPUs (required)
115         :param ephemeral: the size of the ephemeral disk in GB (default 0)
116         :param swap: the size of the dedicated swap disk in GB (default 0)
117         :param rxtx_factor: the receive/transmit factor to be set on ports if
118                             backend supports QoS extension (default 1.0)
119         :param is_public: denotes whether or not the flavor is public
120                           (default True)
121         :param metadata: freeform dict() for special metadata
122         """
123         self.name = kwargs.get('name')
124
125         if kwargs.get('flavor_id'):
126             self.flavor_id = kwargs['flavor_id']
127         else:
128             self.flavor_id = 'auto'
129
130         self.ram = kwargs.get('ram')
131         self.disk = kwargs.get('disk')
132         self.vcpus = kwargs.get('vcpus')
133
134         if kwargs.get('ephemeral'):
135             self.ephemeral = kwargs['ephemeral']
136         else:
137             self.ephemeral = 0
138
139         if kwargs.get('swap'):
140             self.swap = kwargs['swap']
141         else:
142             self.swap = 0
143
144         if kwargs.get('rxtx_factor'):
145             self.rxtx_factor = kwargs['rxtx_factor']
146         else:
147             self.rxtx_factor = 1.0
148
149         if kwargs.get('is_public') is not None:
150             self.is_public = kwargs['is_public']
151         else:
152             self.is_public = True
153
154         if kwargs.get('metadata'):
155             self.metadata = kwargs['metadata']
156         else:
157             self.metadata = None
158
159         if not self.name or not self.ram or not self.disk or not self.vcpus:
160             raise FlavorSettingsError(
161                 'The attributes name, ram, disk, and vcpus are required for'
162                 'FlavorSettings')
163
164         if not isinstance(self.ram, int):
165             raise FlavorSettingsError('The ram attribute must be a integer')
166
167         if not isinstance(self.disk, int):
168             raise FlavorSettingsError('The ram attribute must be a integer')
169
170         if not isinstance(self.vcpus, int):
171             raise FlavorSettingsError('The vcpus attribute must be a integer')
172
173         if self.ephemeral and not isinstance(self.ephemeral, int):
174             raise FlavorSettingsError(
175                 'The ephemeral attribute must be an integer')
176
177         if self.swap and not isinstance(self.swap, int):
178             raise FlavorSettingsError('The swap attribute must be an integer')
179
180         if self.rxtx_factor and not isinstance(self.rxtx_factor, (int, float)):
181             raise FlavorSettingsError(
182                 'The is_public attribute must be an integer or float')
183
184         if self.is_public and not isinstance(self.is_public, bool):
185             raise FlavorSettingsError(
186                 'The is_public attribute must be a boolean')
187
188
189 class FlavorSettingsError(Exception):
190     """
191     Exception to be thrown when an flavor settings are incorrect
192     """