Add live migration with trunk test

Change-Id: I2d75fae81145b4bd1c0d38fabd785bc26835be15
Related-Bug: #1914747
Depends-On: https://review.opendev.org/c/openstack/neutron/+/774245
Depends-On: https://review.opendev.org/c/openstack/nova/+/775838
This commit is contained in:
elajkat 2021-02-08 16:43:59 +01:00 committed by Lajos Katona
parent ef55216ca1
commit 0b14db2a4c
6 changed files with 391 additions and 1 deletions

View File

@ -23,6 +23,8 @@ from tempest.common import compute
from tempest.common import utils
from tempest.common import waiters
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib.common.utils import test_utils
from tempest.lib import decorators
CONF = config.CONF
@ -55,6 +57,10 @@ class LiveMigrationTestBase(base.BaseV2ComputeAdminTest):
def setup_clients(cls):
super(LiveMigrationTestBase, cls).setup_clients()
cls.admin_migration_client = cls.os_admin.migrations_client
cls.networks_client = cls.os_primary.networks_client
cls.subnets_client = cls.os_primary.subnets_client
cls.ports_client = cls.os_primary.ports_client
cls.trunks_client = cls.os_primary.trunks_client
def _migrate_server_to(self, server_id, dest_host, volume_backed=False):
kwargs = dict()
@ -197,6 +203,86 @@ class LiveMigrationTest(LiveMigrationTestBase):
self.assertEqual(volume_id1, volume_id2)
def _create_net_subnet(self, name, cidr):
net_name = data_utils.rand_name(name=name)
net = self.networks_client.create_network(name=net_name)['network']
self.addClassResourceCleanup(
self.networks_client.delete_network, net['id'])
subnet = self.subnets_client.create_subnet(
network_id=net['id'],
cidr=cidr,
ip_version=4)
self.addClassResourceCleanup(self.subnets_client.delete_subnet,
subnet['subnet']['id'])
return net
def _create_port(self, network_id, name):
name = data_utils.rand_name(name=name)
port = self.ports_client.create_port(name=name,
network_id=network_id)['port']
self.addClassResourceCleanup(test_utils.call_and_ignore_notfound_exc,
self.ports_client.delete_port,
port_id=port['id'])
return port
def _create_trunk_with_subport(self):
tenant_network = self.get_tenant_network()
parent = self._create_port(network_id=tenant_network['id'],
name='parent')
net = self._create_net_subnet(name='subport_net', cidr='19.80.0.0/24')
subport = self._create_port(network_id=net['id'], name='subport')
trunk = self.trunks_client.create_trunk(
name=data_utils.rand_name('trunk'),
port_id=parent['id'],
sub_ports=[{"segmentation_id": 42, "port_id": subport['id'],
"segmentation_type": "vlan"}]
)['trunk']
self.addClassResourceCleanup(test_utils.call_and_ignore_notfound_exc,
self.trunks_client.delete_trunk,
trunk['id'])
return trunk, parent, subport
def _is_port_status_active(self, port_id):
port = self.ports_client.show_port(port_id)['port']
return port['status'] == 'ACTIVE'
@decorators.idempotent_id('0022c12e-a482-42b0-be2d-396b5f0cffe3')
@utils.requires_ext(service='network', extension='trunk')
@utils.services('network')
def test_live_migration_with_trunk(self):
"""Test live migration with trunk and subport"""
trunk, parent, subport = self._create_trunk_with_subport()
server = self.create_test_server(
wait_until="ACTIVE", networks=[{'port': parent['id']}])
# Wait till subport status is ACTIVE
self.assertTrue(
test_utils.call_until_true(
self._is_port_status_active, CONF.validation.connect_timeout,
5, subport['id']))
parent = self.ports_client.show_port(parent['id'])['port']
self.assertEqual('ACTIVE', parent['status'])
subport = self.ports_client.show_port(subport['id'])['port']
if not CONF.compute_feature_enabled.can_migrate_between_any_hosts:
# not to specify a host so that the scheduler will pick one
target_host = None
else:
target_host = self.get_host_other_than(server['id'])
self._live_migrate(server['id'], target_host, 'ACTIVE')
# Wait till subport status is ACTIVE
self.assertTrue(
test_utils.call_until_true(
self._is_port_status_active, CONF.validation.connect_timeout,
5, subport['id']))
parent = self.ports_client.show_port(parent['id'])['port']
self.assertEqual('ACTIVE', parent['status'])
class LiveMigrationRemoteConsolesV26Test(LiveMigrationTestBase):
min_microversion = '2.6'

View File

@ -72,6 +72,7 @@ class Manager(clients.ServiceClients):
self.qos_client = self.network.QosClient()
self.qos_min_bw_client = self.network.QosMinimumBandwidthRulesClient()
self.segments_client = self.network.SegmentsClient()
self.trunks_client = self.network.TrunksClient()
def _set_image_clients(self):
if CONF.service_available.glance:

View File

@ -36,6 +36,7 @@ from tempest.lib.services.network.service_providers_client import \
from tempest.lib.services.network.subnetpools_client import SubnetpoolsClient
from tempest.lib.services.network.subnets_client import SubnetsClient
from tempest.lib.services.network.tags_client import TagsClient
from tempest.lib.services.network.trunks_client import TrunksClient
from tempest.lib.services.network.versions_client import NetworkVersionsClient
__all__ = ['AgentsClient', 'ExtensionsClient', 'FloatingIPsClient',
@ -44,4 +45,4 @@ __all__ = ['AgentsClient', 'ExtensionsClient', 'FloatingIPsClient',
'QosClient', 'QosMinimumBandwidthRulesClient', 'QuotasClient',
'RoutersClient', 'SecurityGroupRulesClient', 'SecurityGroupsClient',
'SegmentsClient', 'ServiceProvidersClient', 'SubnetpoolsClient',
'SubnetsClient', 'TagsClient']
'SubnetsClient', 'TagsClient', 'TrunksClient']

View File

@ -0,0 +1,100 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib.services.network import base
class TrunksClient(base.BaseNetworkClient):
def create_trunk(self, **kwargs):
"""Creates a trunk.
For a full list of available parameters, please refer to the official
API reference:
https://docs.openstack.org/api-ref/network/v2/index.html#create-trunk
"""
uri = '/trunks'
post_data = {'trunk': kwargs}
return self.create_resource(uri, post_data)
def update_trunk(self, trunk_id, **kwargs):
"""Updates a trunk.
For a full list of available parameters, please refer to the official
API reference:
https://docs.openstack.org/api-ref/network/v2/index.html#update-trunk
"""
uri = '/trunks/%s' % trunk_id
put_data = {'trunk': kwargs}
return self.update_resource(uri, put_data)
def show_trunk(self, trunk_id):
"""Shows details for a trunk.
For a full list of available parameters, please refer to the official
API reference:
https://docs.openstack.org/api-ref/network/v2/index.html#show-trunk
"""
uri = '/trunks/%s' % trunk_id
return self.show_resource(uri)
def delete_trunk(self, trunk_id):
"""Deletes a trunk.
For a full list of available parameters, please refer to the official
API reference:
https://docs.openstack.org/api-ref/network/v2/index.html#delete-trunk
"""
uri = '/trunks/%s' % trunk_id
return self.delete_resource(uri)
def list_trunks(self, **filters):
"""Lists trunks to which the tenant has access.
For a full list of available parameters, please refer to the official
API reference:
https://docs.openstack.org/api-ref/network/v2/index.html#list-trunks
"""
uri = '/trunks'
return self.list_resources(uri, **filters)
def add_subports_to_trunk(self, trunk_id, sub_ports):
"""Add subports to a trunk.
For a full list of available parameters, please refer to the official
API reference:
https://docs.openstack.org/api-ref/network/v2/index.html#add-subports-to-trunk
"""
uri = '/trunks/%s/add_subports' % trunk_id
put_data = {'sub_ports': sub_ports}
return self.update_resource(uri, put_data)
def delete_subports_from_trunk(self, trunk_id, sub_ports):
"""Deletes subports from a trunk.
For a full list of available parameters, please refer to the official
API reference:
https://docs.openstack.org/api-ref/network/v2/index.html#delete-subports-from-trunk
"""
uri = '/trunks/%s/remove_subports' % trunk_id
put_data = {'sub_ports': sub_ports}
return self.update_resource(uri, put_data)
def list_subports_of_trunk(self, trunk_id):
"""List subports of a trunk.
For a full list of available parameters, please refer to the official
API reference:
https://docs.openstack.org/api-ref/network/v2/index.html#list-subports-for-trunk
"""
uri = '/trunks/%s/get_subports' % trunk_id
return self.list_resources(uri)

View File

@ -0,0 +1,201 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import copy
from tempest.lib.services.network import trunks_client
from tempest.tests.lib import fake_auth_provider
from tempest.tests.lib.services import base
class TestTrunksClient(base.BaseServiceTest):
FAKE_TRUNK_ID = "dfbc2103-93cf-4edf-952a-ef6deb32ddc6"
FAKE_PORT_ID = "1f04eb36-6c84-11eb-b0ab-4fc62961629d"
FAKE_TRUNKS = {
"trunks": [
{
"admin_state_up": True,
"description": "",
"id": "dfbc2103-93cf-4edf-952a-ef6deb32ddc6",
"name": "trunk0",
"port_id": "00130aab-bb51-42a1-a7c4-6703a3a43aa5",
"project_id": "",
"revision_number": 2,
"status": "DOWN",
"sub_ports": [
{
"port_id": "87d2483d-e5e6-483d-b5f0-81b9ed1d1a91",
"segmentation_id": 101,
"segmentation_type": "vlan"
}
],
"tags": [],
},
{
"admin_state_up": True,
"description": "",
"id": "9eb0e72e-11d3-4295-bcaf-6c89008d9f0a",
"name": "trunk1",
"port_id": "035a12bf-2ae3-42ae-8ad6-9f70640cddde",
"project_id": "",
"revision_number": 2,
"status": "DOWN",
"sub_ports": [
{
"port_id": "cba839d5-02e2-4e09-b964-81356da78165",
"segmentation_id": 102,
"segmentation_type": "vlan"
}
],
"tags": [],
},
]
}
FAKE_TRUNK_1 = {
"name": "trunk0",
"port_id": "00130aab-bb51-42a1-a7c4-6703a3a43aa5"
}
def setUp(self):
super(TestTrunksClient, self).setUp()
fake_auth = fake_auth_provider.FakeAuthProvider()
self.trunks_client = trunks_client.TrunksClient(
fake_auth, "network", "regionOne")
def _test_create_trunk(self, bytes_body=False):
self.check_service_client_function(
self.trunks_client.create_trunk,
"tempest.lib.common.rest_client.RestClient.post",
{"trunk": self.FAKE_TRUNKS["trunks"][0]},
bytes_body,
201,
**self.FAKE_TRUNK_1)
def _test_list_trunks(self, bytes_body=False):
self.check_service_client_function(
self.trunks_client.list_trunks,
"tempest.lib.common.rest_client.RestClient.get",
self.FAKE_TRUNKS,
bytes_body,
200)
def _test_show_trunk(self, bytes_body=False):
self.check_service_client_function(
self.trunks_client.show_trunk,
"tempest.lib.common.rest_client.RestClient.get",
{"trunk": self.FAKE_TRUNKS["trunks"][0]},
bytes_body,
200,
trunk_id=self.FAKE_TRUNK_ID)
def _test_update_trunk(self, bytes_body=False):
update_kwargs = {
"admin_state_up": True,
"name": "new_trunk"
}
resp_body = {
"trunk": copy.deepcopy(
self.FAKE_TRUNKS["trunks"][0]
)
}
resp_body["trunk"].update(update_kwargs)
self.check_service_client_function(
self.trunks_client.update_trunk,
"tempest.lib.common.rest_client.RestClient.put",
resp_body,
bytes_body,
200,
trunk_id=self.FAKE_TRUNK_ID,
**update_kwargs)
def _test_add_subports_to_trunk(self, bytes_body=False):
sub_ports = [{
"port_id": "f04eb36-6c84-11eb-b0ab-4fc62961629d",
"segmentation_type": "vlan",
"segmentation_id": "1001"
}]
resp_body = copy.deepcopy(self.FAKE_TRUNKS["trunks"][0])
resp_body["sub_ports"].append(sub_ports)
self.check_service_client_function(
self.trunks_client.add_subports_to_trunk,
"tempest.lib.common.rest_client.RestClient.put",
resp_body,
bytes_body,
200,
trunk_id=self.FAKE_TRUNK_ID,
sub_ports=sub_ports)
def _test_delete_subports_from_trunk(self, bytes_body=False):
fake_sub_ports = self.FAKE_TRUNKS['trunks'][0]['sub_ports']
sub_ports = [
{"port_id": fake_sub_ports[0]['port_id']}
]
resp_body = copy.deepcopy(self.FAKE_TRUNKS["trunks"][0])
resp_body['sub_ports'] = []
self.check_service_client_function(
self.trunks_client.delete_subports_from_trunk,
"tempest.lib.common.rest_client.RestClient.put",
resp_body,
bytes_body,
200,
trunk_id=self.FAKE_TRUNK_ID,
sub_ports=sub_ports)
def test_create_trunk_with_str_body(self):
self._test_create_trunk()
def test_create_trunk_with_bytes_body(self):
self._test_create_trunk(bytes_body=True)
def test_list_trunks_with_str_body(self):
self._test_list_trunks()
def test_list_trunks_with_bytes_body(self):
self._test_list_trunks(bytes_body=True)
def test_show_trunk_with_str_body(self):
self._test_show_trunk()
def test_show_trunk_with_bytes_body(self):
self._test_show_trunk(bytes_body=True)
def test_update_trunk_with_str_body(self):
self._test_update_trunk()
def test_update_trunk_with_bytes_body(self):
self._test_update_trunk(bytes_body=True)
def test_add_subports_to_trunk_str_body(self):
self._test_add_subports_to_trunk()
def test_add_subports_to_trunk_bytes_body(self):
self._test_add_subports_to_trunk(bytes_body=True)
def test_delete_subports_from_trunk_str_body(self):
self._test_delete_subports_from_trunk()
def test_delete_subports_from_trunk_bytes_body(self):
self._test_delete_subports_from_trunk(bytes_body=True)
def test_delete_trunk(self):
self.check_service_client_function(
self.trunks_client.delete_trunk,
"tempest.lib.common.rest_client.RestClient.delete",
{},
status=204,
trunk_id=self.FAKE_TRUNK_ID)

View File

@ -302,6 +302,7 @@
devstack_services:
neutron-placement: true
neutron-qos: true
neutron-trunk: true
group-vars:
subnode:
devstack_localrc: