1 # Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs")
2 # and others. All rights reserved.
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:
8 # http://www.apache.org/licenses/LICENSE-2.0
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.
19 from heatclient.exc import HTTPBadRequest
22 from snaps import file_utils
23 from snaps.config.flavor import FlavorConfig
24 from snaps.config.image import ImageConfig
25 from snaps.config.stack import (StackConfigError, StackConfig,
26 STATUS_UPDATE_COMPLETE)
27 from snaps.openstack.create_flavor import OpenStackFlavor
28 from snaps.openstack.create_image import OpenStackImage
31 from urllib.request import URLError
33 from urllib2 import URLError
39 from snaps.openstack import create_stack
40 from snaps.openstack.create_stack import (
41 StackSettings, StackCreationError, StackError, OpenStackHeatStack)
42 from snaps.openstack.tests import openstack_tests, create_instance_tests
43 from snaps.openstack.tests.os_source_file_test import OSIntegrationTestCase
44 from snaps.openstack.utils import (
45 heat_utils, neutron_utils, nova_utils, keystone_utils)
47 __author__ = 'spisarski'
49 logger = logging.getLogger('create_stack_tests')
52 class StackSettingsUnitTests(unittest.TestCase):
54 Tests the construction of the StackSettings class
57 def test_no_params(self):
58 with self.assertRaises(StackConfigError):
61 def test_empty_config(self):
62 with self.assertRaises(StackConfigError):
63 StackSettings(**dict())
65 def test_name_only(self):
66 with self.assertRaises(StackConfigError):
67 StackSettings(name='foo')
69 def test_config_with_name_only(self):
70 with self.assertRaises(StackConfigError):
71 StackSettings(**{'name': 'foo'})
73 def test_config_minimum_template(self):
74 settings = StackSettings(**{'name': 'stack', 'template': 'foo'})
75 self.assertEqual('stack', settings.name)
76 self.assertEqual('foo', settings.template)
77 self.assertIsNone(settings.template_path)
78 self.assertIsNone(settings.env_values)
79 self.assertEqual(snaps.config.stack.STACK_COMPLETE_TIMEOUT,
80 settings.stack_create_timeout)
82 def test_config_minimum_template_path(self):
83 settings = StackSettings(**{'name': 'stack', 'template_path': 'foo'})
84 self.assertEqual('stack', settings.name)
85 self.assertIsNone(settings.template)
86 self.assertEqual('foo', settings.template_path)
87 self.assertIsNone(settings.env_values)
88 self.assertEqual(snaps.config.stack.STACK_COMPLETE_TIMEOUT,
89 settings.stack_create_timeout)
91 def test_minimum_template(self):
92 settings = StackSettings(name='stack', template='foo')
93 self.assertEqual('stack', settings.name)
94 self.assertEqual('foo', settings.template)
95 self.assertIsNone(settings.template_path)
96 self.assertIsNone(settings.env_values)
97 self.assertEqual(snaps.config.stack.STACK_COMPLETE_TIMEOUT,
98 settings.stack_create_timeout)
100 def test_minimum_template_path(self):
101 settings = StackSettings(name='stack', template_path='foo')
102 self.assertEqual('stack', settings.name)
103 self.assertEqual('foo', settings.template_path)
104 self.assertIsNone(settings.template)
105 self.assertIsNone(settings.env_values)
106 self.assertEqual(snaps.config.stack.STACK_COMPLETE_TIMEOUT,
107 settings.stack_create_timeout)
110 env_values = {'foo': 'bar'}
111 settings = StackSettings(name='stack', template='bar',
112 template_path='foo', env_values=env_values,
113 stack_create_timeout=999)
114 self.assertEqual('stack', settings.name)
115 self.assertEqual('bar', settings.template)
116 self.assertEqual('foo', settings.template_path)
117 self.assertEqual(env_values, settings.env_values)
118 self.assertEqual(999, settings.stack_create_timeout)
120 def test_config_all(self):
121 env_values = {'foo': 'bar'}
122 settings = StackSettings(
123 **{'name': 'stack', 'template': 'bar', 'template_path': 'foo',
124 'env_values': env_values, 'stack_create_timeout': 999})
125 self.assertEqual('stack', settings.name)
126 self.assertEqual('bar', settings.template)
127 self.assertEqual('foo', settings.template_path)
128 self.assertEqual(env_values, settings.env_values)
129 self.assertEqual(999, settings.stack_create_timeout)
132 class CreateStackSuccessTests(OSIntegrationTestCase):
134 Tests for the OpenStackHeatStack class defined in create_stack.py
138 self.user_roles = ['heat_stack_owner']
140 super(self.__class__, self).__start__()
142 self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
144 self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
145 self.stack_creator = None
147 self.image_creator = OpenStackImage(
148 self.os_creds, openstack_tests.cirros_image_settings(
149 name=self.guid + '-image',
150 image_metadata=self.image_metadata))
151 self.image_creator.create()
154 flavor_config = openstack_tests.get_flavor_config(
155 name=self.guid + '-flavor-name', ram=256, disk=10,
156 vcpus=1, metadata=self.flavor_metadata)
157 self.flavor_creator = OpenStackFlavor(
158 self.admin_os_creds, flavor_config)
159 self.flavor_creator.create()
161 self.network_name = self.guid + '-net'
162 self.subnet_name = self.guid + '-subnet'
163 self.vm_inst_name = self.guid + '-inst'
166 'image_name': self.image_creator.image_settings.name,
167 'flavor_name': self.flavor_creator.flavor_settings.name,
168 'net_name': self.network_name,
169 'subnet_name': self.subnet_name,
170 'inst_name': self.vm_inst_name}
172 self.heat_tmplt_path = pkg_resources.resource_filename(
173 'snaps.openstack.tests.heat', 'test_heat_template.yaml')
177 Cleans the stack and downloaded stack file
179 if self.stack_creator:
181 self.stack_creator.clean()
185 if self.image_creator:
187 self.image_creator.clean()
191 if self.flavor_creator:
193 self.flavor_creator.clean()
197 super(self.__class__, self).__clean__()
199 def test_create_stack_template_file(self):
201 Tests the creation of an OpenStack stack from Heat template file.
204 # Set the default stack settings, then set any custom parameters sent
206 stack_settings = StackConfig(
207 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
208 template_path=self.heat_tmplt_path,
209 env_values=self.env_values)
210 self.stack_creator = OpenStackHeatStack(
211 self.os_creds, stack_settings)
212 created_stack = self.stack_creator.create(block=True)
213 self.assertIsNotNone(created_stack)
215 retrieved_stack = heat_utils.get_stack_by_id(self.heat_cli,
217 self.assertIsNotNone(retrieved_stack)
218 self.assertEqual(created_stack.name, retrieved_stack.name)
219 self.assertEqual(created_stack.id, retrieved_stack.id)
220 self.assertEqual(0, len(self.stack_creator.get_outputs()))
222 derived_creator = create_stack.generate_creator(
223 self.os_creds, retrieved_stack,
224 [self.image_creator.image_settings])
225 derived_stack = derived_creator.get_stack()
226 self.assertEqual(retrieved_stack, derived_stack)
228 def test_create_stack_short_timeout(self):
230 Tests the creation of an OpenStack stack from Heat template file.
233 # Set the default stack settings, then set any custom parameters sent
235 stack_settings = StackConfig(
236 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
237 template_path=self.heat_tmplt_path,
238 env_values=self.env_values, stack_create_timeout=0)
240 self.stack_creator = OpenStackHeatStack(
241 self.os_creds, stack_settings)
242 with self.assertRaises(StackCreationError):
243 self.stack_creator.create(block=True)
245 def test_create_stack_template_dict(self):
247 Tests the creation of an OpenStack stack from a heat dict() object.
250 # Set the default stack settings, then set any custom parameters sent
252 template_dict = heat_utils.parse_heat_template_str(
253 file_utils.read_file(self.heat_tmplt_path))
254 stack_settings = StackConfig(
255 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
256 template=template_dict,
257 env_values=self.env_values)
258 self.stack_creator = OpenStackHeatStack(
259 self.os_creds, stack_settings)
260 created_stack = self.stack_creator.create(block=True)
261 self.assertIsNotNone(created_stack)
263 retrieved_stack = heat_utils.get_stack_by_id(self.heat_cli,
265 self.assertIsNotNone(retrieved_stack)
266 self.assertEqual(created_stack.name, retrieved_stack.name)
267 self.assertEqual(created_stack.id, retrieved_stack.id)
268 self.assertEqual(0, len(self.stack_creator.get_outputs()))
270 def test_create_delete_stack(self):
272 Tests the creation then deletion of an OpenStack stack to ensure
273 clean() does not raise an Exception.
276 template_dict = heat_utils.parse_heat_template_str(
277 file_utils.read_file(self.heat_tmplt_path))
278 stack_settings = StackConfig(
279 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
280 template=template_dict,
281 env_values=self.env_values)
282 self.stack_creator = OpenStackHeatStack(
283 self.os_creds, stack_settings)
284 created_stack = self.stack_creator.create(block=True)
285 self.assertIsNotNone(created_stack)
287 retrieved_stack = heat_utils.get_stack_by_id(self.heat_cli,
289 self.assertIsNotNone(retrieved_stack)
290 self.assertEqual(created_stack.name, retrieved_stack.name)
291 self.assertEqual(created_stack.id, retrieved_stack.id)
292 self.assertEqual(0, len(self.stack_creator.get_outputs()))
293 self.assertEqual(snaps.config.stack.STATUS_CREATE_COMPLETE,
294 self.stack_creator.get_status())
296 # Delete Stack manually
297 heat_utils.delete_stack(self.heat_cli, created_stack)
299 end_time = time.time() + 90
301 while time.time() < end_time:
302 status = heat_utils.get_stack_status(self.heat_cli,
304 if status == snaps.config.stack.STATUS_DELETE_COMPLETE:
308 self.assertTrue(deleted)
310 # Must not throw an exception when attempting to cleanup non-existent
312 self.stack_creator.clean()
313 self.assertIsNone(self.stack_creator.get_stack())
315 def test_create_same_stack(self):
317 Tests the creation of an OpenStack stack when the stack already exists.
320 template_dict = heat_utils.parse_heat_template_str(
321 file_utils.read_file(self.heat_tmplt_path))
322 stack_settings = StackConfig(
323 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
324 template=template_dict,
325 env_values=self.env_values)
326 self.stack_creator = OpenStackHeatStack(
327 self.os_creds, stack_settings)
328 created_stack1 = self.stack_creator.create(block=True)
330 retrieved_stack = heat_utils.get_stack_by_id(self.heat_cli,
332 self.assertIsNotNone(retrieved_stack)
333 self.assertEqual(created_stack1.name, retrieved_stack.name)
334 self.assertEqual(created_stack1.id, retrieved_stack.id)
335 self.assertEqual(0, len(self.stack_creator.get_outputs()))
337 # Should be retrieving the instance data
338 stack_creator2 = OpenStackHeatStack(self.os_creds, stack_settings)
339 stack2 = stack_creator2.create(block=True)
340 self.assertEqual(created_stack1.id, stack2.id)
342 def test_retrieve_network_creators(self):
344 Tests the creation of an OpenStack stack from Heat template file and
345 the retrieval of the network creator.
347 stack_settings = StackConfig(
348 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
349 template_path=self.heat_tmplt_path,
350 env_values=self.env_values)
351 self.stack_creator = OpenStackHeatStack(
352 self.os_creds, stack_settings)
353 created_stack = self.stack_creator.create(block=True)
354 self.assertIsNotNone(created_stack)
356 net_creators = self.stack_creator.get_network_creators()
357 self.assertIsNotNone(net_creators)
358 self.assertEqual(1, len(net_creators))
359 self.assertEqual(self.network_name, net_creators[0].get_network().name)
361 # Need to use 'admin' creds as heat creates objects under it's own
363 neutron = neutron_utils.neutron_client(
364 self.os_creds, self.os_session)
365 keystone = keystone_utils.keystone_client(
366 self.os_creds, self.os_session)
367 net_by_name = neutron_utils.get_network(
368 neutron, keystone, network_name=net_creators[0].get_network().name)
369 self.assertEqual(net_creators[0].get_network(), net_by_name)
370 self.assertIsNotNone(neutron_utils.get_network_by_id(
371 neutron, net_creators[0].get_network().id))
373 self.assertEqual(1, len(net_creators[0].get_network().subnets))
374 subnet = net_creators[0].get_network().subnets[0]
375 subnet_by_name = neutron_utils.get_subnet(
376 neutron, net_creators[0].get_network(), subnet_name=subnet.name)
377 self.assertEqual(subnet, subnet_by_name)
379 subnet_by_id = neutron_utils.get_subnet_by_id(neutron, subnet.id)
380 self.assertIsNotNone(subnet_by_id)
381 self.assertEqual(subnet_by_name, subnet_by_id)
383 def test_retrieve_vm_inst_creators(self):
385 Tests the creation of an OpenStack stack from Heat template file and
386 the retrieval of the network creator.
388 stack_settings = StackConfig(
389 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
390 template_path=self.heat_tmplt_path,
391 env_values=self.env_values)
392 self.stack_creator = OpenStackHeatStack(
393 self.os_creds, stack_settings)
394 created_stack = self.stack_creator.create(block=True)
395 self.assertIsNotNone(created_stack)
397 vm_inst_creators = self.stack_creator.get_vm_inst_creators()
398 self.assertIsNotNone(vm_inst_creators)
399 self.assertEqual(1, len(vm_inst_creators))
400 self.assertEqual(self.vm_inst_name,
401 vm_inst_creators[0].get_vm_inst().name)
403 nova = nova_utils.nova_client(self.os_creds, self.os_session)
404 neutron = neutron_utils.neutron_client(self.os_creds, self.os_session)
405 keystone = keystone_utils.keystone_client(self.os_creds, self.os_session)
406 vm_inst_by_name = nova_utils.get_server(
407 nova, neutron, keystone,
408 server_name=vm_inst_creators[0].get_vm_inst().name)
410 self.assertEqual(vm_inst_creators[0].get_vm_inst(), vm_inst_by_name)
411 self.assertIsNotNone(nova_utils.get_server_object_by_id(
412 nova, neutron, keystone, vm_inst_creators[0].get_vm_inst().id))
415 class CreateStackFloatingIpTests(OSIntegrationTestCase):
417 Tests to ensure that floating IPs can be accessed via an
418 OpenStackVmInstance object obtained from the OpenStackHeatStack instance
422 self.user_roles = ['heat_stack_owner', 'admin']
424 super(self.__class__, self).__start__()
426 self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
428 self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
429 self.stack_creator = None
431 self.image_creator = OpenStackImage(
432 self.os_creds, openstack_tests.cirros_image_settings(
433 name=self.guid + '-image',
434 image_metadata=self.image_metadata))
435 self.image_creator.create()
437 self.network_name = self.guid + '-net'
438 self.subnet_name = self.guid + '-subnet'
439 self.flavor1_name = self.guid + '-flavor1'
440 self.flavor2_name = self.guid + '-flavor2'
441 self.sec_grp_name = self.guid + '-sec_grp'
442 self.vm_inst1_name = self.guid + '-inst1'
443 self.vm_inst2_name = self.guid + '-inst2'
444 self.keypair_name = self.guid + '-kp'
447 'image1_name': self.image_creator.image_settings.name,
448 'image2_name': self.image_creator.image_settings.name,
449 'flavor1_name': self.flavor1_name,
450 'flavor2_name': self.flavor2_name,
451 'flavor_extra_specs': self.flavor_metadata,
452 'net_name': self.network_name,
453 'subnet_name': self.subnet_name,
454 'inst1_name': self.vm_inst1_name,
455 'inst2_name': self.vm_inst2_name,
456 'keypair_name': self.keypair_name,
457 'external_net_name': self.ext_net_name,
458 'security_group_name': self.sec_grp_name}
460 self.heat_tmplt_path = pkg_resources.resource_filename(
461 'snaps.openstack.tests.heat', 'floating_ip_heat_template.yaml')
463 self.vm_inst_creators = list()
467 Cleans the stack and downloaded stack file
469 if self.stack_creator:
471 self.stack_creator.clean()
475 if self.image_creator:
477 self.image_creator.clean()
481 for vm_inst_creator in self.vm_inst_creators:
483 keypair_settings = vm_inst_creator.keypair_settings
484 if keypair_settings and keypair_settings.private_filepath:
485 expanded_path = os.path.expanduser(
486 keypair_settings.private_filepath)
487 os.chmod(expanded_path, 0o755)
488 os.remove(expanded_path)
492 super(self.__class__, self).__clean__()
494 def test_connect_via_ssh_heat_vm(self):
496 Tests the creation of an OpenStack stack from Heat template file and
497 the retrieval of two VM instance creators and attempt to connect via
498 SSH to the first one with a floating IP.
500 stack_settings = StackConfig(
501 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
502 template_path=self.heat_tmplt_path,
503 env_values=self.env_values)
504 self.stack_creator = OpenStackHeatStack(
505 self.os_creds, stack_settings,
506 [self.image_creator.image_settings])
507 created_stack = self.stack_creator.create(block=True)
508 self.assertIsNotNone(created_stack)
510 self.vm_inst_creators = self.stack_creator.get_vm_inst_creators(
511 heat_keypair_option='private_key')
512 self.assertIsNotNone(self.vm_inst_creators)
513 self.assertEqual(2, len(self.vm_inst_creators))
515 for vm_inst_creator in self.vm_inst_creators:
516 if vm_inst_creator.get_vm_inst().name == self.vm_inst1_name:
518 create_instance_tests.validate_ssh_client(vm_inst_creator))
520 vm_settings = vm_inst_creator.instance_settings
521 self.assertEqual(0, len(vm_settings.floating_ip_settings))
523 def test_connect_via_ssh_heat_vm_derived(self):
525 Tests the the retrieval of two VM instance creators from a derived
526 OpenStackHeatStack object and attempt to connect via
527 SSH to the first one with a floating IP.
529 stack_settings = StackConfig(
530 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
531 template_path=self.heat_tmplt_path,
532 env_values=self.env_values)
533 self.stack_creator = OpenStackHeatStack(
534 self.os_creds, stack_settings,
535 [self.image_creator.image_settings])
536 created_stack = self.stack_creator.create(block=True)
537 self.assertIsNotNone(created_stack)
539 derived_stack = create_stack.generate_creator(
540 self.os_creds, created_stack,
541 [self.image_creator.image_settings])
543 self.vm_inst_creators = derived_stack.get_vm_inst_creators(
544 heat_keypair_option='private_key')
545 self.assertIsNotNone(self.vm_inst_creators)
546 self.assertEqual(2, len(self.vm_inst_creators))
548 for vm_inst_creator in self.vm_inst_creators:
549 if vm_inst_creator.get_vm_inst().name == self.vm_inst1_name:
551 create_instance_tests.validate_ssh_client(vm_inst_creator))
553 vm_settings = vm_inst_creator.instance_settings
554 self.assertEqual(0, len(vm_settings.floating_ip_settings))
557 class CreateStackNestedResourceTests(OSIntegrationTestCase):
559 Tests to ensure that nested heat templates work
563 self.user_roles = ['heat_stack_owner']
565 super(self.__class__, self).__start__()
567 self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
569 self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
570 self.stack_creator = None
572 self.image_creator = OpenStackImage(
573 self.os_creds, openstack_tests.cirros_image_settings(
574 name="{}-{}".format(self.guid, 'image'),
575 image_metadata=self.image_metadata))
576 self.image_creator.create()
578 flavor_config = openstack_tests.get_flavor_config(
579 name="{}-{}".format(self.guid, 'flavor-name'), ram=256, disk=10,
580 vcpus=1, metadata=self.flavor_metadata)
581 self.flavor_creator = OpenStackFlavor(
582 self.admin_os_creds, flavor_config)
583 self.flavor_creator.create()
586 'network_name': self.guid + '-network',
587 'public_network': self.ext_net_name,
588 'agent_image': self.image_creator.image_settings.name,
589 'agent_flavor': self.flavor_creator.flavor_settings.name,
590 'key_name': self.guid + '-key',
593 heat_tmplt_path = pkg_resources.resource_filename(
594 'snaps.openstack.tests.heat', 'agent-group.yaml')
595 heat_resource_path = pkg_resources.resource_filename(
596 'snaps.openstack.tests.heat', 'agent.yaml')
598 stack_settings = StackConfig(
600 self.__class__.__name__, str(self.guid) + '-stack'),
601 template_path=heat_tmplt_path,
602 resource_files=[heat_resource_path],
603 env_values=env_values)
605 self.stack_creator = OpenStackHeatStack(
606 self.os_creds, stack_settings,
607 [self.image_creator.image_settings])
609 self.vm_inst_creators = list()
613 Cleans the stack and downloaded stack file
615 if self.stack_creator:
617 self.stack_creator.clean()
621 if self.image_creator:
623 self.image_creator.clean()
627 if self.flavor_creator:
629 self.flavor_creator.clean()
633 for vm_inst_creator in self.vm_inst_creators:
635 keypair_settings = vm_inst_creator.keypair_settings
636 if keypair_settings and keypair_settings.private_filepath:
637 expanded_path = os.path.expanduser(
638 keypair_settings.private_filepath)
639 os.chmod(expanded_path, 0o755)
640 os.remove(expanded_path)
644 super(self.__class__, self).__clean__()
646 def test_nested(self):
648 Tests the creation of an OpenStack stack from Heat template file and
649 the retrieval of two VM instance creators and attempt to connect via
650 SSH to the first one with a floating IP.
652 created_stack = self.stack_creator.create(block=True)
653 self.assertIsNotNone(created_stack)
655 self.vm_inst_creators = self.stack_creator.get_vm_inst_creators(
656 heat_keypair_option='private_key')
657 self.assertIsNotNone(self.vm_inst_creators)
658 self.assertEqual(1, len(self.vm_inst_creators))
660 for vm_inst_creator in self.vm_inst_creators:
662 create_instance_tests.validate_ssh_client(vm_inst_creator))
665 class CreateStackUpdateTests(OSIntegrationTestCase):
667 Tests to ensure that stack update commands work
671 self.user_roles = ['heat_stack_owner']
673 super(self.__class__, self).__start__()
675 self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
677 self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
678 self.stack_creator = None
680 self.image_creator = OpenStackImage(
681 self.os_creds, openstack_tests.cirros_image_settings(
682 name=self.guid + '-image',
683 image_metadata=self.image_metadata))
684 self.image_creator.create()
686 self.flavor_creator = OpenStackFlavor(
689 name=self.guid + '-flavor-name', ram=256, disk=10, vcpus=1))
690 self.flavor_creator.create()
693 'network_name': self.guid + '-network',
694 'public_network': self.ext_net_name,
695 'agent_image': self.image_creator.image_settings.name,
696 'agent_flavor': self.flavor_creator.flavor_settings.name,
697 'key_name': self.guid + '-key',
700 heat_tmplt_path = pkg_resources.resource_filename(
701 'snaps.openstack.tests.heat', 'agent-group.yaml')
702 heat_resource_path = pkg_resources.resource_filename(
703 'snaps.openstack.tests.heat', 'agent.yaml')
705 stack_settings = StackConfig(
706 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
707 template_path=heat_tmplt_path,
708 resource_files=[heat_resource_path],
709 env_values=env_values)
711 self.stack_creator = OpenStackHeatStack(
712 self.os_creds, stack_settings,
713 [self.image_creator.image_settings])
715 self.vm_inst_creators = list()
719 Cleans the stack and downloaded stack file
721 if self.stack_creator:
723 self.stack_creator.clean()
727 if self.image_creator:
729 self.image_creator.clean()
733 if self.flavor_creator:
735 self.flavor_creator.clean()
739 for vm_inst_creator in self.vm_inst_creators:
741 keypair_settings = vm_inst_creator.keypair_settings
742 if keypair_settings and keypair_settings.private_filepath:
743 expanded_path = os.path.expanduser(
744 keypair_settings.private_filepath)
745 os.chmod(expanded_path, 0o755)
746 os.remove(expanded_path)
750 super(self.__class__, self).__clean__()
752 def test_update(self):
754 Tests the update of an OpenStack stack from Heat template file
755 by changing the number of VM instances from 1 to 2, and
756 the retrieval of two VM instance creators and attempt to connect via
757 SSH to the first one with a floating IP.
759 created_stack = self.stack_creator.create(block=True)
760 self.assertIsNotNone(created_stack)
762 self.vm_inst_creators = self.stack_creator.get_vm_inst_creators(
763 heat_keypair_option='private_key')
764 self.assertIsNotNone(self.vm_inst_creators)
765 self.assertEqual(1, len(self.vm_inst_creators))
767 for vm_inst_creator in self.vm_inst_creators:
769 create_instance_tests.validate_ssh_client(vm_inst_creator))
772 'network_name': self.guid + '-network',
773 'public_network': self.ext_net_name,
775 'agent_image': self.image_creator.image_settings.name,
776 'agent_flavor': self.flavor_creator.flavor_settings.name,
777 'key_name': self.guid + '-key',
780 updated_stack = self.stack_creator.update(env_values, block=True)
781 self.assertIsNotNone(updated_stack)
782 self.assertEqual(STATUS_UPDATE_COMPLETE, updated_stack.status)
784 self.vm_inst_creators = self.stack_creator.get_vm_inst_creators(
785 heat_keypair_option='private_key')
786 self.assertIsNotNone(self.vm_inst_creators)
787 self.assertEqual(2, len(self.vm_inst_creators))
789 for vm_inst_creator in self.vm_inst_creators:
791 create_instance_tests.validate_ssh_client(vm_inst_creator))
794 class CreateStackRouterTests(OSIntegrationTestCase):
796 Tests for the CreateStack class defined in create_stack.py where the
797 target is a Network, Subnet, and Router
802 Instantiates the CreateStack object that is responsible for downloading
803 and creating an OS stack file within OpenStack
805 self.user_roles = ['heat_stack_owner']
807 super(self.__class__, self).__start__()
809 self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
811 self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
812 self.neutron = neutron_utils.neutron_client(
813 self.os_creds, self.os_session)
814 self.stack_creator = None
816 self.net_name = self.guid + '-net'
817 self.subnet_name = self.guid + '-subnet'
818 self.router_name = self.guid + '-router'
821 'net_name': self.net_name,
822 'subnet_name': self.subnet_name,
823 'router_name': self.router_name,
824 'external_net_name': self.ext_net_name}
826 self.heat_tmplt_path = pkg_resources.resource_filename(
827 'snaps.openstack.tests.heat', 'router_heat_template.yaml')
829 stack_settings = StackConfig(
830 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
831 template_path=self.heat_tmplt_path,
832 env_values=self.env_values)
833 self.stack_creator = OpenStackHeatStack(
834 self.os_creds, stack_settings)
835 self.created_stack = self.stack_creator.create(block=True)
836 self.assertIsNotNone(self.created_stack)
840 Cleans the stack and downloaded stack file
842 if self.stack_creator:
844 self.stack_creator.clean()
848 super(self.__class__, self).__clean__()
850 def test_retrieve_router_creator(self):
852 Tests the creation of an OpenStack stack from Heat template file and
853 the retrieval of an OpenStackRouter creator/state machine instance
855 router_creators = self.stack_creator.get_router_creators()
856 self.assertEqual(1, len(router_creators))
858 creator = router_creators[0]
859 self.assertEqual(self.router_name, creator.router_settings.name)
861 router = creator.get_router()
863 ext_net = neutron_utils.get_network(
864 self.neutron, self.keystone, network_name=self.ext_net_name)
865 self.assertEqual(ext_net.id, router.external_network_id)
868 class CreateStackVolumeTests(OSIntegrationTestCase):
870 Tests to ensure that floating IPs can be accessed via an
871 OpenStackVolume object obtained from the OpenStackHeatStack instance
876 self.user_roles = ['heat_stack_owner', 'admin']
878 super(self.__class__, self).__start__()
880 self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
882 self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
883 self.stack_creator = None
885 self.volume_name = self.guid + '-volume'
886 self.volume_type_name = self.guid + '-volume-type'
889 'volume_name': self.volume_name,
890 'volume_type_name': self.volume_type_name}
892 self.heat_tmplt_path = pkg_resources.resource_filename(
893 'snaps.openstack.tests.heat', 'volume_heat_template.yaml')
895 stack_settings = StackConfig(
896 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
897 template_path=self.heat_tmplt_path,
898 env_values=self.env_values)
899 self.stack_creator = OpenStackHeatStack(
900 self.os_creds, stack_settings)
901 self.created_stack = self.stack_creator.create(block=True)
902 self.assertIsNotNone(self.created_stack)
906 Cleans the stack and downloaded stack file
908 if self.stack_creator:
910 self.stack_creator.clean()
914 super(self.__class__, self).__clean__()
916 def test_retrieve_volume_creator(self):
918 Tests the creation of an OpenStack stack from Heat template file and
919 the retrieval of an OpenStackVolume creator/state machine instance
921 volume_creators = self.stack_creator.get_volume_creators()
922 self.assertEqual(1, len(volume_creators))
924 creator = volume_creators[0]
925 self.assertEqual(self.volume_name, creator.volume_settings.name)
926 self.assertEqual(self.volume_name, creator.get_volume().name)
927 self.assertEqual(self.volume_type_name,
928 creator.volume_settings.type_name)
929 self.assertEqual(self.volume_type_name, creator.get_volume().type)
930 self.assertEqual(1, creator.volume_settings.size)
931 self.assertEqual(1, creator.get_volume().size)
933 def test_retrieve_volume_type_creator(self):
935 Tests the creation of an OpenStack stack from Heat template file and
936 the retrieval of an OpenStackVolume creator/state machine instance
938 volume_type_creators = self.stack_creator.get_volume_type_creators()
939 self.assertEqual(1, len(volume_type_creators))
941 creator = volume_type_creators[0]
942 self.assertIsNotNone(creator)
944 volume_type = creator.get_volume_type()
945 self.assertIsNotNone(volume_type)
947 self.assertEqual(self.volume_type_name, volume_type.name)
948 self.assertTrue(volume_type.public)
949 self.assertIsNone(volume_type.qos_spec)
951 # TODO - Add encryption back and find out why it broke in Pike
952 # encryption = volume_type.encryption
953 # self.assertIsNotNone(encryption)
954 # self.assertIsNone(encryption.cipher)
955 # self.assertEqual('front-end', encryption.control_location)
956 # self.assertIsNone(encryption.key_size)
957 # self.assertEqual(u'nova.volume.encryptors.luks.LuksEncryptor',
958 # encryption.provider)
959 # self.assertEqual(volume_type.id, encryption.volume_type_id)
962 class CreateStackFlavorTests(OSIntegrationTestCase):
964 Tests to ensure that floating IPs can be accessed via an
965 OpenStackFlavor object obtained from the OpenStackHeatStack instance
970 self.user_roles = ['heat_stack_owner', 'admin']
972 super(self.__class__, self).__start__()
974 self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
976 self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
977 self.stack_creator = None
979 self.heat_tmplt_path = pkg_resources.resource_filename(
980 'snaps.openstack.tests.heat', 'flavor_heat_template.yaml')
982 stack_settings = StackConfig(
983 name=self.guid + '-stack',
984 template_path=self.heat_tmplt_path)
985 self.stack_creator = OpenStackHeatStack(
986 self.os_creds, stack_settings)
987 self.created_stack = self.stack_creator.create(block=True)
988 self.assertIsNotNone(self.created_stack)
992 Cleans the stack and downloaded stack file
994 if self.stack_creator:
996 self.stack_creator.clean()
1000 super(self.__class__, self).__clean__()
1002 def test_retrieve_flavor_creator(self):
1004 Tests the creation of an OpenStack stack from Heat template file and
1005 the retrieval of an OpenStackVolume creator/state machine instance
1007 flavor_creators = self.stack_creator.get_flavor_creators()
1008 self.assertEqual(1, len(flavor_creators))
1010 creator = flavor_creators[0]
1011 self.assertTrue(creator.get_flavor().name.startswith(self.guid))
1012 self.assertEqual(1024, creator.get_flavor().ram)
1013 self.assertEqual(200, creator.get_flavor().disk)
1014 self.assertEqual(8, creator.get_flavor().vcpus)
1015 self.assertEqual(0, creator.get_flavor().ephemeral)
1016 self.assertIsNone(creator.get_flavor().swap)
1017 self.assertEqual(1.0, creator.get_flavor().rxtx_factor)
1018 self.assertTrue(creator.get_flavor().is_public)
1021 class CreateStackKeypairTests(OSIntegrationTestCase):
1023 Tests to ensure that floating IPs can be accessed via an
1024 OpenStackKeypair object obtained from the OpenStackHeatStack instance
1029 self.user_roles = ['heat_stack_owner']
1031 super(self.__class__, self).__start__()
1033 self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
1035 self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
1036 self.nova = nova_utils.nova_client(self.os_creds, self.os_session)
1037 self.stack_creator = None
1039 self.keypair_name = self.guid + '-kp'
1042 'keypair_name': self.keypair_name}
1044 self.heat_tmplt_path = pkg_resources.resource_filename(
1045 'snaps.openstack.tests.heat', 'keypair_heat_template.yaml')
1047 stack_settings = StackConfig(
1048 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
1049 template_path=self.heat_tmplt_path,
1050 env_values=self.env_values)
1051 self.stack_creator = OpenStackHeatStack(
1052 self.os_creds, stack_settings)
1053 self.created_stack = self.stack_creator.create(block=True)
1054 self.assertIsNotNone(self.created_stack)
1056 self.keypair_creators = list()
1060 Cleans the stack and downloaded stack file
1062 if self.stack_creator:
1064 self.stack_creator.clean()
1067 for keypair_creator in self.keypair_creators:
1069 keypair_creator.clean()
1073 super(self.__class__, self).__clean__()
1075 def test_retrieve_keypair_creator(self):
1077 Tests the creation of an OpenStack stack from Heat template file and
1078 the retrieval of an OpenStackKeypair creator/state machine instance
1080 self.kp_creators = self.stack_creator.get_keypair_creators(
1082 self.assertEqual(1, len(self.kp_creators))
1084 self.keypair_creator = self.kp_creators[0]
1086 self.assertEqual(self.keypair_name,
1087 self.keypair_creator.get_keypair().name)
1088 self.assertIsNotNone(
1089 self.keypair_creator.keypair_settings.private_filepath)
1091 private_file_contents = file_utils.read_file(
1092 self.keypair_creator.keypair_settings.private_filepath)
1093 self.assertTrue(private_file_contents.startswith(
1094 '-----BEGIN RSA PRIVATE KEY-----'))
1096 keypair = nova_utils.get_keypair_by_id(
1097 self.nova, self.keypair_creator.get_keypair().id)
1098 self.assertIsNotNone(keypair)
1099 self.assertEqual(self.keypair_creator.get_keypair(), keypair)
1102 class CreateStackSecurityGroupTests(OSIntegrationTestCase):
1104 Tests for the OpenStackHeatStack class to ensure it returns an
1105 OpenStackSecurityGroup object
1110 Instantiates the CreateStack object that is responsible for downloading
1111 and creating an OS stack file within OpenStack
1113 self.user_roles = ['heat_stack_owner']
1115 super(self.__class__, self).__start__()
1117 self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
1119 self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
1120 self.nova = nova_utils.nova_client(self.os_creds, self.os_session)
1121 self.stack_creator = None
1123 self.security_group_name = self.guid + '-sec-grp'
1126 'security_group_name': self.security_group_name}
1128 self.heat_tmplt_path = pkg_resources.resource_filename(
1129 'snaps.openstack.tests.heat', 'security_group_heat_template.yaml')
1131 stack_settings = StackConfig(
1132 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
1133 template_path=self.heat_tmplt_path,
1134 env_values=self.env_values)
1135 self.stack_creator = OpenStackHeatStack(
1136 self.os_creds, stack_settings)
1137 self.created_stack = self.stack_creator.create(block=True)
1138 self.assertIsNotNone(self.created_stack)
1142 Cleans the stack and downloaded stack file
1144 if self.stack_creator:
1146 self.stack_creator.clean()
1150 super(self.__class__, self).__clean__()
1152 def test_retrieve_security_group_creator(self):
1154 Tests the creation of an OpenStack stack from Heat template file and
1155 the retrieval of an OpenStackSecurityGroup creator/state machine
1158 sec_grp_creators = self.stack_creator.get_security_group_creators()
1159 self.assertEqual(1, len(sec_grp_creators))
1161 creator = sec_grp_creators[0]
1162 sec_grp = creator.get_security_group()
1164 self.assertEqual(self.security_group_name, sec_grp.name)
1165 self.assertEqual('Test description', sec_grp.description)
1166 self.assertEqual(2, len(sec_grp.rules))
1168 has_ssh_rule = False
1169 has_icmp_rule = False
1171 for rule in sec_grp.rules:
1172 if (rule.security_group_id == sec_grp.id
1173 and rule.direction == 'egress'
1174 and rule.ethertype == 'IPv4'
1175 and rule.port_range_min == 22
1176 and rule.port_range_max == 22
1177 and rule.protocol == 'tcp'
1178 and rule.remote_group_id is None
1179 and rule.remote_ip_prefix == '0.0.0.0/0'):
1181 if (rule.security_group_id == sec_grp.id
1182 and rule.direction == 'ingress'
1183 and rule.ethertype == 'IPv4'
1184 and rule.port_range_min is None
1185 and rule.port_range_max is None
1186 and rule.protocol == 'icmp'
1187 and rule.remote_group_id is None
1188 and rule.remote_ip_prefix == '0.0.0.0/0'):
1189 has_icmp_rule = True
1191 self.assertTrue(has_ssh_rule)
1192 self.assertTrue(has_icmp_rule)
1195 class CreateStackNegativeTests(OSIntegrationTestCase):
1197 Negative test cases for the OpenStackHeatStack class with poor
1202 self.user_roles = ['heat_stack_owner']
1204 super(self.__class__, self).__start__()
1206 self.stack_name = self.__class__.__name__ + '-' + str(uuid.uuid4())
1207 self.stack_creator = None
1208 self.heat_tmplt_path = pkg_resources.resource_filename(
1209 'snaps.openstack.tests.heat', 'test_heat_template.yaml')
1212 if self.stack_creator:
1213 self.stack_creator.clean()
1215 super(self.__class__, self).__clean__()
1217 def test_missing_dependencies(self):
1219 Expect an StackCreationError when the stack file does not exist
1221 stack_settings = StackConfig(name=self.stack_name,
1222 template_path=self.heat_tmplt_path)
1223 self.stack_creator = OpenStackHeatStack(
1224 self.os_creds, stack_settings)
1225 with self.assertRaises(HTTPBadRequest):
1226 self.stack_creator.create(block=True)
1228 def test_bad_stack_file(self):
1230 Expect an StackCreationError when the stack file does not exist
1232 stack_settings = StackConfig(
1233 name=self.stack_name, template_path='foo')
1234 self.stack_creator = OpenStackHeatStack(
1235 self.os_creds, stack_settings)
1236 with self.assertRaises(IOError):
1237 self.stack_creator.create(block=True)
1240 class CreateStackFailureTests(OSIntegrationTestCase):
1242 Tests for the OpenStackHeatStack class defined in create_stack.py for
1243 when failures occur. Failures are being triggered by allocating 1 million
1248 self.user_roles = ['heat_stack_owner']
1250 super(self.__class__, self).__start__()
1252 self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
1254 self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
1255 self.stack_creator = None
1257 self.tmp_file = file_utils.save_string_to_file(
1258 ' ', str(uuid.uuid4()) + '-bad-image')
1259 self.image_creator = OpenStackImage(
1260 self.os_creds, ImageConfig(
1261 name=self.guid + 'image', image_file=self.tmp_file.name,
1262 image_user='foo', img_format='qcow2'))
1263 self.image_creator.create()
1266 self.flavor_creator = OpenStackFlavor(
1267 self.admin_os_creds,
1269 name=self.guid + '-flavor-name', ram=256, disk=10,
1271 self.flavor_creator.create()
1273 self.network_name = self.guid + '-net'
1274 self.subnet_name = self.guid + '-subnet'
1275 self.vm_inst_name = self.guid + '-inst'
1278 'image_name': self.image_creator.image_settings.name,
1279 'flavor_name': self.flavor_creator.flavor_settings.name,
1280 'net_name': self.network_name,
1281 'subnet_name': self.subnet_name,
1282 'inst_name': self.vm_inst_name}
1284 self.heat_tmplt_path = pkg_resources.resource_filename(
1285 'snaps.openstack.tests.heat', 'test_heat_template.yaml')
1289 Cleans the stack and downloaded stack file
1291 if self.stack_creator:
1293 self.stack_creator.clean()
1297 if self.image_creator:
1299 self.image_creator.clean()
1303 if self.flavor_creator:
1305 self.flavor_creator.clean()
1311 os.remove(self.tmp_file.name)
1315 super(self.__class__, self).__clean__()
1317 def test_stack_failure(self):
1319 Tests the creation of an OpenStack stack from Heat template file that
1320 should always fail due to too many CPU cores
1323 # Set the default stack settings, then set any custom parameters sent
1325 stack_settings = StackConfig(
1326 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
1327 template_path=self.heat_tmplt_path,
1328 env_values=self.env_values)
1329 self.stack_creator = OpenStackHeatStack(
1330 self.os_creds, stack_settings)
1332 with self.assertRaises(StackError):
1334 self.stack_creator.create(block=True)
1336 resources = heat_utils.get_resources(
1337 self.heat_cli, self.stack_creator.get_stack().id)
1340 for resource in resources:
1341 if (resource.status ==
1342 snaps.config.stack.STATUS_CREATE_COMPLETE):
1344 self.assertTrue(found)