Merge "Changes to VMInstanceSettings and FloatingIPSettings constructors."
[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.utils import nova_utils
20
21 __author__ = 'spisarski'
22
23 logger = logging.getLogger('create_image')
24
25 MEM_PAGE_SIZE_ANY = {'hw:mem_page_size': 'any'}
26 MEM_PAGE_SIZE_LARGE = {'hw:mem_page_size': 'large'}
27
28
29 class OpenStackFlavor:
30     """
31     Class responsible for creating a user in OpenStack
32     """
33
34     def __init__(self, os_creds, flavor_settings):
35         """
36         Constructor
37         :param os_creds: The OpenStack connection credentials
38         :param flavor_settings: The flavor settings
39         :return:
40         """
41         self.__os_creds = os_creds
42         self.flavor_settings = flavor_settings
43         self.__flavor = None
44         self.__nova = None
45
46     def create(self, cleanup=False):
47         """
48         Creates the image in OpenStack if it does not already exist
49         :param cleanup: Denotes whether or not this is being called for cleanup
50                         or not
51         :return: The OpenStack flavor object
52         """
53         self.__nova = nova_utils.nova_client(self.__os_creds)
54         self.__flavor = nova_utils.get_flavor_by_name(
55             self.__nova, self.flavor_settings.name)
56         if self.__flavor:
57             logger.info(
58                 'Found flavor with name - ' + self.flavor_settings.name)
59         elif not cleanup:
60             self.__flavor = nova_utils.create_flavor(
61                 self.__nova, self.flavor_settings)
62             if self.flavor_settings.metadata:
63                 self.__flavor.set_keys(self.flavor_settings.metadata)
64             self.__flavor = nova_utils.get_flavor_by_name(
65                 self.__nova, self.flavor_settings.name)
66         else:
67             logger.info('Did not create flavor due to cleanup mode')
68
69         return self.__flavor
70
71     def clean(self):
72         """
73         Cleanse environment of all artifacts
74         :return: void
75         """
76         if self.__flavor:
77             try:
78                 nova_utils.delete_flavor(self.__nova, self.__flavor)
79             except NotFound:
80                 pass
81
82             self.__flavor = None
83
84     def get_flavor(self):
85         """
86         Returns the OpenStack flavor object
87         :return:
88         """
89         return self.__flavor
90
91
92 class FlavorSettings:
93     """
94     Configuration settings for OpenStack flavor creation
95     """
96
97     def __init__(self, **kwargs):
98         """
99         Constructor
100         :param config: dict() object containing the configuration settings
101                        using the attribute names below as each member's the
102                        key and overrides any of the other parameters.
103         :param name: the flavor's name (required)
104         :param flavor_id: the string ID (default 'auto')
105         :param ram: the required RAM in MB (required)
106         :param disk: the size of the root disk in GB (required)
107         :param vcpus: the number of virtual CPUs (required)
108         :param ephemeral: the size of the ephemeral disk in GB (default 0)
109         :param swap: the size of the dedicated swap disk in GB (default 0)
110         :param rxtx_factor: the receive/transmit factor to be set on ports if
111                             backend supports QoS extension (default 1.0)
112         :param is_public: denotes whether or not the flavor is public
113                           (default True)
114         :param metadata: freeform dict() for special metadata
115         """
116         self.name = kwargs.get('name')
117
118         if kwargs.get('flavor_id'):
119             self.flavor_id = kwargs['flavor_id']
120         else:
121             self.flavor_id = 'auto'
122
123         self.ram = kwargs.get('ram')
124         self.disk = kwargs.get('disk')
125         self.vcpus = kwargs.get('vcpus')
126
127         if kwargs.get('ephemeral'):
128             self.ephemeral = kwargs['ephemeral']
129         else:
130             self.ephemeral = 0
131
132         if kwargs.get('swap'):
133             self.swap = kwargs['swap']
134         else:
135             self.swap = 0
136
137         if kwargs.get('rxtx_factor'):
138             self.rxtx_factor = kwargs['rxtx_factor']
139         else:
140             self.rxtx_factor = 1.0
141
142         if kwargs.get('is_public') is not None:
143             self.is_public = kwargs['is_public']
144         else:
145             self.is_public = True
146
147         if kwargs.get('metadata'):
148             self.metadata = kwargs['metadata']
149         else:
150             self.metadata = None
151
152         if not self.name or not self.ram or not self.disk or not self.vcpus:
153             raise Exception(
154                 'The attributes name, ram, disk, and vcpus are required for'
155                 'FlavorSettings')
156
157         if not isinstance(self.ram, int):
158             raise Exception('The ram attribute must be a integer')
159
160         if not isinstance(self.disk, int):
161             raise Exception('The ram attribute must be a integer')
162
163         if not isinstance(self.vcpus, int):
164             raise Exception('The vcpus attribute must be a integer')
165
166         if self.ephemeral and not isinstance(self.ephemeral, int):
167             raise Exception('The ephemeral attribute must be an integer')
168
169         if self.swap and not isinstance(self.swap, int):
170             raise Exception('The swap attribute must be an integer')
171
172         if self.rxtx_factor and not isinstance(self.rxtx_factor, (int, float)):
173             raise Exception(
174                 'The is_public attribute must be an integer or float')
175
176         if self.is_public and not isinstance(self.is_public, bool):
177             raise Exception('The is_public attribute must be a boolean')