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.
23 import snaps.config.stack as stack_config
24 from snaps.config.flavor import FlavorConfig
25 from snaps.openstack.create_flavor import OpenStackFlavor
27 from snaps.openstack.create_image import OpenStackImage
28 from snaps.openstack.create_instance import OpenStackVmInstance
29 from snaps.openstack.create_stack import StackConfig
30 from snaps.openstack.tests import openstack_tests
31 from snaps.openstack.tests.os_source_file_test import OSComponentTestCase
32 from snaps.openstack.utils import (
33 heat_utils, neutron_utils, nova_utils, settings_utils, glance_utils,
34 cinder_utils, keystone_utils)
36 __author__ = 'spisarski'
38 logger = logging.getLogger('heat_utils_tests')
41 class HeatSmokeTests(OSComponentTestCase):
43 Tests to ensure that the heat client can communicate with the cloud
46 def test_heat_connect_success(self):
48 Tests to ensure that the proper credentials can connect.
50 heat = heat_utils.heat_client(self.os_creds, self.os_session)
52 # This should not throw an exception
53 stacks = heat.stacks.list()
55 logger.info('Stack - %s', stack)
57 def test_heat_connect_fail(self):
59 Tests to ensure that the improper credentials cannot connect.
61 from snaps.openstack.os_credentials import OSCreds
63 heat = heat_utils.heat_client(
64 OSCreds(username='user', password='pass',
65 auth_url=self.os_creds.auth_url,
66 project_name=self.os_creds.project_name,
67 proxy_settings=self.os_creds.proxy_settings))
68 stacks = heat.stacks.list()
70 # This should throw an exception
71 with self.assertRaises(Exception):
73 logger.info('Stack - %s', stack)
76 class HeatUtilsCreateSimpleStackTests(OSComponentTestCase):
78 Test basic Heat functionality
83 Instantiates OpenStack instances that cannot be spawned by Heat
85 guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
86 stack_name1 = guid + '-stack1'
87 stack_name2 = guid + '-stack2'
88 self.network_name = guid + '-net'
89 self.subnet_name = guid + '-subnet'
90 self.vm_inst_name = guid + '-inst'
92 self.image_creator = OpenStackImage(
93 self.os_creds, openstack_tests.cirros_image_settings(
94 name=guid + '-image', image_metadata=self.image_metadata))
95 self.image_creator.create()
98 self.flavor_creator = OpenStackFlavor(
100 FlavorConfig(name=guid + '-flavor', ram=256, disk=10, vcpus=1))
101 self.flavor_creator.create()
103 env_values = {'image_name': self.image_creator.image_settings.name,
104 'flavor_name': self.flavor_creator.flavor_settings.name,
105 'net_name': self.network_name,
106 'subnet_name': self.subnet_name,
107 'inst_name': self.vm_inst_name}
108 heat_tmplt_path = pkg_resources.resource_filename(
109 'snaps.openstack.tests.heat', 'test_heat_template.yaml')
110 self.stack_settings1 = StackConfig(
111 name=stack_name1, template_path=heat_tmplt_path,
112 env_values=env_values)
113 self.stack_settings2 = StackConfig(
114 name=stack_name2, template_path=heat_tmplt_path,
115 env_values=env_values)
118 self.heat_client = heat_utils.heat_client(
119 self.os_creds, self.os_session)
123 Cleans the stack and image
127 heat_utils.delete_stack(self.heat_client, self.stack1)
133 heat_utils.delete_stack(self.heat_client, self.stack2)
137 if self.image_creator:
139 self.image_creator.clean()
143 if self.flavor_creator:
145 self.flavor_creator.clean()
149 super(self.__class__, self).__clean__()
151 def test_create_stack(self):
153 Tests the creation of an OpenStack Heat stack1 that does not exist.
155 self.stack1 = heat_utils.create_stack(self.heat_client,
156 self.stack_settings1)
158 stack_query_1 = heat_utils.get_stack(
159 self.heat_client, stack_settings=self.stack_settings1)
160 self.assertEqual(self.stack1, stack_query_1)
162 stack_query_2 = heat_utils.get_stack(
163 self.heat_client, stack_name=self.stack_settings1.name)
164 self.assertEqual(self.stack1, stack_query_2)
166 stack_query_3 = heat_utils.get_stack_by_id(self.heat_client,
168 self.assertEqual(self.stack1, stack_query_3)
170 resources = heat_utils.get_resources(self.heat_client, self.stack1.id)
171 self.assertIsNotNone(resources)
172 self.assertEqual(4, len(resources))
174 outputs = heat_utils.get_outputs(self.heat_client, self.stack1)
175 self.assertIsNotNone(outputs)
176 self.assertEqual(0, len(outputs))
178 self.assertTrue(stack_active(self.heat_client, self.stack1))
180 neutron = neutron_utils.neutron_client(self.os_creds, self.os_session)
181 networks = heat_utils.get_stack_networks(
182 self.heat_client, neutron, self.stack1)
183 self.assertIsNotNone(networks)
184 self.assertEqual(1, len(networks))
185 self.assertEqual(self.network_name, networks[0].name)
187 subnets = neutron_utils.get_subnets_by_network(neutron, networks[0])
188 self.assertEqual(1, len(subnets))
189 self.assertEqual(self.subnet_name, subnets[0].name)
191 nova = nova_utils.nova_client(self.os_creds, self.os_session)
192 keystone = keystone_utils.keystone_client(
193 self.os_creds, self.os_session)
194 servers = heat_utils.get_stack_servers(
195 self.heat_client, nova, neutron, keystone, self.stack1,
196 self.os_creds.project_name)
197 self.assertIsNotNone(servers)
198 self.assertEqual(1, len(servers))
199 self.assertEqual(self.vm_inst_name, servers[0].name)
201 def test_create_stack_x2(self):
203 Tests the creation of an OpenStack keypair that does not exist.
205 self.stack1 = heat_utils.create_stack(self.heat_client,
206 self.stack_settings1)
208 stack1_query_1 = heat_utils.get_stack(
209 self.heat_client, stack_settings=self.stack_settings1)
210 self.assertEqual(self.stack1, stack1_query_1)
212 stack1_query_2 = heat_utils.get_stack(
213 self.heat_client, stack_name=self.stack_settings1.name)
214 self.assertEqual(self.stack1, stack1_query_2)
216 stack1_query_3 = heat_utils.get_stack_by_id(self.heat_client,
218 self.assertEqual(self.stack1, stack1_query_3)
220 self.assertTrue(stack_active(self.heat_client, self.stack1))
222 self.stack2 = heat_utils.create_stack(self.heat_client,
223 self.stack_settings2)
225 stack2_query_1 = heat_utils.get_stack(
226 self.heat_client, stack_settings=self.stack_settings2)
227 self.assertEqual(self.stack2, stack2_query_1)
229 stack2_query_2 = heat_utils.get_stack(
230 self.heat_client, stack_name=self.stack_settings2.name)
231 self.assertEqual(self.stack2, stack2_query_2)
233 stack2_query_3 = heat_utils.get_stack_by_id(self.heat_client,
235 self.assertEqual(self.stack2, stack2_query_3)
237 self.assertTrue(stack_active(self.heat_client, self.stack2))
240 class HeatUtilsCreateComplexStackTests(OSComponentTestCase):
242 Test basic Heat functionality
247 Instantiates OpenStack instances that cannot be spawned by Heat
249 guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
250 stack_name = guid + '-stack'
251 self.network_name = guid + '-net'
252 self.subnet_name = guid + '-subnet'
253 self.vm_inst1_name = guid + '-inst1'
254 self.vm_inst2_name = guid + '-inst2'
255 self.flavor1_name = guid + '-flavor1'
256 self.flavor2_name = guid + '-flavor2'
257 self.keypair_name = guid + '-keypair'
259 self.image_creator1 = OpenStackImage(
260 self.os_creds, openstack_tests.cirros_image_settings(
261 name=guid + '-image1', image_metadata=self.image_metadata))
262 self.image_creator1.create()
264 self.image_creator2 = OpenStackImage(
265 self.os_creds, openstack_tests.cirros_image_settings(
266 name=guid + '-image2', image_metadata=self.image_metadata))
267 self.image_creator2.create()
269 env_values = {'image1_name': self.image_creator1.image_settings.name,
270 'image2_name': self.image_creator2.image_settings.name,
271 'flavor1_name': self.flavor1_name,
272 'flavor2_name': self.flavor2_name,
273 'net_name': self.network_name,
274 'subnet_name': self.subnet_name,
275 'keypair_name': self.keypair_name,
276 'inst1_name': self.vm_inst1_name,
277 'inst2_name': self.vm_inst2_name,
278 'external_net_name': self.ext_net_name}
279 heat_tmplt_path = pkg_resources.resource_filename(
280 'snaps.openstack.tests.heat', 'floating_ip_heat_template.yaml')
281 stack_settings = StackConfig(
282 name=stack_name, template_path=heat_tmplt_path,
283 env_values=env_values)
284 self.heat_client = heat_utils.heat_client(
285 self.os_creds, self.os_session)
286 self.stack = heat_utils.create_stack(self.heat_client, stack_settings)
288 self.assertTrue(stack_active(self.heat_client, self.stack))
290 self.keypair1_settings = None
291 self.keypair2_settings = None
295 Cleans the stack and image
299 heat_utils.delete_stack(self.heat_client, self.stack)
300 # Wait until stack deployment has completed
301 end_time = (time.time() +
302 stack_config.STACK_COMPLETE_TIMEOUT)
304 while time.time() < end_time:
305 status = heat_utils.get_stack_status(self.heat_client,
307 if status == stack_config.STATUS_DELETE_COMPLETE:
310 elif status == stack_config.STATUS_DELETE_FAILED:
317 nova = nova_utils.nova_client(
318 self.os_creds, self.os_session)
319 keystone = keystone_utils.keystone_client(
320 self.os_creds, self.os_session)
321 neutron = neutron_utils.neutron_client(
322 self.os_creds, self.os_session)
323 glance = glance_utils.glance_client(
324 self.os_creds, self.os_session)
326 servers = heat_utils.get_stack_servers(
327 self.heat_client, nova, neutron, keystone, self.stack,
328 self.os_creds.project_name)
329 for server in servers:
330 vm_settings = settings_utils.create_vm_inst_config(
331 nova, keystone, neutron, server,
332 self.os_creds.project_name)
333 img_settings = settings_utils.determine_image_config(
335 [self.image_creator1.image_settings,
336 self.image_creator2.image_settings])
337 vm_creator = OpenStackVmInstance(
338 self.os_creds, vm_settings, img_settings)
339 vm_creator.initialize()
341 vm_creator.vm_deleted(block=True)
343 heat_utils.delete_stack(self.heat_client, self.stack)
348 if self.image_creator1:
350 self.image_creator1.clean()
354 if self.image_creator2:
356 self.image_creator2.clean()
360 if self.keypair1_settings:
361 expanded_path = os.path.expanduser(
362 self.keypair1_settings.private_filepath)
363 os.chmod(expanded_path, 0o755)
364 os.remove(expanded_path)
366 if self.keypair2_settings:
367 expanded_path = os.path.expanduser(
368 self.keypair2_settings.private_filepath)
369 os.chmod(expanded_path, 0o755)
370 os.remove(expanded_path)
372 super(self.__class__, self).__clean__()
374 def test_get_settings_from_stack(self):
376 Tests that a heat template with floating IPs and can have the proper
377 settings derived from settings_utils.py.
379 resources = heat_utils.get_resources(self.heat_client, self.stack.id)
380 self.assertIsNotNone(resources)
381 self.assertEqual(12, len(resources))
383 options = heat_utils.get_outputs(self.heat_client, self.stack)
384 self.assertIsNotNone(options)
385 self.assertEqual(1, len(options))
387 neutron = neutron_utils.neutron_client(self.os_creds, self.os_session)
388 networks = heat_utils.get_stack_networks(
389 self.heat_client, neutron, self.stack)
390 self.assertIsNotNone(networks)
391 self.assertEqual(1, len(networks))
392 self.assertEqual(self.network_name, networks[0].name)
394 network_settings = settings_utils.create_network_config(
395 neutron, networks[0])
396 self.assertIsNotNone(network_settings)
397 self.assertEqual(self.network_name, network_settings.name)
399 nova = nova_utils.nova_client(self.os_creds, self.os_session)
400 glance = glance_utils.glance_client(self.os_creds, self.os_session)
401 keystone = keystone_utils.keystone_client(
402 self.os_creds, self.os_session)
403 servers = heat_utils.get_stack_servers(
404 self.heat_client, nova, neutron, keystone, self.stack,
405 self.os_creds.project_name)
406 self.assertIsNotNone(servers)
407 self.assertEqual(2, len(servers))
409 image_settings = settings_utils.determine_image_config(
411 [self.image_creator1.image_settings,
412 self.image_creator2.image_settings])
414 self.assertIsNotNone(image_settings)
415 if image_settings.name.endswith('1'):
417 self.image_creator1.image_settings.name, image_settings.name)
420 self.image_creator2.image_settings.name, image_settings.name)
422 image_settings = settings_utils.determine_image_config(
424 [self.image_creator1.image_settings,
425 self.image_creator2.image_settings])
426 if image_settings.name.endswith('1'):
428 self.image_creator1.image_settings.name, image_settings.name)
431 self.image_creator2.image_settings.name, image_settings.name)
433 self.keypair1_settings = settings_utils.determine_keypair_config(
434 self.heat_client, self.stack, servers[0],
435 priv_key_key='private_key')
436 self.assertIsNotNone(self.keypair1_settings)
437 self.assertEqual(self.keypair_name, self.keypair1_settings.name)
439 self.keypair2_settings = settings_utils.determine_keypair_config(
440 self.heat_client, self.stack, servers[1],
441 priv_key_key='private_key')
442 self.assertIsNotNone(self.keypair2_settings)
443 self.assertEqual(self.keypair_name, self.keypair2_settings.name)
446 class HeatUtilsRouterTests(OSComponentTestCase):
448 Test Heat volume functionality
453 Instantiates OpenStack instances that cannot be spawned by Heat
455 guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
456 stack_name = guid + '-stack'
458 self.net_name = guid + '-net'
459 self.subnet_name = guid + '-subnet'
460 self.router_name = guid + '-router'
463 'net_name': self.net_name,
464 'subnet_name': self.subnet_name,
465 'router_name': self.router_name,
466 'external_net_name': self.ext_net_name}
468 heat_tmplt_path = pkg_resources.resource_filename(
469 'snaps.openstack.tests.heat', 'router_heat_template.yaml')
470 self.stack_settings = StackConfig(
471 name=stack_name, template_path=heat_tmplt_path,
472 env_values=env_values)
474 self.heat_client = heat_utils.heat_client(
475 self.os_creds, self.os_session)
476 self.neutron = neutron_utils.neutron_client(
477 self.os_creds, self.os_session)
481 Cleans the image and downloaded image file
485 heat_utils.delete_stack(self.heat_client, self.stack)
489 super(self.__class__, self).__clean__()
491 def test_create_router_with_stack(self):
493 Tests the creation of an OpenStack router with Heat and the retrieval
494 of the Router Domain objects from heat_utils#get_stack_routers().
496 self.stack = heat_utils.create_stack(
497 self.heat_client, self.stack_settings)
499 # Wait until stack deployment has completed
500 end_time = time.time() + stack_config.STACK_COMPLETE_TIMEOUT
502 while time.time() < end_time:
503 status = heat_utils.get_stack_status(self.heat_client,
505 if status == stack_config.STATUS_CREATE_COMPLETE:
508 elif status == stack_config.STATUS_CREATE_FAILED:
514 self.assertTrue(is_active)
516 routers = heat_utils.get_stack_routers(
517 self.heat_client, self.neutron, self.stack)
519 self.assertEqual(1, len(routers))
522 self.assertEqual(self.router_name, router.name)
524 keystone = keystone_utils.keystone_client(
525 self.os_creds, self.os_session)
526 ext_net = neutron_utils.get_network(
527 self.neutron, keystone, network_name=self.ext_net_name)
528 self.assertEqual(ext_net.id, router.external_network_id)
531 class HeatUtilsVolumeTests(OSComponentTestCase):
533 Test Heat volume functionality
538 Instantiates OpenStack instances that cannot be spawned by Heat
540 guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
541 stack_name = guid + '-stack'
542 self.volume_name = guid + '-vol'
543 self.volume_type_name = guid + '-vol-type'
546 'volume_name': self.volume_name,
547 'volume_type_name': self.volume_type_name}
549 heat_tmplt_path = pkg_resources.resource_filename(
550 'snaps.openstack.tests.heat', 'volume_heat_template.yaml')
551 self.stack_settings = StackConfig(
552 name=stack_name, template_path=heat_tmplt_path,
553 env_values=env_values)
555 self.heat_client = heat_utils.heat_client(
556 self.os_creds, self.os_session)
557 self.cinder = cinder_utils.cinder_client(
558 self.os_creds, self.os_session)
566 heat_utils.delete_stack(self.heat_client, self.stack)
570 super(self.__class__, self).__clean__()
572 def test_create_vol_with_stack(self):
574 Tests the creation of an OpenStack volume with Heat.
576 self.stack = heat_utils.create_stack(
577 self.heat_client, self.stack_settings)
578 self.assertTrue(stack_active(self.heat_client, self.stack))
580 volumes = heat_utils.get_stack_volumes(
581 self.heat_client, self.cinder, self.stack)
583 self.assertEqual(1, len(volumes))
586 self.assertEqual(self.volume_name, volume.name)
587 self.assertEqual(self.volume_type_name, volume.type)
588 self.assertEqual(1, volume.size)
589 self.assertEqual(False, volume.multi_attach)
591 def test_create_vol_types_with_stack(self):
593 Tests the creation of an OpenStack volume with Heat.
595 self.stack = heat_utils.create_stack(
596 self.heat_client, self.stack_settings)
597 self.assertTrue(stack_active(self.heat_client, self.stack))
599 volume_types = heat_utils.get_stack_volume_types(
600 self.heat_client, self.cinder, self.stack)
602 self.assertEqual(1, len(volume_types))
604 volume_type = volume_types[0]
606 self.assertEqual(self.volume_type_name, volume_type.name)
607 self.assertTrue(volume_type.public)
608 self.assertIsNone(volume_type.qos_spec)
610 # TODO - Add encryption back and find out why it broke in Pike
611 # encryption = volume_type.encryption
612 # self.assertIsNotNone(encryption)
613 # self.assertIsNone(encryption.cipher)
614 # self.assertEqual('front-end', encryption.control_location)
615 # self.assertIsNone(encryption.key_size)
616 # self.assertEqual(u'nova.volume.encryptors.luks.LuksEncryptor',
617 # encryption.provider)
618 # self.assertEqual(volume_type.id, encryption.volume_type_id)
621 class HeatUtilsFlavorTests(OSComponentTestCase):
623 Test Heat volume functionality
628 Instantiates OpenStack instances that cannot be spawned by Heat
630 guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
631 self.name_prefix = guid
632 stack_name = guid + '-stack'
634 heat_tmplt_path = pkg_resources.resource_filename(
635 'snaps.openstack.tests.heat', 'flavor_heat_template.yaml')
636 self.stack_settings = StackConfig(
637 name=stack_name, template_path=heat_tmplt_path)
639 self.heat_client = heat_utils.heat_client(
640 self.os_creds, self.os_session)
641 self.nova = nova_utils.nova_client(
642 self.os_creds, self.os_session)
650 heat_utils.delete_stack(self.heat_client, self.stack)
654 super(self.__class__, self).__clean__()
656 def test_create_flavor_with_stack(self):
658 Tests the creation of an OpenStack volume with Heat.
660 self.stack = heat_utils.create_stack(
661 self.heat_client, self.stack_settings)
663 self.assertTrue(stack_active(self.heat_client, self.stack))
665 flavors = heat_utils.get_stack_flavors(
666 self.heat_client, self.nova, self.stack)
668 self.assertEqual(1, len(flavors))
671 self.assertTrue(flavor.name.startswith(self.name_prefix))
672 self.assertEqual(1024, flavor.ram)
673 self.assertEqual(200, flavor.disk)
674 self.assertEqual(8, flavor.vcpus)
675 self.assertEqual(0, flavor.ephemeral)
676 self.assertIsNone(flavor.swap)
677 self.assertEqual(1.0, flavor.rxtx_factor)
678 self.assertTrue(flavor.is_public)
681 class HeatUtilsKeypairTests(OSComponentTestCase):
683 Test Heat volume functionality
688 Instantiates OpenStack instances that cannot be spawned by Heat
690 guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
691 stack_name = guid + '-stack'
692 self.keypair_name = guid + '-kp'
694 env_values = {'keypair_name': self.keypair_name}
696 heat_tmplt_path = pkg_resources.resource_filename(
697 'snaps.openstack.tests.heat', 'keypair_heat_template.yaml')
698 self.stack_settings = StackConfig(
699 name=stack_name, template_path=heat_tmplt_path,
700 env_values=env_values)
702 self.heat_client = heat_utils.heat_client(
703 self.os_creds, self.os_session)
704 self.nova = nova_utils.nova_client(
705 self.os_creds, self.os_session)
713 heat_utils.delete_stack(self.heat_client, self.stack)
717 super(self.__class__, self).__clean__()
719 def test_create_keypair_with_stack(self):
721 Tests the creation of an OpenStack keypair with Heat.
723 self.stack = heat_utils.create_stack(
724 self.heat_client, self.stack_settings)
725 self.assertTrue(stack_active(self.heat_client, self.stack))
727 keypairs = heat_utils.get_stack_keypairs(
728 self.heat_client, self.nova, self.stack)
730 self.assertEqual(1, len(keypairs))
731 keypair = keypairs[0]
733 self.assertEqual(self.keypair_name, keypair.name)
735 outputs = heat_utils.get_outputs(self.heat_client, self.stack)
737 for output in outputs:
738 if output.key == 'private_key':
739 self.assertTrue(output.value.startswith(
740 '-----BEGIN RSA PRIVATE KEY-----'))
742 keypair = nova_utils.get_keypair_by_id(self.nova, keypair.id)
743 self.assertIsNotNone(keypair)
745 self.assertEqual(self.keypair_name, keypair.name)
748 class HeatUtilsSecurityGroupTests(OSComponentTestCase):
750 Test Heat volume functionality
755 Instantiates OpenStack instances that cannot be spawned by Heat
757 guid = self.__class__.__name__ + '-' + str(uuid.uuid4())
758 stack_name = guid + '-stack'
759 self.sec_grp_name = guid + '-sec-grp'
761 env_values = {'security_group_name': self.sec_grp_name}
763 heat_tmplt_path = pkg_resources.resource_filename(
764 'snaps.openstack.tests.heat', 'security_group_heat_template.yaml')
765 self.stack_settings = StackConfig(
766 name=stack_name, template_path=heat_tmplt_path,
767 env_values=env_values)
769 self.heat_client = heat_utils.heat_client(
770 self.os_creds, self.os_session)
771 self.neutron = neutron_utils.neutron_client(
772 self.os_creds, self.os_session)
780 heat_utils.delete_stack(self.heat_client, self.stack)
784 super(self.__class__, self).__clean__()
786 def test_create_security_group_with_stack(self):
788 Tests the creation of an OpenStack SecurityGroup with Heat.
790 self.stack = heat_utils.create_stack(
791 self.heat_client, self.stack_settings)
792 self.assertTrue(stack_active(self.heat_client, self.stack))
794 sec_grp = heat_utils.get_stack_security_groups(
795 self.heat_client, self.neutron, self.stack)[0]
797 self.assertEqual(self.sec_grp_name, sec_grp.name)
798 self.assertEqual('Test description', sec_grp.description)
799 self.assertEqual(2, len(sec_grp.rules))
802 has_icmp_rule = False
804 for rule in sec_grp.rules:
805 if (rule.security_group_id == sec_grp.id
806 and rule.direction == 'egress'
807 and rule.ethertype == 'IPv4'
808 and rule.port_range_min == 22
809 and rule.port_range_max == 22
810 and rule.protocol == 'tcp'
811 and rule.remote_group_id is None
812 and rule.remote_ip_prefix == '0.0.0.0/0'):
814 if (rule.security_group_id == sec_grp.id
815 and rule.direction == 'ingress'
816 and rule.ethertype == 'IPv4'
817 and rule.port_range_min is None
818 and rule.port_range_max is None
819 and rule.protocol == 'icmp'
820 and rule.remote_group_id is None
821 and rule.remote_ip_prefix == '0.0.0.0/0'):
824 self.assertTrue(has_ssh_rule)
825 self.assertTrue(has_icmp_rule)
828 def stack_active(heat_cli, stack):
830 Blocks until stack application has successfully completed or failed
831 :param heat_cli: the Heat client
832 :param stack: the Stack domain object
835 # Wait until stack deployment has completed
836 end_time = time.time() + stack_config.STACK_COMPLETE_TIMEOUT
838 while time.time() < end_time:
839 status = heat_utils.get_stack_status(heat_cli, stack.id)
840 if status == stack_config.STATUS_CREATE_COMPLETE:
843 elif status == stack_config.STATUS_CREATE_FAILED: