Extra changes on Flavor Config
[snaps.git] / snaps / openstack / tests / openstack_tests.py
1 # Copyright (c) 2017 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 import re
17
18 from snaps import file_utils
19 from snaps.config.flavor import FlavorConfig
20 from snaps.config.image import ImageConfig
21 from snaps.config.network import NetworkConfig, SubnetConfig
22 from snaps.config.router import RouterConfig
23 from snaps.openstack.os_credentials import OSCreds, ProxySettings
24
25 __author__ = 'spisarski'
26
27 logger = logging.getLogger('openstack_tests')
28
29 CIRROS_DEFAULT_IMAGE_URL =\
30     'http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-disk.img'
31 CIRROS_DEFAULT_KERNEL_IMAGE_URL =\
32     'http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-kernel'
33 CIRROS_DEFAULT_RAMDISK_IMAGE_URL =\
34     'http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-initramfs'
35 CIRROS_USER = 'cirros'
36
37 CENTOS_DEFAULT_IMAGE_URL =\
38     'http://cloud.centos.org/centos/7/images/' \
39     'CentOS-7-x86_64-GenericCloud.qcow2'
40 CENTOS_USER = 'centos'
41
42 UBUNTU_DEFAULT_IMAGE_URL = \
43     'http://uec-images.ubuntu.com/releases/trusty/14.04/' \
44     'ubuntu-14.04-server-cloudimg-amd64-disk1.img'
45 UBUNTU_USER = 'ubuntu'
46
47 DEFAULT_IMAGE_FORMAT = 'qcow2'
48
49
50 def get_credentials(os_env_file=None, proxy_settings_str=None,
51                     ssh_proxy_cmd=None, dev_os_env_file=None, overrides=None):
52     """
53     Returns the OpenStack credentials object. It first attempts to retrieve
54     them from a standard OpenStack source file. If that file is None, it will
55     attempt to retrieve them with a YAML file.
56     :param os_env_file: the OpenStack source file
57     :param proxy_settings_str: proxy settings string <host>:<port> (optional)
58     :param ssh_proxy_cmd: the SSH proxy command for your environment (optional)
59     :param dev_os_env_file: the YAML file to retrieve both the OS credentials
60                             and proxy settings
61     :param overrides: dict() containing values to override the credentials
62                       found and passed in.
63     :return: the SNAPS credentials object
64     """
65     if os_env_file:
66         logger.debug('Reading RC file - ' + os_env_file)
67         config = file_utils.read_os_env_file(os_env_file)
68         proj_name = config.get('OS_PROJECT_NAME')
69         if not proj_name:
70             proj_name = config.get('OS_TENANT_NAME')
71
72         proxy_settings = None
73         if proxy_settings_str:
74             tokens = re.split(':', proxy_settings_str)
75             proxy_settings = ProxySettings(host=tokens[0], port=tokens[1],
76                                            ssh_proxy_cmd=ssh_proxy_cmd)
77
78         https_cacert = None
79         if config.get('OS_CACERT'):
80             https_cacert = config.get('OS_CACERT')
81         elif config.get('OS_INSECURE'):
82             https_cacert = False
83
84         interface = 'public'
85         if config.get('OS_INTERFACE'):
86             interface = config.get('OS_INTERFACE')
87
88         creds_dict = {
89             'username': config['OS_USERNAME'],
90             'password': config['OS_PASSWORD'],
91             'auth_url': config['OS_AUTH_URL'],
92             'project_name': proj_name,
93             'identity_api_version': config.get('OS_IDENTITY_API_VERSION'),
94             'image_api_version': config.get('OS_IMAGE_API_VERSION'),
95             'network_api_version': config.get('OS_NETWORK_API_VERSION'),
96             'compute_api_version': config.get('OS_COMPUTE_API_VERSION'),
97             'heat_api_version': config.get('OS_HEAT_API_VERSION'),
98             'user_domain_id': config.get('OS_USER_DOMAIN_ID'),
99             'user_domain_name': config.get('OS_USER_DOMAIN_NAME'),
100             'project_domain_id': config.get('OS_PROJECT_DOMAIN_ID'),
101             'project_domain_name': config.get('OS_PROJECT_DOMAIN_NAME'),
102             'volume_api_version': config.get('OS_VOLUME_API_VERSION'),
103             'interface': interface,
104             'proxy_settings': proxy_settings,
105             'cacert': https_cacert,
106             'region_name': config.get('OS_REGION_NAME')}
107     else:
108         logger.info('Reading development os_env file - ' + dev_os_env_file)
109         config = file_utils.read_yaml(dev_os_env_file)
110
111         proxy_settings = None
112         proxy_str = config.get('http_proxy')
113         if proxy_str:
114             tokens = re.split(':', proxy_str)
115             proxy_settings = ProxySettings(
116                 host=tokens[0], port=tokens[1],
117                 ssh_proxy_cmd=config.get('ssh_proxy_cmd'))
118
119         creds_dict = {
120             'username': config['username'],
121             'password': config['password'],
122             'auth_url': config['os_auth_url'],
123             'project_name': config['project_name'],
124             'identity_api_version': config.get('identity_api_version'),
125             'image_api_version': config.get('image_api_version'),
126             'network_api_version': config.get('network_api_version'),
127             'compute_api_version': config.get('compute_api_version'),
128             'heat_api_version': config.get('heat_api_version'),
129             'user_domain_id': config.get('user_domain_id'),
130             'user_domain_name': config.get('user_domain_name'),
131             'project_domain_id': config.get('project_domain_id'),
132             'project_domain_name': config.get('project_domain_name'),
133             'volume_api_version': config.get('volume_api_version'),
134             'interface': config.get('interface'),
135             'proxy_settings': proxy_settings,
136             'cacert': config.get('cacert'),
137             'region_name': config.get('region_name')}
138
139     if overrides and isinstance(overrides, dict):
140         creds_dict.update(overrides)
141
142     for key, value in creds_dict.items():
143         if value is not None and isinstance(value, str):
144             creds_dict[key] = value.replace('"', '').replace('\'', '')
145
146     os_creds = OSCreds(**creds_dict)
147     logger.info('OS Credentials = %s', os_creds.__str__)
148     return os_creds
149
150
151 def create_image_settings(image_name, image_user, image_format, metadata,
152                           disk_url=None, default_url=None,
153                           kernel_settings=None, ramdisk_settings=None,
154                           public=False, nic_config_pb_loc=None):
155     """
156     Returns the image settings object
157     :param image_name: the name of the image
158     :param image_user: the image's sudo user
159     :param image_format: the image's format string
160     :param metadata: custom metadata for overriding default behavior for test
161                      image settings
162     :param disk_url: the disk image's URL
163     :param default_url: the default URL for the disk image
164     :param kernel_settings: override to the kernel settings from the
165                             image_metadata
166     :param ramdisk_settings: override to the ramdisk settings from the
167                              image_metadata
168     :param public: True denotes image can be used by other projects where False
169                    indicates the converse (default: False)
170     :param nic_config_pb_loc: The location of the playbook used for configuring
171                               multiple NICs
172     :return:
173     """
174
175     logger.debug('Image metadata - ' + str(metadata))
176
177     if metadata and 'config' in metadata:
178         return ImageConfig(**metadata['config'])
179
180     disk_file = None
181     if metadata and ('disk_url' in metadata or 'disk_file' in metadata):
182         disk_url = metadata.get('disk_url')
183         disk_file = metadata.get('disk_file')
184     elif not disk_url:
185         disk_url = default_url
186
187     if (metadata
188             and ('kernel_file' in metadata or 'kernel_url' in metadata)
189             and kernel_settings is None):
190         kernel_image_settings = ImageConfig(
191             name=image_name + '-kernel', image_user=image_user,
192             img_format=image_format, image_file=metadata.get('kernel_file'),
193             url=metadata.get('kernel_url'), public=public)
194     else:
195         kernel_image_settings = kernel_settings
196
197     if (metadata
198             and ('ramdisk_file' in metadata or 'ramdisk_url' in metadata)
199             and ramdisk_settings is None):
200         ramdisk_image_settings = ImageConfig(
201             name=image_name + '-ramdisk', image_user=image_user,
202             img_format=image_format,
203             image_file=metadata.get('ramdisk_file'),
204             url=metadata.get('ramdisk_url'), public=public)
205     else:
206         ramdisk_image_settings = ramdisk_settings
207
208     extra_properties = None
209     if metadata and 'extra_properties' in metadata:
210         extra_properties = metadata['extra_properties']
211
212     return ImageConfig(name=image_name, image_user=image_user,
213                        img_format=image_format, image_file=disk_file,
214                        url=disk_url, extra_properties=extra_properties,
215                        kernel_image_settings=kernel_image_settings,
216                        ramdisk_image_settings=ramdisk_image_settings,
217                        public=public,
218                        nic_config_pb_loc=nic_config_pb_loc)
219
220
221 def cirros_image_settings(name=None, url=None, image_metadata=None,
222                           kernel_settings=None, ramdisk_settings=None,
223                           public=False):
224     """
225     Returns the image settings for a Cirros QCOW2 image
226     :param name: the name of the image
227     :param url: the image's URL
228     :param image_metadata: dict() values to override URLs for disk, kernel, and
229                            ramdisk
230     :param kernel_settings: override to the kernel settings from the
231                             image_metadata
232     :param ramdisk_settings: override to the ramdisk settings from the
233                              image_metadata
234     :param public: True denotes image can be used by other projects where False
235                    indicates the converse
236     :return:
237     """
238     if image_metadata and 'cirros' in image_metadata:
239         metadata = image_metadata['cirros']
240     else:
241         metadata = image_metadata
242
243     return create_image_settings(
244         image_name=name, image_user=CIRROS_USER,
245         image_format=DEFAULT_IMAGE_FORMAT, metadata=metadata, disk_url=url,
246         default_url=CIRROS_DEFAULT_IMAGE_URL,
247         kernel_settings=kernel_settings, ramdisk_settings=ramdisk_settings,
248         public=public)
249
250
251 def file_image_test_settings(name, file_path, image_user=CIRROS_USER):
252     return ImageConfig(name=name, image_user=image_user,
253                        img_format=DEFAULT_IMAGE_FORMAT, image_file=file_path)
254
255
256 def centos_image_settings(name, url=None, image_metadata=None,
257                           kernel_settings=None, ramdisk_settings=None,
258                           public=False):
259     """
260     Returns the image settings for a Centos QCOW2 image
261     :param name: the name of the image
262     :param url: the image's URL
263     :param image_metadata: dict() values to override URLs for disk, kernel, and
264                            ramdisk
265     :param kernel_settings: override to the kernel settings from the
266                             image_metadata
267     :param ramdisk_settings: override to the ramdisk settings from the
268                              image_metadata
269     :param public: True denotes image can be used by other projects where False
270                    indicates the converse
271     :return:
272     """
273     if image_metadata and 'centos' in image_metadata:
274         metadata = image_metadata['centos']
275     else:
276         metadata = image_metadata
277
278     return create_image_settings(
279         image_name=name, image_user=CENTOS_USER,
280         image_format=DEFAULT_IMAGE_FORMAT, metadata=metadata, disk_url=url,
281         default_url=CENTOS_DEFAULT_IMAGE_URL,
282         kernel_settings=kernel_settings, ramdisk_settings=ramdisk_settings,
283         public=public)
284
285
286 def ubuntu_image_settings(name, url=None, image_metadata=None,
287                           kernel_settings=None, ramdisk_settings=None,
288                           public=False):
289     """
290     Returns the image settings for a Ubuntu QCOW2 image
291     :param name: the name of the image
292     :param url: the image's URL
293     :param image_metadata: dict() values to override URLs for disk, kernel, and
294                            ramdisk
295     :param kernel_settings: override to the kernel settings from the
296                             image_metadata
297     :param ramdisk_settings: override to the ramdisk settings from the
298                              image_metadata
299     :param public: True denotes image can be used by other projects where False
300                    indicates the converse
301     :return:
302     """
303     if image_metadata and 'ubuntu' in image_metadata:
304         metadata = image_metadata['ubuntu']
305     else:
306         metadata = image_metadata
307
308     return create_image_settings(
309         image_name=name, image_user=UBUNTU_USER,
310         image_format=DEFAULT_IMAGE_FORMAT, metadata=metadata, disk_url=url,
311         default_url=UBUNTU_DEFAULT_IMAGE_URL,
312         kernel_settings=kernel_settings, ramdisk_settings=ramdisk_settings,
313         public=public)
314
315
316 def get_priv_net_config(project_name, net_name, subnet_name, router_name=None,
317                         cidr='10.55.0.0/24', external_net=None,
318                         netconf_override=None):
319     return OSNetworkConfig(
320         project_name, net_name, subnet_name, cidr, router_name,
321         external_gateway=external_net, netconf_override=netconf_override)
322
323
324 def get_pub_net_config(
325         project_name, net_name, subnet_name=None, router_name=None,
326         cidr='10.55.1.0/24', external_net=None, netconf_override=None):
327     return OSNetworkConfig(project_name, net_name, subnet_name, cidr,
328                            router_name, external_gateway=external_net,
329                            netconf_override=netconf_override)
330
331
332 def get_flavor_config(name, ram, disk, vcpus, ephemeral=None, swap=None,
333                       rxtx_factor=None, is_public=None, metadata=None):
334     """This method replaces the hard coded basic element (e.g. ram, vcpu, disk
335      etc) with those are included in the new freeform dict() of metadata
336      parameter.
337
338     :param name: the flavor name (required)
339     :param ram: memory in MB to allocate to VM (required)
340     :param disk: disk storage in GB (required)
341     :param vcpus: the number of CPUs to allocate to VM (required)
342     :param ephemeral: the size of the ephemeral disk in GB (default=0)
343     :param swap: the size of the swap disk in GB (default=0)
344     :param rxtx_factor: the receive/transmit factor to be set on ports
345          if backend supports QoS extension (default=1.0)
346     :param is_public: flag that denotes whether or not other projects
347          can access image (default=True)
348     :param metadata: - freeform dict() for special metadata (optional)
349                      - freeform dict() for values of basic elements
350                      (e.g. ram, vcpu, disk, etc) could be added.
351                      As result the hard coded values of those elements will be
352                      overwritten by the new ones (optional)
353     :return: The FlavorConfig replacing the hard coded basic element values
354             (e.g. ram, vcpu, disk etc) with those are included in the metadata
355              dict [optional]. The metadata parameter in the FlavorConfig
356              consist of the metadata data only.
357     """
358
359     metadata_excl = metadata
360     if metadata:
361         if 'ram' in metadata:
362             ram = metadata['ram']
363             del metadata_excl['ram']
364         if 'disk' in metadata:
365             disk = metadata['disk']
366             del metadata_excl['disk']
367         if 'vcpus' in metadata:
368             vcpus = metadata['vcpus']
369             del metadata_excl['vcpus']
370         if 'ephemeral' in metadata:
371             ephemeral = metadata['ephemeral']
372             del metadata_excl['ephemeral']
373         if 'swap' in metadata:
374             swap = metadata['swap']
375             del metadata_excl['swap']
376         if 'rxtx_factor' in metadata:
377             rxtx_factor = metadata['rxtx_factor']
378             del metadata_excl['rxtx_factor']
379         if 'is_public' in metadata:
380             is_public = metadata['is_public']
381             del metadata_excl['is_public']
382         if 'metadata' in metadata:
383             metadata_excl = metadata['metadata']
384
385     return FlavorConfig(
386         name=name, ram=ram, disk=disk, vcpus=vcpus, ephemeral=ephemeral,
387         swap=swap, rxtx_factor=rxtx_factor, is_public=is_public,
388         metadata=metadata_excl)
389
390
391 class OSNetworkConfig:
392     """
393     Represents the settings required for the creation of a network in OpenStack
394     where netconf_override is used to reconfigure the network_type,
395     physical_network and segmentation_id
396     """
397
398     def __init__(self, project_name, net_name, subnet_name=None,
399                  subnet_cidr=None, router_name=None, external_gateway=None,
400                  netconf_override=None):
401         """
402         :param netconf_override: dict() containing the reconfigured
403                                  network_type, physical_network and
404                                  segmentation_id
405         """
406         if subnet_name and subnet_cidr:
407             network_conf = NetworkConfig(
408                 name=net_name, subnet_settings=[
409                     SubnetConfig(cidr=subnet_cidr, name=subnet_name)])
410         else:
411             network_conf = NetworkConfig(name=net_name)
412         if netconf_override:
413             network_conf.network_type = netconf_override.get('network_type')
414             network_conf.physical_network = netconf_override.get(
415                 'physical_network')
416             network_conf.segmentation_id = netconf_override.get(
417                 'segmentation_id')
418         self.network_settings = network_conf
419
420         if router_name:
421             if subnet_name:
422                 self.router_settings = RouterConfig(
423                     name=router_name, external_gateway=external_gateway,
424                     internal_subnets=[{'subnet': {
425                         'project_name': project_name,
426                         'network_name': net_name,
427                         'subnet_name': subnet_name}}])
428             else:
429                 self.router_settings = RouterConfig(
430                     name=router_name, external_gateway=external_gateway)