diff --git a/zaza/openstack/charm_tests/test_utils.py b/zaza/openstack/charm_tests/test_utils.py index 27926f8b6..dd353823d 100644 --- a/zaza/openstack/charm_tests/test_utils.py +++ b/zaza/openstack/charm_tests/test_utils.py @@ -616,7 +616,7 @@ def setUpClass(cls, application_name=None, model_alias=None): def resource_cleanup(self): """Remove test resources.""" try: - logging.info('Removing instances launched by test ({}*)' + logging.info('Removing resources created by test ({}*)' .format(self.RESOURCE_PREFIX)) for server in self.nova_client.servers.list(): if server.name.startswith(self.RESOURCE_PREFIX): @@ -624,6 +624,12 @@ def resource_cleanup(self): self.nova_client.servers, server.id, msg="server") + for server_group in self.nova_client.server_groups.list(): + if server_group.name.startswith(self.RESOURCE_PREFIX): + openstack_utils.delete_resource( + self.nova_client.server_groups, + server_group.id, + msg="server group") except AssertionError as e: # Resource failed to be removed within the expected time frame, # log this fact and carry on. @@ -634,7 +640,7 @@ def resource_cleanup(self): pass def launch_guest(self, guest_name, userdata=None, use_boot_volume=False, - instance_key=None): + instance_key=None, scheduler_hints=None): """Launch one guest to use in tests. Note that it is up to the caller to have set the RESOURCE_PREFIX class @@ -651,6 +657,9 @@ def launch_guest(self, guest_name, userdata=None, use_boot_volume=False, :type use_boot_volume: boolean :param instance_key: Key to collect associated config data with. :type instance_key: Optional[str] + :param scheduler_hints: arbitrary key-value pairs specified by the + client to help boot an instance. + :type scheduler_hints: Optional[Dict[str,str]] :returns: Nova instance objects :rtype: Server """ @@ -678,7 +687,8 @@ def launch_guest(self, guest_name, userdata=None, use_boot_volume=False, instance_key, vm_name=instance_name, use_boot_volume=use_boot_volume, - userdata=userdata) + userdata=userdata, + scheduler_hints=scheduler_hints) def launch_guests(self, userdata=None): """Launch two guests to use in tests. @@ -691,12 +701,16 @@ def launch_guests(self, userdata=None): :returns: List of launched Nova instance objects :rtype: List[Server] """ + server_group = configure_guest.create_server_group( + self.RESOURCE_PREFIX, policy='anti-affinity') + launched_instances = [] for guest_number in range(1, 2+1): launched_instances.append( self.launch_guest( guest_name='ins-{}'.format(guest_number), - userdata=userdata)) + userdata=userdata, + scheduler_hints={'group': server_group.id})) return launched_instances def retrieve_guest(self, guest_name): diff --git a/zaza/openstack/configure/guest.py b/zaza/openstack/configure/guest.py index d63938df6..f591dd422 100644 --- a/zaza/openstack/configure/guest.py +++ b/zaza/openstack/configure/guest.py @@ -45,10 +45,32 @@ 'bootstring': 'finished at'}} +def create_server_group(name, policy=None): + """Create a server group for influencing instance placement. + + :param name: Name of server group. + :type name: str + :param policy: Policy for group, one of ('affinity', 'anti-affinity', + 'soft-affinity', 'soft-anti-affinity'). Default: 'affinity' + :type policy: Optional[str] + :param rules + :returns: ServerGroup resource. + :rtype: novaclient.v2.server_groups.ServerGroup + :raises: ValueError + """ + if policy and policy not in ('affinity', 'anti-affinity', 'soft-affinity', + 'soft-anti-affinity'): + raise ValueError + + keystone_session = openstack_utils.get_overcloud_keystone_session() + nova_client = openstack_utils.get_nova_session_client(keystone_session) + return nova_client.server_groups.create(name, policy) + + def launch_instance(instance_key, use_boot_volume=False, vm_name=None, private_network_name=None, image_name=None, flavor_name=None, external_network_name=None, meta=None, - userdata=None): + userdata=None, scheduler_hints=None): """Launch an instance. :param instance_key: Key to collect associated config data with. @@ -71,6 +93,9 @@ def launch_instance(instance_key, use_boot_volume=False, vm_name=None, :type meta: dict :param userdata: Configuration to use upon launch, used by cloud-init. :type userdata: str + :param scheduler_hints: arbitrary key-value pairs specified by the client + to help boot an instance. + :type scheduler_hints: Optional[Dict[str,str]] :returns: the created instance :rtype: novaclient.Server """ @@ -117,7 +142,8 @@ def launch_instance(instance_key, use_boot_volume=False, vm_name=None, key_name=nova_utils.KEYPAIR_NAME, meta=meta, nics=nics, - userdata=userdata) + userdata=userdata, + scheduler_hints=scheduler_hints) # Test Instance is ready. logging.info('Checking instance is active')