Fixed bug with regards to subnet lookups.
[snaps.git] / snaps / openstack / utils / tests / settings_utils_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 unittest
17
18 import os
19 import uuid
20
21 from snaps.config.network import SubnetConfig, NetworkConfig, PortConfig
22 from snaps.config.flavor import FlavorConfig
23 from snaps.config.keypair import KeypairConfig
24 from snaps.config.qos import Consumer
25 from snaps.config.security_group import (
26     SecurityGroupRuleConfig, Direction, Protocol, SecurityGroupConfig)
27 from snaps.config.vm_inst import VmInstanceConfig, FloatingIpConfig
28 from snaps.domain.flavor import Flavor
29 from snaps.domain.volume import (
30     Volume, VolumeType, VolumeTypeEncryption, QoSSpec)
31 from snaps.openstack import (
32     create_image, create_network, create_router, create_flavor,
33     create_keypairs, create_instance)
34 from snaps.openstack.create_qos import Consumer
35 from snaps.openstack.create_network import OpenStackNetwork
36 from snaps.openstack.create_security_group import OpenStackSecurityGroup
37 from snaps.openstack.tests import openstack_tests
38 from snaps.openstack.tests.os_source_file_test import OSComponentTestCase
39 from snaps.openstack.utils import (
40     neutron_utils, settings_utils, nova_utils, glance_utils, keystone_utils)
41
42 __author__ = 'spisarski'
43
44 logger = logging.getLogger('nova_utils_tests')
45
46
47 class SettingsUtilsNetworkingTests(OSComponentTestCase):
48     """
49     Tests the ability to reverse engineer NetworkConfig objects from existing
50     networks deployed to OpenStack
51     """
52
53     def setUp(self):
54         """
55         Instantiates OpenStack instances that cannot be spawned by Heat
56         """
57         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
58         self.network_name = guid + '-net'
59         self.subnet_name = guid + '-subnet'
60         self.net_creator = None
61         self.neutron = neutron_utils.neutron_client(
62             self.os_creds, self.os_session)
63
64     def tearDown(self):
65         """
66         Cleans the image and downloaded image file
67         """
68         if self.net_creator:
69             try:
70                 self.net_creator.clean()
71             except:
72                 pass
73
74         super(self.__class__, self).__clean__()
75
76     def test_derive_net_settings_no_subnet(self):
77         """
78         Validates the utility function settings_utils#create_network_config
79         returns an acceptable NetworkConfig object and ensures that the
80         new settings object will not cause the new OpenStackNetwork instance
81         to create another network
82         """
83         net_settings = NetworkConfig(name=self.network_name)
84         self.net_creator = OpenStackNetwork(self.os_creds, net_settings)
85         network = self.net_creator.create()
86
87         derived_settings = settings_utils.create_network_config(
88             self.neutron, network)
89
90         self.assertIsNotNone(derived_settings)
91         self.assertEqual(net_settings.name, derived_settings.name)
92         self.assertEqual(net_settings.admin_state_up,
93                          derived_settings.admin_state_up)
94         self.assertEqual(net_settings.external, derived_settings.external)
95         self.assertEqual(len(net_settings.subnet_settings),
96                          len(derived_settings.subnet_settings))
97
98         net_creator = OpenStackNetwork(self.os_creds, derived_settings)
99         derived_network = net_creator.create()
100
101         self.assertEqual(network, derived_network)
102
103     def test_derive_net_settings_two_subnets(self):
104         """
105         Validates the utility function settings_utils#create_network_config
106         returns an acceptable NetworkConfig object
107         """
108         subnet_settings = list()
109         subnet_settings.append(SubnetConfig(name='sub1', cidr='10.0.0.0/24'))
110         subnet_settings.append(SubnetConfig(name='sub2', cidr='10.0.1.0/24'))
111         net_settings = NetworkConfig(
112             name=self.network_name, subnet_settings=subnet_settings)
113         self.net_creator = OpenStackNetwork(self.os_creds, net_settings)
114         network = self.net_creator.create()
115
116         derived_settings = settings_utils.create_network_config(
117             self.neutron, network)
118
119         self.assertIsNotNone(derived_settings)
120         self.assertEqual(net_settings.name, derived_settings.name)
121         self.assertEqual(net_settings.admin_state_up,
122                          derived_settings.admin_state_up)
123         self.assertEqual(net_settings.external, derived_settings.external)
124         self.assertEqual(len(net_settings.subnet_settings),
125                          len(derived_settings.subnet_settings))
126
127         # Validate the first subnet
128         orig_sub1 = net_settings.subnet_settings[0]
129         found = False
130         for derived_sub in derived_settings.subnet_settings:
131             if orig_sub1.name == derived_sub.name:
132                 self.assertEqual(orig_sub1.cidr, derived_sub.cidr)
133                 found = True
134
135         self.assertTrue(found)
136
137         # Validate the second subnet
138         orig_sub2 = net_settings.subnet_settings[1]
139         found = False
140         for derived_sub in derived_settings.subnet_settings:
141             if orig_sub2.name == derived_sub.name:
142                 self.assertEqual(orig_sub2.cidr, derived_sub.cidr)
143                 self.assertEqual(orig_sub2.ip_version, derived_sub.ip_version)
144                 found = True
145
146         self.assertTrue(found)
147
148
149 class SettingsUtilsVmInstTests(OSComponentTestCase):
150     """
151     Tests the ability to reverse engineer VmInstanceConfig objects from
152     existing VMs/servers deployed to OpenStack
153     """
154
155     def setUp(self):
156         """
157         Instantiates the CreateImage object that is responsible for downloading
158         and creating an OS image file within OpenStack
159         """
160         self.nova = nova_utils.nova_client(
161             self.os_creds, self.os_session)
162         self.keystone = keystone_utils.keystone_client(
163             self.os_creds, self.os_session)
164         self.glance = glance_utils.glance_client(
165             self.os_creds, self.os_session)
166         self.neutron = neutron_utils.neutron_client(
167             self.os_creds, self.os_session)
168
169         guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
170         self.keypair_priv_filepath = 'tmp/' + guid
171         self.keypair_pub_filepath = self.keypair_priv_filepath + '.pub'
172         self.keypair_name = guid + '-kp'
173         self.vm_inst_name = guid + '-inst'
174         self.test_file_local_path = 'tmp/' + guid + '-hello.txt'
175         self.port_1_name = guid + '-port-1'
176         self.port_2_name = guid + '-port-2'
177         self.floating_ip_name = guid + 'fip1'
178
179         # Setup members to cleanup just in case they don't get created
180         self.inst_creator = None
181         self.keypair_creator = None
182         self.sec_grp_creator = None
183         self.flavor_creator = None
184         self.router_creator = None
185         self.network_creator = None
186         self.image_creator = None
187
188         try:
189             # Create Image
190             os_image_settings = openstack_tests.cirros_image_settings(
191                 name=guid + '-' + '-image',
192                 image_metadata=self.image_metadata)
193             self.image_creator = create_image.OpenStackImage(self.os_creds,
194                                                              os_image_settings)
195             self.image_creator.create()
196
197             # First network is public
198             self.pub_net_config = openstack_tests.get_pub_net_config(
199                 project_name=self.os_creds.project_name,
200                 net_name=guid + '-pub-net', subnet_name=guid + '-pub-subnet',
201                 router_name=guid + '-pub-router',
202                 external_net=self.ext_net_name)
203
204             self.network_creator = create_network.OpenStackNetwork(
205                 self.os_creds, self.pub_net_config.network_settings)
206             self.network_creator.create()
207
208             # Create routers
209             self.router_creator = create_router.OpenStackRouter(
210                 self.os_creds, self.pub_net_config.router_settings)
211             self.router_creator.create()
212
213             # Create Flavor
214             self.flavor_creator = create_flavor.OpenStackFlavor(
215                 self.os_creds,
216                 FlavorConfig(
217                     name=guid + '-flavor-name', ram=256, disk=1, vcpus=1))
218             self.flavor_creator.create()
219
220             # Create Key/Pair
221             self.keypair_creator = create_keypairs.OpenStackKeypair(
222                 self.os_creds, KeypairConfig(
223                     name=self.keypair_name,
224                     public_filepath=self.keypair_pub_filepath,
225                     private_filepath=self.keypair_priv_filepath))
226             self.keypair_creator.create()
227
228             # Create Security Group
229             sec_grp_name = guid + '-sec-grp'
230             rule1 = SecurityGroupRuleConfig(
231                 sec_grp_name=sec_grp_name, direction=Direction.ingress,
232                 protocol=Protocol.icmp)
233             rule2 = SecurityGroupRuleConfig(
234                 sec_grp_name=sec_grp_name, direction=Direction.ingress,
235                 protocol=Protocol.tcp, port_range_min=22, port_range_max=22)
236             self.sec_grp_creator = OpenStackSecurityGroup(
237                 self.os_creds,
238                 SecurityGroupConfig(
239                     name=sec_grp_name, rule_settings=[rule1, rule2]))
240             self.sec_grp_creator.create()
241
242             # Create instance
243             ports_settings = list()
244             ports_settings.append(
245                 PortConfig(
246                     name=self.port_1_name,
247                     network_name=self.pub_net_config.network_settings.name))
248
249             instance_settings = VmInstanceConfig(
250                 name=self.vm_inst_name,
251                 flavor=self.flavor_creator.flavor_settings.name,
252                 port_settings=ports_settings,
253                 floating_ip_settings=[FloatingIpConfig(
254                     name=self.floating_ip_name, port_name=self.port_1_name,
255                     router_name=self.pub_net_config.router_settings.name)])
256
257             self.inst_creator = create_instance.OpenStackVmInstance(
258                 self.os_creds, instance_settings,
259                 self.image_creator.image_settings,
260                 keypair_settings=self.keypair_creator.keypair_settings)
261         except:
262             self.tearDown()
263             raise
264
265     def tearDown(self):
266         """
267         Cleans the created objects
268         """
269         if self.inst_creator:
270             try:
271                 self.inst_creator.clean()
272             except:
273                 pass
274
275         if self.sec_grp_creator:
276             try:
277                 self.sec_grp_creator.clean()
278             except:
279                 pass
280
281         if self.keypair_creator:
282             try:
283                 self.keypair_creator.clean()
284             except:
285                 pass
286
287         if self.flavor_creator:
288             try:
289                 self.flavor_creator.clean()
290             except:
291                 pass
292
293         if os.path.isfile(self.keypair_pub_filepath):
294             try:
295                 os.remove(self.keypair_pub_filepath)
296             except:
297                 pass
298
299         if os.path.isfile(self.keypair_priv_filepath):
300             try:
301                 os.remove(self.keypair_priv_filepath)
302             except:
303                 pass
304
305         if self.router_creator:
306             try:
307                 self.router_creator.clean()
308             except:
309                 pass
310
311         if self.network_creator:
312             try:
313                 self.network_creator.clean()
314             except:
315                 pass
316
317         if self.image_creator and not self.image_creator.image_settings.exists:
318             try:
319                 self.image_creator.clean()
320             except:
321                 pass
322
323         if os.path.isfile(self.test_file_local_path):
324             os.remove(self.test_file_local_path)
325
326         super(self.__class__, self).__clean__()
327
328     def test_derive_vm_inst_config(self):
329         """
330         Validates the utility function settings_utils#create_vm_inst_config
331         returns an acceptable VmInstanceConfig object
332         """
333         self.inst_creator.create(block=True)
334
335         server = nova_utils.get_server(
336             self.nova, self.neutron, self.keystone,
337             vm_inst_settings=self.inst_creator.instance_settings)
338         derived_vm_settings = settings_utils.create_vm_inst_config(
339             self.nova, self.keystone, self.neutron, server,
340             self.os_creds.project_name)
341         self.assertIsNotNone(derived_vm_settings)
342         self.assertIsNotNone(derived_vm_settings.port_settings)
343         self.assertIsNotNone(derived_vm_settings.floating_ip_settings)
344
345     def test_derive_image_settings(self):
346         """
347         Validates the utility function settings_utils#create_image_settings
348         returns an acceptable ImageConfig object
349         """
350         self.inst_creator.create(block=True)
351
352         server = nova_utils.get_server(
353             self.nova, self.neutron, self.keystone,
354             vm_inst_settings=self.inst_creator.instance_settings)
355         derived_image_settings = settings_utils.determine_image_config(
356             self.glance, server, [self.image_creator.image_settings])
357         self.assertIsNotNone(derived_image_settings)
358         self.assertEqual(self.image_creator.image_settings.name,
359                          derived_image_settings.name)
360
361
362 class SettingsUtilsUnitTests(unittest.TestCase):
363     """
364     Exercises the settings_utils.py functions around volumes
365     """
366
367     def test_vol_settings_from_vol(self):
368         volume = Volume(
369             name='vol-name', volume_id='vol-id', project_id='proj-id',
370             description='desc', size=99, vol_type='vol-type',
371             availability_zone='zone1', multi_attach=True)
372         settings = settings_utils.create_volume_config(volume)
373         self.assertEqual(volume.name, settings.name)
374         self.assertEqual(volume.description, settings.description)
375         self.assertEqual(volume.size, settings.size)
376         self.assertEqual(volume.type, settings.type_name)
377         self.assertEqual(volume.availability_zone, settings.availability_zone)
378         self.assertEqual(volume.multi_attach, settings.multi_attach)
379
380     def test_vol_type_settings_from_vol(self):
381         encryption = VolumeTypeEncryption(
382             volume_encryption_id='vol-encrypt-id', volume_type_id='vol-typ-id',
383             control_location='front-end', provider='FooClass', cipher='1',
384             key_size=1)
385         qos_spec = QoSSpec(name='qos-spec-name', spec_id='qos-spec-id',
386                            consumer=Consumer.back_end)
387         volume_type = VolumeType(
388             name='vol-type-name', volume_type_id='vol-type-id', public=True,
389             encryption=encryption, qos_spec=qos_spec)
390
391         settings = settings_utils.create_volume_type_config(volume_type)
392         self.assertEqual(volume_type.name, settings.name)
393         self.assertEqual(volume_type.public, settings.public)
394
395         encrypt_settings = settings.encryption
396         self.assertIsNotNone(encrypt_settings)
397         self.assertEqual(encryption.control_location,
398                          encrypt_settings.control_location.value)
399         self.assertEqual(encryption.cipher, encrypt_settings.cipher)
400         self.assertEqual(encryption.key_size, encrypt_settings.key_size)
401
402         self.assertEqual(qos_spec.name, settings.qos_spec_name)
403
404     def test_flavor_settings_from_flavor(self):
405         flavor = Flavor(
406             name='flavor-name', flavor_id='flavor-id', ram=99, disk=101,
407             vcpus=9, ephemeral=3, swap=5, rxtx_factor=7, is_public=False)
408         settings = settings_utils.create_flavor_config(flavor)
409         self.assertEqual(flavor.name, settings.name)
410         self.assertEqual(flavor.id, settings.flavor_id)
411         self.assertEqual(flavor.ram, settings.ram)
412         self.assertEqual(flavor.disk, settings.disk)
413         self.assertEqual(flavor.vcpus, settings.vcpus)
414         self.assertEqual(flavor.ephemeral, settings.ephemeral)
415         self.assertEqual(flavor.swap, settings.swap)
416         self.assertEqual(flavor.rxtx_factor, settings.rxtx_factor)
417         self.assertEqual(flavor.is_public, settings.is_public)