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 'net_name': self.network_name,
452 'subnet_name': self.subnet_name,
453 'inst1_name': self.vm_inst1_name,
454 'inst2_name': self.vm_inst2_name,
455 'keypair_name': self.keypair_name,
456 'external_net_name': self.ext_net_name,
457 'security_group_name': self.sec_grp_name}
459 self.heat_tmplt_path = pkg_resources.resource_filename(
460 'snaps.openstack.tests.heat', 'floating_ip_heat_template.yaml')
462 self.vm_inst_creators = list()
466 Cleans the stack and downloaded stack file
468 if self.stack_creator:
470 self.stack_creator.clean()
474 if self.image_creator:
476 self.image_creator.clean()
480 for vm_inst_creator in self.vm_inst_creators:
482 keypair_settings = vm_inst_creator.keypair_settings
483 if keypair_settings and keypair_settings.private_filepath:
484 expanded_path = os.path.expanduser(
485 keypair_settings.private_filepath)
486 os.chmod(expanded_path, 0o755)
487 os.remove(expanded_path)
491 super(self.__class__, self).__clean__()
493 def test_connect_via_ssh_heat_vm(self):
495 Tests the creation of an OpenStack stack from Heat template file and
496 the retrieval of two VM instance creators and attempt to connect via
497 SSH to the first one with a floating IP.
499 stack_settings = StackConfig(
500 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
501 template_path=self.heat_tmplt_path,
502 env_values=self.env_values)
503 self.stack_creator = OpenStackHeatStack(
504 self.os_creds, stack_settings,
505 [self.image_creator.image_settings])
506 created_stack = self.stack_creator.create(block=True)
507 self.assertIsNotNone(created_stack)
509 self.vm_inst_creators = self.stack_creator.get_vm_inst_creators(
510 heat_keypair_option='private_key')
511 self.assertIsNotNone(self.vm_inst_creators)
512 self.assertEqual(2, len(self.vm_inst_creators))
514 for vm_inst_creator in self.vm_inst_creators:
515 if vm_inst_creator.get_vm_inst().name == self.vm_inst1_name:
517 create_instance_tests.validate_ssh_client(vm_inst_creator))
519 vm_settings = vm_inst_creator.instance_settings
520 self.assertEqual(0, len(vm_settings.floating_ip_settings))
522 def test_connect_via_ssh_heat_vm_derived(self):
524 Tests the the retrieval of two VM instance creators from a derived
525 OpenStackHeatStack object and attempt to connect via
526 SSH to the first one with a floating IP.
528 stack_settings = StackConfig(
529 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
530 template_path=self.heat_tmplt_path,
531 env_values=self.env_values)
532 self.stack_creator = OpenStackHeatStack(
533 self.os_creds, stack_settings,
534 [self.image_creator.image_settings])
535 created_stack = self.stack_creator.create(block=True)
536 self.assertIsNotNone(created_stack)
538 derived_stack = create_stack.generate_creator(
539 self.os_creds, created_stack,
540 [self.image_creator.image_settings])
542 self.vm_inst_creators = derived_stack.get_vm_inst_creators(
543 heat_keypair_option='private_key')
544 self.assertIsNotNone(self.vm_inst_creators)
545 self.assertEqual(2, len(self.vm_inst_creators))
547 for vm_inst_creator in self.vm_inst_creators:
548 if vm_inst_creator.get_vm_inst().name == self.vm_inst1_name:
550 create_instance_tests.validate_ssh_client(vm_inst_creator))
552 vm_settings = vm_inst_creator.instance_settings
553 self.assertEqual(0, len(vm_settings.floating_ip_settings))
556 class CreateStackNestedResourceTests(OSIntegrationTestCase):
558 Tests to ensure that nested heat templates work
562 self.user_roles = ['heat_stack_owner']
564 super(self.__class__, self).__start__()
566 self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
568 self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
569 self.stack_creator = None
571 self.image_creator = OpenStackImage(
572 self.os_creds, openstack_tests.cirros_image_settings(
573 name="{}-{}".format(self.guid, 'image'),
574 image_metadata=self.image_metadata))
575 self.image_creator.create()
577 flavor_config = openstack_tests.get_flavor_config(
578 name="{}-{}".format(self.guid, 'flavor-name'), ram=256, disk=10,
579 vcpus=1, metadata=self.flavor_metadata)
580 self.flavor_creator = OpenStackFlavor(
581 self.admin_os_creds, flavor_config)
582 self.flavor_creator.create()
585 'network_name': self.guid + '-network',
586 'public_network': self.ext_net_name,
587 'agent_image': self.image_creator.image_settings.name,
588 'agent_flavor': self.flavor_creator.flavor_settings.name,
589 'key_name': self.guid + '-key',
592 heat_tmplt_path = pkg_resources.resource_filename(
593 'snaps.openstack.tests.heat', 'agent-group.yaml')
594 heat_resource_path = pkg_resources.resource_filename(
595 'snaps.openstack.tests.heat', 'agent.yaml')
597 stack_settings = StackConfig(
599 self.__class__.__name__, str(self.guid) + '-stack'),
600 template_path=heat_tmplt_path,
601 resource_files=[heat_resource_path],
602 env_values=env_values)
604 self.stack_creator = OpenStackHeatStack(
605 self.os_creds, stack_settings,
606 [self.image_creator.image_settings])
608 self.vm_inst_creators = list()
612 Cleans the stack and downloaded stack file
614 if self.stack_creator:
616 self.stack_creator.clean()
620 if self.image_creator:
622 self.image_creator.clean()
626 if self.flavor_creator:
628 self.flavor_creator.clean()
632 for vm_inst_creator in self.vm_inst_creators:
634 keypair_settings = vm_inst_creator.keypair_settings
635 if keypair_settings and keypair_settings.private_filepath:
636 expanded_path = os.path.expanduser(
637 keypair_settings.private_filepath)
638 os.chmod(expanded_path, 0o755)
639 os.remove(expanded_path)
643 super(self.__class__, self).__clean__()
645 def test_nested(self):
647 Tests the creation of an OpenStack stack from Heat template file and
648 the retrieval of two VM instance creators and attempt to connect via
649 SSH to the first one with a floating IP.
651 created_stack = self.stack_creator.create(block=True)
652 self.assertIsNotNone(created_stack)
654 self.vm_inst_creators = self.stack_creator.get_vm_inst_creators(
655 heat_keypair_option='private_key')
656 self.assertIsNotNone(self.vm_inst_creators)
657 self.assertEqual(1, len(self.vm_inst_creators))
659 for vm_inst_creator in self.vm_inst_creators:
661 create_instance_tests.validate_ssh_client(vm_inst_creator))
664 class CreateStackUpdateTests(OSIntegrationTestCase):
666 Tests to ensure that stack update commands work
670 self.user_roles = ['heat_stack_owner']
672 super(self.__class__, self).__start__()
674 self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
676 self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
677 self.stack_creator = None
679 self.image_creator = OpenStackImage(
680 self.os_creds, openstack_tests.cirros_image_settings(
681 name=self.guid + '-image',
682 image_metadata=self.image_metadata))
683 self.image_creator.create()
685 self.flavor_creator = OpenStackFlavor(
688 name=self.guid + '-flavor-name', ram=256, disk=10, vcpus=1))
689 self.flavor_creator.create()
692 'network_name': self.guid + '-network',
693 'public_network': self.ext_net_name,
694 'agent_image': self.image_creator.image_settings.name,
695 'agent_flavor': self.flavor_creator.flavor_settings.name,
696 'key_name': self.guid + '-key',
699 heat_tmplt_path = pkg_resources.resource_filename(
700 'snaps.openstack.tests.heat', 'agent-group.yaml')
701 heat_resource_path = pkg_resources.resource_filename(
702 'snaps.openstack.tests.heat', 'agent.yaml')
704 stack_settings = StackConfig(
705 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
706 template_path=heat_tmplt_path,
707 resource_files=[heat_resource_path],
708 env_values=env_values)
710 self.stack_creator = OpenStackHeatStack(
711 self.os_creds, stack_settings,
712 [self.image_creator.image_settings])
714 self.vm_inst_creators = list()
718 Cleans the stack and downloaded stack file
720 if self.stack_creator:
722 self.stack_creator.clean()
726 if self.image_creator:
728 self.image_creator.clean()
732 if self.flavor_creator:
734 self.flavor_creator.clean()
738 for vm_inst_creator in self.vm_inst_creators:
740 keypair_settings = vm_inst_creator.keypair_settings
741 if keypair_settings and keypair_settings.private_filepath:
742 expanded_path = os.path.expanduser(
743 keypair_settings.private_filepath)
744 os.chmod(expanded_path, 0o755)
745 os.remove(expanded_path)
749 super(self.__class__, self).__clean__()
751 def test_update(self):
753 Tests the update of an OpenStack stack from Heat template file
754 by changing the number of VM instances from 1 to 2, and
755 the retrieval of two VM instance creators and attempt to connect via
756 SSH to the first one with a floating IP.
758 created_stack = self.stack_creator.create(block=True)
759 self.assertIsNotNone(created_stack)
761 self.vm_inst_creators = self.stack_creator.get_vm_inst_creators(
762 heat_keypair_option='private_key')
763 self.assertIsNotNone(self.vm_inst_creators)
764 self.assertEqual(1, len(self.vm_inst_creators))
766 for vm_inst_creator in self.vm_inst_creators:
768 create_instance_tests.validate_ssh_client(vm_inst_creator))
771 'network_name': self.guid + '-network',
772 'public_network': self.ext_net_name,
774 'agent_image': self.image_creator.image_settings.name,
775 'agent_flavor': self.flavor_creator.flavor_settings.name,
776 'key_name': self.guid + '-key',
779 updated_stack = self.stack_creator.update(env_values, block=True)
780 self.assertIsNotNone(updated_stack)
781 self.assertEqual(STATUS_UPDATE_COMPLETE, updated_stack.status)
783 self.vm_inst_creators = self.stack_creator.get_vm_inst_creators(
784 heat_keypair_option='private_key')
785 self.assertIsNotNone(self.vm_inst_creators)
786 self.assertEqual(2, len(self.vm_inst_creators))
788 for vm_inst_creator in self.vm_inst_creators:
790 create_instance_tests.validate_ssh_client(vm_inst_creator))
793 class CreateStackRouterTests(OSIntegrationTestCase):
795 Tests for the CreateStack class defined in create_stack.py where the
796 target is a Network, Subnet, and Router
801 Instantiates the CreateStack object that is responsible for downloading
802 and creating an OS stack file within OpenStack
804 self.user_roles = ['heat_stack_owner']
806 super(self.__class__, self).__start__()
808 self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
810 self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
811 self.neutron = neutron_utils.neutron_client(
812 self.os_creds, self.os_session)
813 self.stack_creator = None
815 self.net_name = self.guid + '-net'
816 self.subnet_name = self.guid + '-subnet'
817 self.router_name = self.guid + '-router'
820 'net_name': self.net_name,
821 'subnet_name': self.subnet_name,
822 'router_name': self.router_name,
823 'external_net_name': self.ext_net_name}
825 self.heat_tmplt_path = pkg_resources.resource_filename(
826 'snaps.openstack.tests.heat', 'router_heat_template.yaml')
828 stack_settings = StackConfig(
829 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
830 template_path=self.heat_tmplt_path,
831 env_values=self.env_values)
832 self.stack_creator = OpenStackHeatStack(
833 self.os_creds, stack_settings)
834 self.created_stack = self.stack_creator.create(block=True)
835 self.assertIsNotNone(self.created_stack)
839 Cleans the stack and downloaded stack file
841 if self.stack_creator:
843 self.stack_creator.clean()
847 super(self.__class__, self).__clean__()
849 def test_retrieve_router_creator(self):
851 Tests the creation of an OpenStack stack from Heat template file and
852 the retrieval of an OpenStackRouter creator/state machine instance
854 router_creators = self.stack_creator.get_router_creators()
855 self.assertEqual(1, len(router_creators))
857 creator = router_creators[0]
858 self.assertEqual(self.router_name, creator.router_settings.name)
860 router = creator.get_router()
862 ext_net = neutron_utils.get_network(
863 self.neutron, self.keystone, network_name=self.ext_net_name)
864 self.assertEqual(ext_net.id, router.external_network_id)
867 class CreateStackVolumeTests(OSIntegrationTestCase):
869 Tests to ensure that floating IPs can be accessed via an
870 OpenStackVolume object obtained from the OpenStackHeatStack instance
875 self.user_roles = ['heat_stack_owner', 'admin']
877 super(self.__class__, self).__start__()
879 self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
881 self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
882 self.stack_creator = None
884 self.volume_name = self.guid + '-volume'
885 self.volume_type_name = self.guid + '-volume-type'
888 'volume_name': self.volume_name,
889 'volume_type_name': self.volume_type_name}
891 self.heat_tmplt_path = pkg_resources.resource_filename(
892 'snaps.openstack.tests.heat', 'volume_heat_template.yaml')
894 stack_settings = StackConfig(
895 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
896 template_path=self.heat_tmplt_path,
897 env_values=self.env_values)
898 self.stack_creator = OpenStackHeatStack(
899 self.os_creds, stack_settings)
900 self.created_stack = self.stack_creator.create(block=True)
901 self.assertIsNotNone(self.created_stack)
905 Cleans the stack and downloaded stack file
907 if self.stack_creator:
909 self.stack_creator.clean()
913 super(self.__class__, self).__clean__()
915 def test_retrieve_volume_creator(self):
917 Tests the creation of an OpenStack stack from Heat template file and
918 the retrieval of an OpenStackVolume creator/state machine instance
920 volume_creators = self.stack_creator.get_volume_creators()
921 self.assertEqual(1, len(volume_creators))
923 creator = volume_creators[0]
924 self.assertEqual(self.volume_name, creator.volume_settings.name)
925 self.assertEqual(self.volume_name, creator.get_volume().name)
926 self.assertEqual(self.volume_type_name,
927 creator.volume_settings.type_name)
928 self.assertEqual(self.volume_type_name, creator.get_volume().type)
929 self.assertEqual(1, creator.volume_settings.size)
930 self.assertEqual(1, creator.get_volume().size)
932 def test_retrieve_volume_type_creator(self):
934 Tests the creation of an OpenStack stack from Heat template file and
935 the retrieval of an OpenStackVolume creator/state machine instance
937 volume_type_creators = self.stack_creator.get_volume_type_creators()
938 self.assertEqual(1, len(volume_type_creators))
940 creator = volume_type_creators[0]
941 self.assertIsNotNone(creator)
943 volume_type = creator.get_volume_type()
944 self.assertIsNotNone(volume_type)
946 self.assertEqual(self.volume_type_name, volume_type.name)
947 self.assertTrue(volume_type.public)
948 self.assertIsNone(volume_type.qos_spec)
950 # TODO - Add encryption back and find out why it broke in Pike
951 # encryption = volume_type.encryption
952 # self.assertIsNotNone(encryption)
953 # self.assertIsNone(encryption.cipher)
954 # self.assertEqual('front-end', encryption.control_location)
955 # self.assertIsNone(encryption.key_size)
956 # self.assertEqual(u'nova.volume.encryptors.luks.LuksEncryptor',
957 # encryption.provider)
958 # self.assertEqual(volume_type.id, encryption.volume_type_id)
961 class CreateStackFlavorTests(OSIntegrationTestCase):
963 Tests to ensure that floating IPs can be accessed via an
964 OpenStackFlavor object obtained from the OpenStackHeatStack instance
969 self.user_roles = ['heat_stack_owner', 'admin']
971 super(self.__class__, self).__start__()
973 self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
975 self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
976 self.stack_creator = None
978 self.heat_tmplt_path = pkg_resources.resource_filename(
979 'snaps.openstack.tests.heat', 'flavor_heat_template.yaml')
981 stack_settings = StackConfig(
982 name=self.guid + '-stack',
983 template_path=self.heat_tmplt_path)
984 self.stack_creator = OpenStackHeatStack(
985 self.os_creds, stack_settings)
986 self.created_stack = self.stack_creator.create(block=True)
987 self.assertIsNotNone(self.created_stack)
991 Cleans the stack and downloaded stack file
993 if self.stack_creator:
995 self.stack_creator.clean()
999 super(self.__class__, self).__clean__()
1001 def test_retrieve_flavor_creator(self):
1003 Tests the creation of an OpenStack stack from Heat template file and
1004 the retrieval of an OpenStackVolume creator/state machine instance
1006 flavor_creators = self.stack_creator.get_flavor_creators()
1007 self.assertEqual(1, len(flavor_creators))
1009 creator = flavor_creators[0]
1010 self.assertTrue(creator.get_flavor().name.startswith(self.guid))
1011 self.assertEqual(1024, creator.get_flavor().ram)
1012 self.assertEqual(200, creator.get_flavor().disk)
1013 self.assertEqual(8, creator.get_flavor().vcpus)
1014 self.assertEqual(0, creator.get_flavor().ephemeral)
1015 self.assertIsNone(creator.get_flavor().swap)
1016 self.assertEqual(1.0, creator.get_flavor().rxtx_factor)
1017 self.assertTrue(creator.get_flavor().is_public)
1020 class CreateStackKeypairTests(OSIntegrationTestCase):
1022 Tests to ensure that floating IPs can be accessed via an
1023 OpenStackKeypair object obtained from the OpenStackHeatStack instance
1028 self.user_roles = ['heat_stack_owner']
1030 super(self.__class__, self).__start__()
1032 self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
1034 self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
1035 self.nova = nova_utils.nova_client(self.os_creds, self.os_session)
1036 self.stack_creator = None
1038 self.keypair_name = self.guid + '-kp'
1041 'keypair_name': self.keypair_name}
1043 self.heat_tmplt_path = pkg_resources.resource_filename(
1044 'snaps.openstack.tests.heat', 'keypair_heat_template.yaml')
1046 stack_settings = StackConfig(
1047 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
1048 template_path=self.heat_tmplt_path,
1049 env_values=self.env_values)
1050 self.stack_creator = OpenStackHeatStack(
1051 self.os_creds, stack_settings)
1052 self.created_stack = self.stack_creator.create(block=True)
1053 self.assertIsNotNone(self.created_stack)
1055 self.keypair_creators = list()
1059 Cleans the stack and downloaded stack file
1061 if self.stack_creator:
1063 self.stack_creator.clean()
1066 for keypair_creator in self.keypair_creators:
1068 keypair_creator.clean()
1072 super(self.__class__, self).__clean__()
1074 def test_retrieve_keypair_creator(self):
1076 Tests the creation of an OpenStack stack from Heat template file and
1077 the retrieval of an OpenStackKeypair creator/state machine instance
1079 self.kp_creators = self.stack_creator.get_keypair_creators(
1081 self.assertEqual(1, len(self.kp_creators))
1083 self.keypair_creator = self.kp_creators[0]
1085 self.assertEqual(self.keypair_name,
1086 self.keypair_creator.get_keypair().name)
1087 self.assertIsNotNone(
1088 self.keypair_creator.keypair_settings.private_filepath)
1090 private_file_contents = file_utils.read_file(
1091 self.keypair_creator.keypair_settings.private_filepath)
1092 self.assertTrue(private_file_contents.startswith(
1093 '-----BEGIN RSA PRIVATE KEY-----'))
1095 keypair = nova_utils.get_keypair_by_id(
1096 self.nova, self.keypair_creator.get_keypair().id)
1097 self.assertIsNotNone(keypair)
1098 self.assertEqual(self.keypair_creator.get_keypair(), keypair)
1101 class CreateStackSecurityGroupTests(OSIntegrationTestCase):
1103 Tests for the OpenStackHeatStack class to ensure it returns an
1104 OpenStackSecurityGroup object
1109 Instantiates the CreateStack object that is responsible for downloading
1110 and creating an OS stack file within OpenStack
1112 self.user_roles = ['heat_stack_owner']
1114 super(self.__class__, self).__start__()
1116 self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
1118 self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
1119 self.nova = nova_utils.nova_client(self.os_creds, self.os_session)
1120 self.stack_creator = None
1122 self.security_group_name = self.guid + '-sec-grp'
1125 'security_group_name': self.security_group_name}
1127 self.heat_tmplt_path = pkg_resources.resource_filename(
1128 'snaps.openstack.tests.heat', 'security_group_heat_template.yaml')
1130 stack_settings = StackConfig(
1131 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
1132 template_path=self.heat_tmplt_path,
1133 env_values=self.env_values)
1134 self.stack_creator = OpenStackHeatStack(
1135 self.os_creds, stack_settings)
1136 self.created_stack = self.stack_creator.create(block=True)
1137 self.assertIsNotNone(self.created_stack)
1141 Cleans the stack and downloaded stack file
1143 if self.stack_creator:
1145 self.stack_creator.clean()
1149 super(self.__class__, self).__clean__()
1151 def test_retrieve_security_group_creator(self):
1153 Tests the creation of an OpenStack stack from Heat template file and
1154 the retrieval of an OpenStackSecurityGroup creator/state machine
1157 sec_grp_creators = self.stack_creator.get_security_group_creators()
1158 self.assertEqual(1, len(sec_grp_creators))
1160 creator = sec_grp_creators[0]
1161 sec_grp = creator.get_security_group()
1163 self.assertEqual(self.security_group_name, sec_grp.name)
1164 self.assertEqual('Test description', sec_grp.description)
1165 self.assertEqual(2, len(sec_grp.rules))
1167 has_ssh_rule = False
1168 has_icmp_rule = False
1170 for rule in sec_grp.rules:
1171 if (rule.security_group_id == sec_grp.id
1172 and rule.direction == 'egress'
1173 and rule.ethertype == 'IPv4'
1174 and rule.port_range_min == 22
1175 and rule.port_range_max == 22
1176 and rule.protocol == 'tcp'
1177 and rule.remote_group_id is None
1178 and rule.remote_ip_prefix == '0.0.0.0/0'):
1180 if (rule.security_group_id == sec_grp.id
1181 and rule.direction == 'ingress'
1182 and rule.ethertype == 'IPv4'
1183 and rule.port_range_min is None
1184 and rule.port_range_max is None
1185 and rule.protocol == 'icmp'
1186 and rule.remote_group_id is None
1187 and rule.remote_ip_prefix == '0.0.0.0/0'):
1188 has_icmp_rule = True
1190 self.assertTrue(has_ssh_rule)
1191 self.assertTrue(has_icmp_rule)
1194 class CreateStackNegativeTests(OSIntegrationTestCase):
1196 Negative test cases for the OpenStackHeatStack class with poor
1201 self.user_roles = ['heat_stack_owner']
1203 super(self.__class__, self).__start__()
1205 self.stack_name = self.__class__.__name__ + '-' + str(uuid.uuid4())
1206 self.stack_creator = None
1207 self.heat_tmplt_path = pkg_resources.resource_filename(
1208 'snaps.openstack.tests.heat', 'test_heat_template.yaml')
1211 if self.stack_creator:
1212 self.stack_creator.clean()
1214 super(self.__class__, self).__clean__()
1216 def test_missing_dependencies(self):
1218 Expect an StackCreationError when the stack file does not exist
1220 stack_settings = StackConfig(name=self.stack_name,
1221 template_path=self.heat_tmplt_path)
1222 self.stack_creator = OpenStackHeatStack(
1223 self.os_creds, stack_settings)
1224 with self.assertRaises(HTTPBadRequest):
1225 self.stack_creator.create(block=True)
1227 def test_bad_stack_file(self):
1229 Expect an StackCreationError when the stack file does not exist
1231 stack_settings = StackConfig(
1232 name=self.stack_name, template_path='foo')
1233 self.stack_creator = OpenStackHeatStack(
1234 self.os_creds, stack_settings)
1235 with self.assertRaises(IOError):
1236 self.stack_creator.create(block=True)
1239 class CreateStackFailureTests(OSIntegrationTestCase):
1241 Tests for the OpenStackHeatStack class defined in create_stack.py for
1242 when failures occur. Failures are being triggered by allocating 1 million
1247 self.user_roles = ['heat_stack_owner']
1249 super(self.__class__, self).__start__()
1251 self.guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
1253 self.heat_cli = heat_utils.heat_client(self.os_creds, self.os_session)
1254 self.stack_creator = None
1256 self.tmp_file = file_utils.save_string_to_file(
1257 ' ', str(uuid.uuid4()) + '-bad-image')
1258 self.image_creator = OpenStackImage(
1259 self.os_creds, ImageConfig(
1260 name=self.guid + 'image', image_file=self.tmp_file.name,
1261 image_user='foo', img_format='qcow2'))
1262 self.image_creator.create()
1265 self.flavor_creator = OpenStackFlavor(
1266 self.admin_os_creds,
1268 name=self.guid + '-flavor-name', ram=256, disk=10,
1270 self.flavor_creator.create()
1272 self.network_name = self.guid + '-net'
1273 self.subnet_name = self.guid + '-subnet'
1274 self.vm_inst_name = self.guid + '-inst'
1277 'image_name': self.image_creator.image_settings.name,
1278 'flavor_name': self.flavor_creator.flavor_settings.name,
1279 'net_name': self.network_name,
1280 'subnet_name': self.subnet_name,
1281 'inst_name': self.vm_inst_name}
1283 self.heat_tmplt_path = pkg_resources.resource_filename(
1284 'snaps.openstack.tests.heat', 'test_heat_template.yaml')
1288 Cleans the stack and downloaded stack file
1290 if self.stack_creator:
1292 self.stack_creator.clean()
1296 if self.image_creator:
1298 self.image_creator.clean()
1302 if self.flavor_creator:
1304 self.flavor_creator.clean()
1310 os.remove(self.tmp_file.name)
1314 super(self.__class__, self).__clean__()
1316 def test_stack_failure(self):
1318 Tests the creation of an OpenStack stack from Heat template file that
1319 should always fail due to too many CPU cores
1322 # Set the default stack settings, then set any custom parameters sent
1324 stack_settings = StackConfig(
1325 name=self.__class__.__name__ + '-' + str(self.guid) + '-stack',
1326 template_path=self.heat_tmplt_path,
1327 env_values=self.env_values)
1328 self.stack_creator = OpenStackHeatStack(
1329 self.os_creds, stack_settings)
1331 with self.assertRaises(StackError):
1333 self.stack_creator.create(block=True)
1335 resources = heat_utils.get_resources(
1336 self.heat_cli, self.stack_creator.get_stack().id)
1339 for resource in resources:
1340 if (resource.status ==
1341 snaps.config.stack.STATUS_CREATE_COMPLETE):
1343 self.assertTrue(found)