Add a test for attach/detach port on multiple servers
A regression was introduced in nova in newton when you attach the same port across multiple instances (not at the same time). The problem was nova started creating some internal resources on attach but wasn't cleaning them up on detach, so when you'd tried to attach the same port to a second server it would fail because of a unique constraint on the internal resource that nova creates. We should have an integration test that covers this scenario so we don't regress it again. This change covers both booting servers with a pre-created port and attaching a pre-created port to existing servers. Depends-On: I2254bad0df3ccc00cd5c9438fa2684e705442e2d Change-Id: I469b8ec426bd71dea515e99f76d415c62fff7dd3 Related-Bug: #1602357
This commit is contained in:
parent
ad37b61be6
commit
a8c641a96e
@ -16,7 +16,9 @@
|
||||
import time
|
||||
|
||||
from tempest.api.compute import base
|
||||
from tempest.common import compute
|
||||
from tempest.common.utils import net_utils
|
||||
from tempest.common import waiters
|
||||
from tempest import config
|
||||
from tempest import exceptions
|
||||
from tempest.lib import exceptions as lib_exc
|
||||
@ -48,6 +50,7 @@ class AttachInterfacesTestJSON(base.BaseV2ComputeTest):
|
||||
cls.networks_client = cls.os.networks_client
|
||||
cls.subnets_client = cls.os.subnets_client
|
||||
cls.ports_client = cls.os.ports_client
|
||||
cls.servers_client = cls.servers_client
|
||||
|
||||
def wait_for_interface_status(self, server, port_id, status):
|
||||
"""Waits for an interface to reach a given status."""
|
||||
@ -73,6 +76,34 @@ class AttachInterfacesTestJSON(base.BaseV2ComputeTest):
|
||||
|
||||
return body
|
||||
|
||||
# TODO(mriedem): move this into a common waiters utility module
|
||||
def wait_for_port_detach(self, port_id):
|
||||
"""Waits for the port's device_id to be unset.
|
||||
|
||||
:param port_id: The id of the port being detached.
|
||||
:returns: The final port dict from the show_port response.
|
||||
"""
|
||||
port = self.ports_client.show_port(port_id)['port']
|
||||
device_id = port['device_id']
|
||||
start = int(time.time())
|
||||
|
||||
# NOTE(mriedem): Nova updates the port's device_id to '' rather than
|
||||
# None, but it's not contractual so handle Falsey either way.
|
||||
while device_id:
|
||||
time.sleep(self.build_interval)
|
||||
port = self.ports_client.show_port(port_id)['port']
|
||||
device_id = port['device_id']
|
||||
|
||||
timed_out = int(time.time()) - start >= self.build_timeout
|
||||
|
||||
if device_id and timed_out:
|
||||
message = ('Port %s failed to detach (device_id %s) within '
|
||||
'the required time (%s s).' %
|
||||
(port_id, device_id, self.build_timeout))
|
||||
raise exceptions.TimeoutException(message)
|
||||
|
||||
return port
|
||||
|
||||
def _check_interface(self, iface, port_id=None, network_id=None,
|
||||
fixed_ip=None, mac_addr=None):
|
||||
self.assertIn('port_state', iface)
|
||||
@ -240,3 +271,40 @@ class AttachInterfacesTestJSON(base.BaseV2ComputeTest):
|
||||
if fixed_ip is not None:
|
||||
break
|
||||
self.servers_client.remove_fixed_ip(server['id'], address=fixed_ip)
|
||||
|
||||
@test.idempotent_id('2f3a0127-95c7-4977-92d2-bc5aec602fb4')
|
||||
def test_reassign_port_between_servers(self):
|
||||
"""Tests the following:
|
||||
|
||||
1. Create a port in Neutron.
|
||||
2. Create two servers in Nova.
|
||||
3. Attach the port to the first server.
|
||||
4. Detach the port from the first server.
|
||||
5. Attach the port to the second server.
|
||||
6. Detach the port from the second server.
|
||||
"""
|
||||
network = self.get_tenant_network()
|
||||
network_id = network['id']
|
||||
port = self.ports_client.create_port(network_id=network_id)
|
||||
port_id = port['port']['id']
|
||||
self.addCleanup(self.ports_client.delete_port, port_id)
|
||||
|
||||
# create two servers
|
||||
_, servers = compute.create_test_server(
|
||||
self.os, tenant_network=network, wait_until='ACTIVE', min_count=2)
|
||||
# add our cleanups for the servers since we bypassed the base class
|
||||
for server in servers:
|
||||
self.addCleanup(waiters.wait_for_server_termination,
|
||||
self.servers_client, server['id'])
|
||||
self.addCleanup(self.servers_client.delete_server, server['id'])
|
||||
|
||||
for server in servers:
|
||||
# attach the port to the server
|
||||
iface = self.client.create_interface(
|
||||
server['id'], port_id=port_id)['interfaceAttachment']
|
||||
self._check_interface(iface, port_id=port_id)
|
||||
|
||||
# detach the port from the server; this is a cast in the compute
|
||||
# API so we have to poll the port until the device_id is unset.
|
||||
self.client.delete_interface(server['id'], port_id)
|
||||
self.wait_for_port_detach(port_id)
|
||||
|
@ -642,6 +642,8 @@ class TestNetworkBasicOps(manager.NetworkScenarioTest):
|
||||
|
||||
Nova should unbind the port from the instance on delete if the port was
|
||||
not created by Nova as part of the boot request.
|
||||
|
||||
We should also be able to boot another server with the same port.
|
||||
"""
|
||||
# Setup the network, create a port and boot the server from that port.
|
||||
self._setup_network_and_servers(boot_with_port=True)
|
||||
@ -670,6 +672,17 @@ class TestNetworkBasicOps(manager.NetworkScenarioTest):
|
||||
self.assertEqual('', port['device_id'])
|
||||
self.assertEqual('', port['device_owner'])
|
||||
|
||||
# Boot another server with the same port to make sure nothing was
|
||||
# left around that could cause issues.
|
||||
name = data_utils.rand_name('reuse-port')
|
||||
server = self._create_server(name, self.network, port['id'])
|
||||
port_list = self._list_ports(device_id=server['id'],
|
||||
network_id=self.network['id'])
|
||||
self.assertEqual(1, len(port_list),
|
||||
'There should only be one port created for '
|
||||
'server %s.' % server['id'])
|
||||
self.assertEqual(port['id'], port_list[0]['id'])
|
||||
|
||||
@test.requires_ext(service='network', extension='l3_agent_scheduler')
|
||||
@test.idempotent_id('2e788c46-fb3f-4ac9-8f82-0561555bea73')
|
||||
@test.services('compute', 'network')
|
||||
|
Loading…
Reference in New Issue
Block a user