Add scenario test for fip port_details

Change-Id: I275da05d4dae1a1ce1dff7d63f3b58ff5916aac3
Related-Bug: #1723026
This commit is contained in:
Hongbin Lu 2018-04-25 22:32:30 +00:00
parent a1037291ac
commit 965b03dc12
4 changed files with 104 additions and 1 deletions

View File

@ -131,7 +131,7 @@
vars:
devstack_localrc:
Q_AGENT: linuxbridge
NETWORK_API_EXTENSIONS: "address-scope,agent,allowed-address-pairs,auto-allocated-topology,availability_zone,binding,default-subnetpools,dhcp_agent_scheduler,dns-domain-ports,dns-integration,ext-gw-mode,external-net,extra_dhcp_opt,extraroute,flavors,ip-substring-filtering,l3-flavors,l3-ha,l3_agent_scheduler,logging,metering,multi-provider,net-mtu,net-mtu-writable,network-ip-availability,network_availability_zone,pagination,port-security,project-id,provider,qos,qos-fip,quotas,quota_details,rbac-policies,router,router_availability_zone,security-group,port-security-groups-filtering,segment,service-type,sorting,standard-attr-description,standard-attr-revisions,standard-attr-timestamp,standard-attr-tag,subnet_allocation,tag,tag-ext,trunk,trunk-details"
NETWORK_API_EXTENSIONS: "address-scope,agent,allowed-address-pairs,auto-allocated-topology,availability_zone,binding,default-subnetpools,dhcp_agent_scheduler,dns-domain-ports,dns-integration,ext-gw-mode,external-net,extra_dhcp_opt,extraroute,fip-port-details,flavors,ip-substring-filtering,l3-flavors,l3-ha,l3_agent_scheduler,logging,metering,multi-provider,net-mtu,net-mtu-writable,network-ip-availability,network_availability_zone,pagination,port-security,project-id,provider,qos,qos-fip,quotas,quota_details,rbac-policies,router,router_availability_zone,security-group,port-security-groups-filtering,segment,service-type,sorting,standard-attr-description,standard-attr-revisions,standard-attr-timestamp,standard-attr-tag,subnet_allocation,tag,tag-ext,trunk,trunk-details"
devstack_local_conf:
post-config:
$NEUTRON_CONF:
@ -156,6 +156,8 @@
override-checkout: stable/queens
vars:
branch_override: stable/queens
devstack_localrc:
NETWORK_API_EXTENSIONS: "address-scope,agent,allowed-address-pairs,auto-allocated-topology,availability_zone,binding,default-subnetpools,dhcp_agent_scheduler,dns-integration,ext-gw-mode,external-net,extra_dhcp_opt,extraroute,flavors,ip-substring-filtering,l3-flavors,l3-ha,l3_agent_scheduler,logging,metering,multi-provider,net-mtu,net-mtu-writable,network-ip-availability,network_availability_zone,pagination,port-security,project-id,provider,qos,qos-fip,quotas,quota_details,rbac-policies,router,router_availability_zone,security-group,port-security-groups-filtering,segment,service-type,sorting,standard-attr-description,standard-attr-revisions,standard-attr-timestamp,standard-attr-tag,subnet_allocation,tag,tag-ext,trunk,trunk-details"
- job:
name: neutron-tempest-plugin-dvr-multinode-scenario

View File

@ -15,6 +15,7 @@
from tempest.lib.services.compute import availability_zone_client
from tempest.lib.services.compute import hypervisor_client
from tempest.lib.services.compute import interfaces_client
from tempest.lib.services.compute import keypairs_client
from tempest.lib.services.compute import servers_client
from tempest.lib.services.identity.v2 import tenants_client
@ -75,6 +76,8 @@ class Manager(manager.Manager):
enable_instance_password=CONF.compute_feature_enabled
.enable_instance_password,
**params)
self.interfaces_client = interfaces_client.InterfacesClient(
self.auth_provider, **params)
self.keypairs_client = keypairs_client.KeyPairsClient(
self.auth_provider, **params)
self.hv_client = hypervisor_client.HypervisorClient(

View File

@ -167,6 +167,15 @@ class BaseTempestTestCase(base_api.BaseNetworkTest):
self.floating_ips.append(fip)
return fip
def create_interface(cls, server_id, port_id, client=None):
client = client or cls.os_primary.interfaces_client
body = client.create_interface(server_id, port_id=port_id)
return body['interfaceAttachment']
def delete_interface(cls, server_id, port_id, client=None):
client = client or cls.os_primary.interfaces_client
client.delete_interface(server_id, port_id=port_id)
def setup_network_and_server(
self, router=None, server_name=None, **kwargs):
"""Create network resources and a server.

View File

@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
import time
from neutron_lib import constants as lib_constants
from neutron_lib.services.qos import constants as qos_consts
from tempest.common import utils
@ -26,6 +28,7 @@ from neutron_tempest_plugin.api import base as base_api
from neutron_tempest_plugin.common import ssh
from neutron_tempest_plugin.common import utils as common_utils
from neutron_tempest_plugin import config
from neutron_tempest_plugin import exceptions
from neutron_tempest_plugin.scenario import base
from neutron_tempest_plugin.scenario import constants
from neutron_tempest_plugin.scenario import test_qos
@ -199,6 +202,92 @@ class DefaultSnatToExternal(FloatingIpTestCasesMixin,
gateway_external_ip)
class FloatingIPPortDetailsTest(FloatingIpTestCasesMixin,
base.BaseTempestTestCase):
same_network = True
@classmethod
@utils.requires_ext(extension="router", service="network")
@utils.requires_ext(extension="fip-port-details", service="network")
def resource_setup(cls):
super(FloatingIPPortDetailsTest, cls).resource_setup()
@decorators.idempotent_id('a663aeee-dd81-492b-a207-354fd6284dbe')
def test_floatingip_port_details(self):
"""Tests the following:
1. Create a port with floating ip in Neutron.
2. Create two servers in Nova.
3. Attach the port to the server.
4. Detach the port from the server.
5. Attach the port to the second server.
6. Detach the port from the second server.
"""
port = self.create_port(self.network)
fip = self.create_and_associate_floatingip(port['id'])
server1 = self._create_server(create_floating_ip=False)
server2 = self._create_server(create_floating_ip=False)
for server in [server1, server2]:
# attach the port to the server
self.create_interface(
server['server']['id'], port_id=port['id'])
waiters.wait_for_interface_status(
self.os_primary.interfaces_client, server['server']['id'],
port['id'], 'ACTIVE')
fip = self.client.show_floatingip(fip['id'])['floatingip']
self._check_port_details(
fip, port, status='ACTIVE',
device_id=server['server']['id'], device_owner='compute:nova')
# 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.delete_interface(server['server']['id'], port['id'])
self._wait_for_port_detach(port['id'])
fip = self.client.show_floatingip(fip['id'])['floatingip']
self._check_port_details(
fip, port, status='DOWN', device_id='', device_owner='')
def _check_port_details(self, fip, port, status, device_id, device_owner):
self.assertIn('port_details', fip)
port_details = fip['port_details']
self.assertEqual(port['name'], port_details['name'])
self.assertEqual(port['network_id'], port_details['network_id'])
self.assertEqual(port['mac_address'], port_details['mac_address'])
self.assertEqual(port['admin_state_up'],
port_details['admin_state_up'])
self.assertEqual(status, port_details['status'])
self.assertEqual(device_id, port_details['device_id'])
self.assertEqual(device_owner, port_details['device_owner'])
def _wait_for_port_detach(self, port_id, timeout=120, interval=10):
"""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.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(interval)
port = self.client.show_port(port_id)['port']
device_id = port['device_id']
timed_out = int(time.time()) - start >= 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, timeout))
raise exceptions.TimeoutException(message)
return port
class FloatingIPQosTest(FloatingIpTestCasesMixin,
test_qos.QoSTest):