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
This commit is contained in:
Ghanshyam Mann 2021-03-24 18:48:38 -05:00 committed by Ghanshyam
parent f0a2967f3d
commit 6428139de1
4 changed files with 109 additions and 124 deletions

View File

@ -47,7 +47,7 @@ LATEST_MICROVERSION = 'latest'
class ScenarioTest(tempest.test.BaseTestCase): class ScenarioTest(tempest.test.BaseTestCase):
"""Base class for scenario tests. Uses tempest own clients. """ """Base class for scenario tests. Uses tempest own clients. """
credentials = ['primary'] credentials = ['primary', 'admin']
compute_min_microversion = None compute_min_microversion = None
compute_max_microversion = LATEST_MICROVERSION compute_max_microversion = LATEST_MICROVERSION
@ -115,8 +115,6 @@ class ScenarioTest(tempest.test.BaseTestCase):
"""This setup the service clients for the tests""" """This setup the service clients for the tests"""
super(ScenarioTest, cls).setup_clients() super(ScenarioTest, cls).setup_clients()
cls.flavors_client = cls.os_primary.flavors_client 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: if CONF.service_available.glance:
# Check if glance v1 is available to determine which client to use. # Check if glance v1 is available to determine which client to use.
if CONF.image_feature_enabled.api_v1: if CONF.image_feature_enabled.api_v1:
@ -962,20 +960,98 @@ class ScenarioTest(tempest.test.BaseTestCase):
LOG.exception(extra_msg) LOG.exception(extra_msg)
raise raise
def create_floating_ip(self, server, pool_name=None, **kwargs): def get_server_port_id_and_ip4(self, server, ip_addr=None, **kwargs):
"""Create a floating IP and associates to a server on Nova"""
if not pool_name: if ip_addr and not kwargs.get('fixed_ips'):
pool_name = CONF.network.floating_network_name 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.addCleanup(test_utils.call_and_ignore_notfound_exc,
self.compute_floating_ips_client.delete_floating_ip, client.delete_floatingip,
floating_ip['id']) floating_ip['id'])
self.compute_floating_ips_client.associate_floating_ip_to_server( return floating_ip
floating_ip['ip'], server['id'])
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 return floating_ip
def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt', 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 # The tests calling this method don't have a floating IP
# and can't make use of the validation resources. So the # and can't make use of the validation resources. So the
# method is creating the floating IP there. # 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': elif CONF.validation.connect_method == 'fixed':
# Determine the network name to look for based on config or creds # Determine the network name to look for based on config or creds
# provider network resources. # provider network resources.
@ -1138,8 +1215,6 @@ class NetworkScenarioTest(ScenarioTest):
""" """
credentials = ['primary', 'admin']
@classmethod @classmethod
def skip_checks(cls): def skip_checks(cls):
super(NetworkScenarioTest, cls).skip_checks() super(NetworkScenarioTest, cls).skip_checks()
@ -1274,43 +1349,6 @@ class NetworkScenarioTest(ScenarioTest):
return subnet 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): def get_network_by_name(self, network_name):
net = self.os_admin.networks_client.list_networks( net = self.os_admin.networks_client.list_networks(
name=network_name)['networks'] name=network_name)['networks']
@ -1318,63 +1356,6 @@ class NetworkScenarioTest(ScenarioTest):
"Unable to get network by name: %s" % network_name) "Unable to get network by name: %s" % network_name)
return net[0] 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): def check_floating_ip_status(self, floating_ip, status):
"""Verifies floatingip reaches the given status """Verifies floatingip reaches the given status
@ -1575,8 +1556,6 @@ class NetworkScenarioTest(ScenarioTest):
class EncryptionScenarioTest(ScenarioTest): class EncryptionScenarioTest(ScenarioTest):
"""Base class for encryption scenario tests""" """Base class for encryption scenario tests"""
credentials = ['primary', 'admin']
@classmethod @classmethod
def setup_clients(cls): def setup_clients(cls):
super(EncryptionScenarioTest, cls).setup_clients() super(EncryptionScenarioTest, cls).setup_clients()
@ -1618,6 +1597,8 @@ class ObjectStorageScenarioTest(ScenarioTest):
class. class.
""" """
credentials = ['primary']
@classmethod @classmethod
def skip_checks(cls): def skip_checks(cls):
super(ObjectStorageScenarioTest, cls).skip_checks() super(ObjectStorageScenarioTest, cls).skip_checks()

View File

@ -100,7 +100,7 @@ class TestMinimumBasicScenario(manager.ScenarioTest):
for addresses in server['addresses'].values(): for addresses in server['addresses'].values():
for address in addresses: for address in addresses:
if (address['OS-EXT-IPS:type'] == 'floating' and if (address['OS-EXT-IPS:type'] == 'floating' and
address['addr'] == floating_ip['ip']): address['addr'] == floating_ip['floating_ip_address']):
return address return address
@decorators.idempotent_id('bdbb5441-9204-419d-a225-b4fdbfb1a1a8') @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'] server = self.servers_client.show_server(server['id'])['server']
if (CONF.network_feature_enabled.floating_ips and if (CONF.network_feature_enabled.floating_ips and
CONF.network.floating_network_name): 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 # fetch the server again to make sure the addresses were refreshed
# after associating the floating IP # after associating the floating IP
server = self.servers_client.show_server(server['id'])['server'] server = self.servers_client.show_server(server['id'])['server']
@ -138,8 +140,8 @@ class TestMinimumBasicScenario(manager.ScenarioTest):
self.assertIsNotNone( self.assertIsNotNone(
address, address,
"Failed to find floating IP '%s' in server addresses: %s" % "Failed to find floating IP '%s' in server addresses: %s" %
(floating_ip['ip'], server['addresses'])) (floating_ip['floating_ip_address'], server['addresses']))
ssh_ip = floating_ip['ip'] ssh_ip = floating_ip['floating_ip_address']
else: else:
ssh_ip = self.get_server_ip(server) ssh_ip = self.get_server_ip(server)
@ -162,8 +164,7 @@ class TestMinimumBasicScenario(manager.ScenarioTest):
if floating_ip: if floating_ip:
# delete the floating IP, this should refresh the server addresses # delete the floating IP, this should refresh the server addresses
self.compute_floating_ips_client.delete_floating_ip( self.disassociate_floating_ip(floating_ip)
floating_ip['id'])
def is_floating_ip_detached_from_server(): def is_floating_ip_detached_from_server():
server_info = self.servers_client.show_server( server_info = self.servers_client.show_server(
@ -177,5 +178,6 @@ class TestMinimumBasicScenario(manager.ScenarioTest):
CONF.compute.build_timeout, CONF.compute.build_timeout,
CONF.compute.build_interval): CONF.compute.build_interval):
msg = ("Floating IP '%s' should not be in server addresses: %s" 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) raise exceptions.TimeoutException(msg)

View File

@ -52,7 +52,9 @@ class TestServerBasicOps(manager.ScenarioTest):
# Obtain a floating IP if floating_ips is enabled # Obtain a floating IP if floating_ips is enabled
if (CONF.network_feature_enabled.floating_ips and if (CONF.network_feature_enabled.floating_ips and
CONF.network.floating_network_name): 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: else:
server = self.servers_client.show_server( server = self.servers_client.show_server(
self.instance['id'])['server'] self.instance['id'])['server']

View File

@ -84,11 +84,11 @@ class TestVolumeBackupRestore(manager.ScenarioTest):
security_groups=[ security_groups=[
{'name': security_group['name']}]) {'name': security_group['name']}])
# Create a floating ip # Create a floating ip and associate it to server.
floating_ip = self.create_floating_ip(server) fip = self.create_floating_ip(server)
floating_ip = self.associate_floating_ip(fip, server)
# Check server connectivity # 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, username=CONF.validation.image_ssh_user,
private_key=keypair['private_key'], private_key=keypair['private_key'],
should_connect=True) should_connect=True)