From 6428139de18291c916852ae48130fb8a7b4db318 Mon Sep 17 00:00:00 2001 From: Ghanshyam Mann Date: Wed, 24 Mar 2021 18:48:38 -0500 Subject: [PATCH] Move floating IP operation from nova-network to neutron nova-network is no more available in nova and all network request needs to move to neutron. Scenario tests are something we should be testing with the latest interface not the deprecated one so we can remove the nova netowrk specific service clients and methods. This commit moves the floating ip operation from nova-network to neutron. nova network create_floating_ip used to associate the FIP to server also so with neutron create floating ip we need to associate the FIP to server in separate method. Implements: blueprint tempest-scenario-manager-stable Change-Id: I6ad260731eedc2e1f56fe67b3a9e19fed8d4a38e --- tempest/scenario/manager.py | 205 ++++++++---------- tempest/scenario/test_minimum_basic.py | 16 +- tempest/scenario/test_server_basic_ops.py | 4 +- .../scenario/test_volume_backup_restore.py | 8 +- 4 files changed, 109 insertions(+), 124 deletions(-) diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py index 5188191cc7..fc0a7307a5 100644 --- a/tempest/scenario/manager.py +++ b/tempest/scenario/manager.py @@ -47,7 +47,7 @@ LATEST_MICROVERSION = 'latest' class ScenarioTest(tempest.test.BaseTestCase): """Base class for scenario tests. Uses tempest own clients. """ - credentials = ['primary'] + credentials = ['primary', 'admin'] compute_min_microversion = None compute_max_microversion = LATEST_MICROVERSION @@ -115,8 +115,6 @@ class ScenarioTest(tempest.test.BaseTestCase): """This setup the service clients for the tests""" super(ScenarioTest, cls).setup_clients() cls.flavors_client = cls.os_primary.flavors_client - cls.compute_floating_ips_client = ( - cls.os_primary.compute_floating_ips_client) if CONF.service_available.glance: # Check if glance v1 is available to determine which client to use. if CONF.image_feature_enabled.api_v1: @@ -962,20 +960,98 @@ class ScenarioTest(tempest.test.BaseTestCase): LOG.exception(extra_msg) raise - def create_floating_ip(self, server, pool_name=None, **kwargs): - """Create a floating IP and associates to a server on Nova""" + def get_server_port_id_and_ip4(self, server, ip_addr=None, **kwargs): - if not pool_name: - pool_name = CONF.network.floating_network_name + if ip_addr and not kwargs.get('fixed_ips'): + kwargs['fixed_ips'] = 'ip_address=%s' % ip_addr + ports = self.os_admin.ports_client.list_ports( + device_id=server['id'], **kwargs)['ports'] + + # A port can have more than one IP address in some cases. + # If the network is dual-stack (IPv4 + IPv6), this port is associated + # with 2 subnets + + def _is_active(port): + # NOTE(vsaienko) With Ironic, instances live on separate hardware + # servers. Neutron does not bind ports for Ironic instances, as a + # result the port remains in the DOWN state. This has been fixed + # with the introduction of the networking-baremetal plugin but + # it's not mandatory (and is not used on all stable branches). + return (port['status'] == 'ACTIVE' or + port.get('binding:vnic_type') == 'baremetal') + + port_map = [(p["id"], fxip["ip_address"]) + for p in ports + for fxip in p["fixed_ips"] + if (netutils.is_valid_ipv4(fxip["ip_address"]) and + _is_active(p))] + inactive = [p for p in ports if p['status'] != 'ACTIVE'] + if inactive: + LOG.warning("Instance has ports that are not ACTIVE: %s", inactive) + + self.assertNotEmpty(port_map, + "No IPv4 addresses found in: %s" % ports) + self.assertEqual(len(port_map), 1, + "Found multiple IPv4 addresses: %s. " + "Unable to determine which port to target." + % port_map) + return port_map[0] + + def create_floating_ip(self, server, external_network_id=None, + port_id=None, client=None, **kwargs): + """Create a floating IP and associates to a resource/port on Neutron""" + + if not external_network_id: + external_network_id = CONF.network.public_network_id + if not client: + client = self.floating_ips_client + if not port_id: + port_id, ip4 = self.get_server_port_id_and_ip4(server) + else: + ip4 = None + + floatingip_kwargs = { + 'floating_network_id': external_network_id, + 'port_id': port_id, + 'tenant_id': server.get('project_id') or server['tenant_id'], + 'fixed_ip_address': ip4, + } + if CONF.network.subnet_id: + floatingip_kwargs['subnet_id'] = CONF.network.subnet_id + + floatingip_kwargs.update(kwargs) + result = client.create_floatingip(**floatingip_kwargs) + floating_ip = result['floatingip'] - floating_ip = (self.compute_floating_ips_client. - create_floating_ip(pool=pool_name, - **kwargs)['floating_ip']) self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.compute_floating_ips_client.delete_floating_ip, + client.delete_floatingip, floating_ip['id']) - self.compute_floating_ips_client.associate_floating_ip_to_server( - floating_ip['ip'], server['id']) + return floating_ip + + def associate_floating_ip(self, floating_ip, server): + """Associate floating ip to server + + This wrapper utility attaches the floating_ip for + the respective port_id of server + """ + port_id, _ = self.get_server_port_id_and_ip4(server) + kwargs = dict(port_id=port_id) + floating_ip = self.floating_ips_client.update_floatingip( + floating_ip['id'], **kwargs)['floatingip'] + self.assertEqual(port_id, floating_ip['port_id']) + return floating_ip + + def disassociate_floating_ip(self, floating_ip): + """Disassociates floating ip + + This wrapper utility disassociates given floating ip. + :param floating_ip: a dict which is a return value of + floating_ips_client.create_floatingip method + """ + kwargs = dict(port_id=None) + floating_ip = self.floating_ips_client.update_floatingip( + floating_ip['id'], **kwargs)['floatingip'] + self.assertIsNone(floating_ip['port_id']) return floating_ip def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt', @@ -1046,7 +1122,8 @@ class ScenarioTest(tempest.test.BaseTestCase): # The tests calling this method don't have a floating IP # and can't make use of the validation resources. So the # method is creating the floating IP there. - return self.create_floating_ip(server, **kwargs)['ip'] + return self.create_floating_ip( + server, **kwargs)['floating_ip_address'] elif CONF.validation.connect_method == 'fixed': # Determine the network name to look for based on config or creds # provider network resources. @@ -1138,8 +1215,6 @@ class NetworkScenarioTest(ScenarioTest): """ - credentials = ['primary', 'admin'] - @classmethod def skip_checks(cls): super(NetworkScenarioTest, cls).skip_checks() @@ -1274,43 +1349,6 @@ class NetworkScenarioTest(ScenarioTest): return subnet - def get_server_port_id_and_ip4(self, server, ip_addr=None, **kwargs): - - if ip_addr and not kwargs.get('fixed_ips'): - kwargs['fixed_ips'] = 'ip_address=%s' % ip_addr - ports = self.os_admin.ports_client.list_ports( - device_id=server['id'], **kwargs)['ports'] - - # A port can have more than one IP address in some cases. - # If the network is dual-stack (IPv4 + IPv6), this port is associated - # with 2 subnets - - def _is_active(port): - # NOTE(vsaienko) With Ironic, instances live on separate hardware - # servers. Neutron does not bind ports for Ironic instances, as a - # result the port remains in the DOWN state. This has been fixed - # with the introduction of the networking-baremetal plugin but - # it's not mandatory (and is not used on all stable branches). - return (port['status'] == 'ACTIVE' or - port.get('binding:vnic_type') == 'baremetal') - - port_map = [(p["id"], fxip["ip_address"]) - for p in ports - for fxip in p["fixed_ips"] - if (netutils.is_valid_ipv4(fxip["ip_address"]) and - _is_active(p))] - inactive = [p for p in ports if p['status'] != 'ACTIVE'] - if inactive: - LOG.warning("Instance has ports that are not ACTIVE: %s", inactive) - - self.assertNotEmpty(port_map, - "No IPv4 addresses found in: %s" % ports) - self.assertEqual(len(port_map), 1, - "Found multiple IPv4 addresses: %s. " - "Unable to determine which port to target." - % port_map) - return port_map[0] - def get_network_by_name(self, network_name): net = self.os_admin.networks_client.list_networks( name=network_name)['networks'] @@ -1318,63 +1356,6 @@ class NetworkScenarioTest(ScenarioTest): "Unable to get network by name: %s" % network_name) return net[0] - def create_floating_ip(self, server, external_network_id=None, - port_id=None, client=None, **kwargs): - """Create a floating IP and associates to a resource/port on Neutron""" - - if not external_network_id: - external_network_id = CONF.network.public_network_id - if not client: - client = self.floating_ips_client - if not port_id: - port_id, ip4 = self.get_server_port_id_and_ip4(server) - else: - ip4 = None - - floatingip_kwargs = { - 'floating_network_id': external_network_id, - 'port_id': port_id, - 'tenant_id': server.get('project_id') or server['tenant_id'], - 'fixed_ip_address': ip4, - } - if CONF.network.subnet_id: - floatingip_kwargs['subnet_id'] = CONF.network.subnet_id - - floatingip_kwargs.update(kwargs) - result = client.create_floatingip(**floatingip_kwargs) - floating_ip = result['floatingip'] - - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - client.delete_floatingip, - floating_ip['id']) - return floating_ip - - def associate_floating_ip(self, floating_ip, server): - """Associate floating ip - - This wrapper utility attaches the floating_ip for - the respective port_id of server - """ - port_id, _ = self.get_server_port_id_and_ip4(server) - kwargs = dict(port_id=port_id) - floating_ip = self.floating_ips_client.update_floatingip( - floating_ip['id'], **kwargs)['floatingip'] - self.assertEqual(port_id, floating_ip['port_id']) - return floating_ip - - def disassociate_floating_ip(self, floating_ip): - """Disassociates floating ip - - This wrapper utility disassociates given floating ip. - :param floating_ip: a dict which is a return value of - floating_ips_client.create_floatingip method - """ - kwargs = dict(port_id=None) - floating_ip = self.floating_ips_client.update_floatingip( - floating_ip['id'], **kwargs)['floatingip'] - self.assertIsNone(floating_ip['port_id']) - return floating_ip - def check_floating_ip_status(self, floating_ip, status): """Verifies floatingip reaches the given status @@ -1575,8 +1556,6 @@ class NetworkScenarioTest(ScenarioTest): class EncryptionScenarioTest(ScenarioTest): """Base class for encryption scenario tests""" - credentials = ['primary', 'admin'] - @classmethod def setup_clients(cls): super(EncryptionScenarioTest, cls).setup_clients() @@ -1618,6 +1597,8 @@ class ObjectStorageScenarioTest(ScenarioTest): class. """ + credentials = ['primary'] + @classmethod def skip_checks(cls): super(ObjectStorageScenarioTest, cls).skip_checks() diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py index 5201315672..2c981c8777 100644 --- a/tempest/scenario/test_minimum_basic.py +++ b/tempest/scenario/test_minimum_basic.py @@ -100,7 +100,7 @@ class TestMinimumBasicScenario(manager.ScenarioTest): for addresses in server['addresses'].values(): for address in addresses: if (address['OS-EXT-IPS:type'] == 'floating' and - address['addr'] == floating_ip['ip']): + address['addr'] == floating_ip['floating_ip_address']): return address @decorators.idempotent_id('bdbb5441-9204-419d-a225-b4fdbfb1a1a8') @@ -129,7 +129,9 @@ class TestMinimumBasicScenario(manager.ScenarioTest): server = self.servers_client.show_server(server['id'])['server'] if (CONF.network_feature_enabled.floating_ips and CONF.network.floating_network_name): - floating_ip = self.create_floating_ip(server) + fip = self.create_floating_ip(server) + floating_ip = self.associate_floating_ip( + fip, server) # fetch the server again to make sure the addresses were refreshed # after associating the floating IP server = self.servers_client.show_server(server['id'])['server'] @@ -138,8 +140,8 @@ class TestMinimumBasicScenario(manager.ScenarioTest): self.assertIsNotNone( address, "Failed to find floating IP '%s' in server addresses: %s" % - (floating_ip['ip'], server['addresses'])) - ssh_ip = floating_ip['ip'] + (floating_ip['floating_ip_address'], server['addresses'])) + ssh_ip = floating_ip['floating_ip_address'] else: ssh_ip = self.get_server_ip(server) @@ -162,8 +164,7 @@ class TestMinimumBasicScenario(manager.ScenarioTest): if floating_ip: # delete the floating IP, this should refresh the server addresses - self.compute_floating_ips_client.delete_floating_ip( - floating_ip['id']) + self.disassociate_floating_ip(floating_ip) def is_floating_ip_detached_from_server(): server_info = self.servers_client.show_server( @@ -177,5 +178,6 @@ class TestMinimumBasicScenario(manager.ScenarioTest): CONF.compute.build_timeout, CONF.compute.build_interval): msg = ("Floating IP '%s' should not be in server addresses: %s" - % (floating_ip['ip'], server['addresses'])) + % (floating_ip['floating_ip_address'], + server['addresses'])) raise exceptions.TimeoutException(msg) diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py index 4c82d84c88..2a15470ad0 100644 --- a/tempest/scenario/test_server_basic_ops.py +++ b/tempest/scenario/test_server_basic_ops.py @@ -52,7 +52,9 @@ class TestServerBasicOps(manager.ScenarioTest): # Obtain a floating IP if floating_ips is enabled if (CONF.network_feature_enabled.floating_ips and CONF.network.floating_network_name): - self.ip = self.create_floating_ip(self.instance)['ip'] + fip = self.create_floating_ip(self.instance) + self.ip = self.associate_floating_ip( + fip, self.instance)['floating_ip_address'] else: server = self.servers_client.show_server( self.instance['id'])['server'] diff --git a/tempest/scenario/test_volume_backup_restore.py b/tempest/scenario/test_volume_backup_restore.py index 71e6b537ba..d0885cfa18 100644 --- a/tempest/scenario/test_volume_backup_restore.py +++ b/tempest/scenario/test_volume_backup_restore.py @@ -84,11 +84,11 @@ class TestVolumeBackupRestore(manager.ScenarioTest): security_groups=[ {'name': security_group['name']}]) - # Create a floating ip - floating_ip = self.create_floating_ip(server) - + # Create a floating ip and associate it to server. + fip = self.create_floating_ip(server) + floating_ip = self.associate_floating_ip(fip, server) # Check server connectivity - self.check_vm_connectivity(floating_ip['ip'], + self.check_vm_connectivity(floating_ip['floating_ip_address'], username=CONF.validation.image_ssh_user, private_key=keypair['private_key'], should_connect=True)