From 44db5342af1e694d49f613a8af7140e49c4fc793 Mon Sep 17 00:00:00 2001 From: Devang Doshi Date: Mon, 7 Mar 2016 21:57:44 +0000 Subject: [PATCH] Tempest: Adding l2gw test Added L2 gateway API tests into tempest. Test l2 gateway create, Test l2 gateway create with segmentation id, Test l2 gateway delete, Test l2 gateway update interface, Test l2 gateway update l2gw name, test l2 gateway show Change-Id: Ibfd08960bb0828b4a7b1fe7c84b4abef1e22723f --- vmware_nsx_tempest/common/__init__.py | 0 vmware_nsx_tempest/common/constants.py | 26 ++ vmware_nsx_tempest/config.py | 6 + .../services/l2_gateway_client.py | 65 ++-- vmware_nsx_tempest/services/nsxv3_client.py | 9 + .../tests/nsxv3/api/test_l2_gateway.py | 321 ++++++++++++++++++ 6 files changed, 403 insertions(+), 24 deletions(-) create mode 100644 vmware_nsx_tempest/common/__init__.py create mode 100644 vmware_nsx_tempest/common/constants.py create mode 100644 vmware_nsx_tempest/tests/nsxv3/api/test_l2_gateway.py diff --git a/vmware_nsx_tempest/common/__init__.py b/vmware_nsx_tempest/common/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vmware_nsx_tempest/common/constants.py b/vmware_nsx_tempest/common/constants.py new file mode 100644 index 0000000000..bb40ead80f --- /dev/null +++ b/vmware_nsx_tempest/common/constants.py @@ -0,0 +1,26 @@ +# Copyright 2016 VMware, Inc. +# All Rights Reserved +# +# 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 oslo_log import log + +LOG = log.getLogger(__name__) + +# L2GW constants. +L2GW = "l2_gateway" +L2GWS = L2GW + "s" +L2_GWS_BASE_URI = "/l2-gateways" +EXPECTED_HTTP_RESPONSE_200 = "200" +EXPECTED_HTTP_RESPONSE_201 = "201" +EXPECTED_HTTP_RESPONSE_204 = "204" diff --git a/vmware_nsx_tempest/config.py b/vmware_nsx_tempest/config.py index 5d81ef9913..2e2d3832da 100644 --- a/vmware_nsx_tempest/config.py +++ b/vmware_nsx_tempest/config.py @@ -109,6 +109,12 @@ L2gwGroup = [ default="", help="l2gw multiple devices, interface has multiple VLANs" " m-ifs::dvportgroup-144|138#246;dvportgroup-155|339"), + cfg.StrOpt('vlan_1', + default="16", + help="VLAN id"), + cfg.StrOpt('vlan_2', + default="17", + help="VLAN id"), ] nsxv3_group = cfg.OptGroup(name='nsxv3', diff --git a/vmware_nsx_tempest/services/l2_gateway_client.py b/vmware_nsx_tempest/services/l2_gateway_client.py index 503512aea8..de7aedb06c 100644 --- a/vmware_nsx_tempest/services/l2_gateway_client.py +++ b/vmware_nsx_tempest/services/l2_gateway_client.py @@ -1,3 +1,6 @@ +# Copyright 2016 VMware, Inc. +# All Rights Reserved +# # 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 @@ -9,55 +12,69 @@ # 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 oslo_log import log from tempest.lib.services.network import base +from vmware_nsx_tempest._i18n import _LI +from vmware_nsx_tempest._i18n import _LW +from vmware_nsx_tempest.common import constants + +LOG = log.getLogger(__name__) + class L2GatewayClient(base.BaseNetworkClient): - resource = 'l2_gateway' - resource_plural = 'l2_gateways' - path = 'l2-gateways' - resource_base_path = '/%s' % path - resource_object_path = '/%s/%%s' % path + """ + Request resources via API for L2GatewayClient + l2 gateway create request + l2 gateway update request + l2 gateway show request + l2 gateway delete request + l2 gateway list all request + """ def create_l2_gateway(self, **kwargs): - uri = self.resource_base_path - post_data = {self.resource: kwargs} + uri = constants.L2_GWS_BASE_URI + post_data = {constants.L2GW: kwargs} + LOG.info(_LI("URI : %(uri)s, posting data : %(post_data)s") % { + "uri": uri, "post_data": post_data}) return self.create_resource(uri, post_data) def update_l2_gateway(self, l2_gateway_id, **kwargs): - uri = self.resource_object_path % l2_gateway_id - post_data = {self.resource: kwargs} + uri = constants.L2_GWS_BASE_URI + "/" + l2_gateway_id + post_data = {constants.L2GW: kwargs} + constants.LOG.info( + _LI("URI : %(uri)s, posting data : %(post_data)s") % { + "uri": uri, "post_data": post_data}) return self.update_resource(uri, post_data) def show_l2_gateway(self, l2_gateway_id, **fields): - uri = self.resource_object_path % l2_gateway_id + uri = constants.L2_GWS_BASE_URI + "/" + l2_gateway_id + LOG.info(_LI("URI : %(uri)s") % {"uri": uri}) return self.show_resource(uri, **fields) def delete_l2_gateway(self, l2_gateway_id): - uri = self.resource_object_path % l2_gateway_id + uri = constants.L2_GWS_BASE_URI + "/" + l2_gateway_id + LOG.info(_LI("URI : %(uri)s") % {"uri": uri}) return self.delete_resource(uri) def list_l2_gateways(self, **filters): - uri = self.resource_base_path + uri = constants.L2_GWS_BASE_URI + LOG.info(_LI("URI : %(uri)s") % {"uri": uri}) return self.list_resources(uri, **filters) def get_client(client_mgr): - """create a l2-gateway client from manager or networks_client - - For itempest user: - from itempest import load_our_solar_system as osn - from vmware_nsx_tempest.services import l2_gateway_client - l2gw_client = l2_gateway_client.get_client(osn.adm.manager) - For tempest user: - l2gw_client = l2_gateway_client.get_client(osn.adm) """ - manager = getattr(client_mgr, 'manager', client_mgr) - net_client = getattr(manager, 'networks_client') + Create a l2-gateway client from manager or networks_client + """ try: - _params = manager.default_params_with_timeout_values.copy() - except Exception: + manager = getattr(client_mgr, "manager", client_mgr) + net_client = getattr(manager, "networks_client") + _params = manager.default_params_withy_timeout_values.copy() + except AttributeError as attribute_err: + LOG.warning(_LW("Failed to locate the attribute, Error: %(err_msg)s") % + {"err_msg": attribute_err.__str__()}) _params = {} client = L2GatewayClient(net_client.auth_provider, net_client.service, diff --git a/vmware_nsx_tempest/services/nsxv3_client.py b/vmware_nsx_tempest/services/nsxv3_client.py index a3d3c509ef..df0943822a 100755 --- a/vmware_nsx_tempest/services/nsxv3_client.py +++ b/vmware_nsx_tempest/services/nsxv3_client.py @@ -223,6 +223,15 @@ class NSXV3Client(object): response = self.get(endpoint="/logical-switches") return response.json()['results'] + def get_bridge_cluster_info(self): + """ + Get bridge cluster information. + + :return: returns bridge cluster id and bridge cluster name. + """ + response = self.get(endpoint="/bridge-clusters") + return response.json()["results"] + def get_logical_switch(self, os_name, os_uuid): """ Get the logical switch based on the name and uuid provided. diff --git a/vmware_nsx_tempest/tests/nsxv3/api/test_l2_gateway.py b/vmware_nsx_tempest/tests/nsxv3/api/test_l2_gateway.py new file mode 100644 index 0000000000..c2d5b2a6c9 --- /dev/null +++ b/vmware_nsx_tempest/tests/nsxv3/api/test_l2_gateway.py @@ -0,0 +1,321 @@ +# Copyright 2016 VMware Inc +# All Rights Reserved. +# +# Copyright 2015 OpenStack Foundation +# +# 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.api.network import base +from tempest import config +from tempest.lib.common.utils import data_utils +from tempest import test + +from vmware_nsx_tempest._i18n import _LI +from vmware_nsx_tempest._i18n import _LW +from vmware_nsx_tempest.common import constants +from vmware_nsx_tempest.services import l2_gateway_client +from vmware_nsx_tempest.services import nsxv3_client + +LOG = constants.log.getLogger(__name__) + +CONF = config.CONF + + +class L2GatewayTest(base.BaseAdminNetworkTest): + """ + Test l2 gateway operations. + """ + + credentials = ["primary", "admin"] + + @classmethod + def skip_checks(cls): + """ + Skip running test if we do not meet crietria to run the tests. + """ + super(L2GatewayTest, cls).skip_checks() + if not test.is_extension_enabled("l2-gateway", "network"): + raise cls.skipException("l2-gateway extension not enabled.") + + @classmethod + def setup_clients(cls): + """ + Create various client connections. Such as NSXv3 and L2 Gateway. + """ + super(L2GatewayTest, cls).setup_clients() + cls.l2gw_created = {} + try: + manager = getattr(cls.os_adm, "manager", cls.os_adm) + net_client = getattr(manager, "networks_client") + _params = manager.default_params_withy_timeout_values.copy() + except AttributeError as attribute_err: + LOG.warning( + _LW("Failed to locate the attribute, Error: %(err_msg)s") % + {"err_msg": attribute_err.__str__()}) + _params = {} + cls.l2gw_client = l2_gateway_client.L2GatewayClient( + net_client.auth_provider, + net_client.service, + net_client.region, + net_client.endpoint_type, + **_params) + cls.nsxv3_client_obj = nsxv3_client.NSXV3Client( + CONF.nsxv3.nsx_manager, + CONF.nsxv3.nsx_user, + CONF.nsxv3.nsx_password) + + @classmethod + def resource_setup(cls): + """ + Setting up the resources for the test. + """ + super(L2GatewayTest, cls).resource_setup() + cls.VLAN_1 = getattr(CONF.l2gw, "vlan_1", None) + cls.VLAN_2 = getattr(CONF.l2gw, "vlan_2", None) + + @classmethod + def resource_cleanup(cls): + """ + Clean all the resources used during the test. + """ + for l2gw_id in cls.l2gw_created.keys(): + cls.l2gw_client.delete_l2_gateway(l2gw_id) + cls.l2gw_created.pop(l2gw_id) + + def operate_l2gw(self, name, devices, task): + """ + l2gw operations such create, delete, update and show. + + :param name: l2gw name. + :param devices: l2gw parameters information. + :param task: Operation to perform. + """ + LOG.info(_LI("name: %(name)s, devices: %(devices)s, " + "task: %(task)s") % + {"name": name, "devices": devices, "task": task}) + if task == "create": + rsp = self.l2gw_client.create_l2_gateway( + name=name, **devices) + self.assertEqual(constants.EXPECTED_HTTP_RESPONSE_201, + rsp.response["status"], + "Response code is not %(code)s" % { + "code": + constants.EXPECTED_HTTP_RESPONSE_201}) + rsp_l2gw = rsp[constants.L2GW] + self.l2gw_created[rsp_l2gw["id"]] = rsp_l2gw + LOG.info(_LI("response : %(rsp_l2gw)s") % {"rsp_l2gw": rsp_l2gw}) + self.assertEqual(name, rsp_l2gw["name"], + "l2gw name=%(rsp_name)s is not the same as " + "requested=%(name)s" % {"rsp_name": rsp_l2gw[ + "name"], "name": name}) + elif task == "delete": + l2gw_id, _ = self.l2gw_created.popitem() + rsp = self.l2gw_client.delete_l2_gateway(l2gw_id) + LOG.info(_LI("response : %(rsp)s") % {"rsp": rsp}) + self.assertEqual(constants.EXPECTED_HTTP_RESPONSE_204, + rsp.response["status"], + "Response code is not %(code)s" % { + "code": + constants.EXPECTED_HTTP_RESPONSE_204}) + elif task == "update": + l2gw_id, _ = self.l2gw_created.popitem() + rsp = self.l2gw_client.update_l2_gateway(l2gw_id, + name=name, **devices) + self.assertEqual(constants.EXPECTED_HTTP_RESPONSE_200, + rsp.response["status"], + "Response code is not %(code)s" % { + "code": + constants.EXPECTED_HTTP_RESPONSE_200}) + rsp_l2gw = rsp[constants.L2GW] + self.l2gw_created[rsp_l2gw["id"]] = rsp_l2gw + LOG.info(_LI("response : %(rsp_l2gw)s") % {"rsp_l2gw": rsp_l2gw}) + self.assertEqual(name, rsp_l2gw["name"], + "l2gw name=%(rsp_name)s is not the same as " + "requested=%(name)s" % { + "rsp_name": rsp_l2gw["name"], "name": name}) + if "name" in devices["devices"][0]["interfaces"][0]: + self.assertEqual( + devices["devices"][0]["interfaces"][0]["name"], + rsp_l2gw["devices"][0]["interfaces"][0][ + "name"], "L2GW interface name update " + "failed!!!") + if "segmentation_id" in devices["devices"][0]["interfaces"][0]: + self.assertEqual(devices["devices"][0]["interfaces"][0][ + "segmentation_id"][0], + rsp_l2gw["devices"][0]["interfaces"][0][ + "segmentation_id"][0], + "L2GW segmentation id update failed!!!") + elif task == "show": + l2gw_id, l2gw_parameters = self.l2gw_created.popitem() + rsp = self.l2gw_client.show_l2_gateway(l2gw_id) + self.assertEqual(constants.EXPECTED_HTTP_RESPONSE_200, + rsp.response["status"], + "Response code is not %(code)s" % { + "code": + constants.EXPECTED_HTTP_RESPONSE_200}) + rsp_l2gw = rsp[constants.L2GW] + constants.LOG.info( + _LI("response : %(rsp_l2gw)s") % {"rsp_l2gw": rsp_l2gw}) + self.assertEqual(name, rsp_l2gw["name"], + "l2gw name=%(rsp_name)s is not the same as " + "requested=%(name)s" % { + "rsp_name": rsp_l2gw["name"], + "name": name}) + self.assertEqual(l2gw_parameters, rsp_l2gw, + "l2-gateway-show does not show parameter as it " + "was created.") + self.l2gw_created[l2gw_id] = l2gw_parameters + + def nsx_bridge_cluster_info(self): + """ + Collect the device and interface name of the nsx brdige cluster. + + :return: nsx bridge id and display name. + """ + response = self.nsxv3_client_obj.get_bridge_cluster_info() + if len(response) == 0: + raise RuntimeError("NSX bridge cluster information is null") + return response[0]["id"], response[0]["display_name"] + + @test.attr(type="nsxv3") + @test.idempotent_id("e5e3a089-602c-496e-8c17-4ef613266924") + def test_l2_gateway_create(self): + """ + Create l2gw based on UUID and bridge cluster name. It creates l2gw. + To create l2gw we need bridge cluster name (interface name) and + bridge cluster UUID (device name) from NSX manager. + """ + LOG.info(_LI("Testing l2_gateway_create api")) + device_name, interface_name = self.nsx_bridge_cluster_info() + l2gw_name = data_utils.rand_name(constants.L2GW) + devices = {"devices": [{"device_name": device_name, + "interfaces": [{"name": interface_name}]}] + } + self.operate_l2gw(name=l2gw_name, devices=devices, task="create") + self.resource_cleanup() + + @test.attr(type="nsxv3") + @test.idempotent_id("9968a529-e785-472f-8705-9b394a912e43") + def test_l2_gateway_create_with_segmentation_id(self): + """ + Create l2gw based on UUID and bridge cluster name. It creates l2gw. + To create l2gw we need bridge cluster name (interface name) and + bridge cluster UUID (device name) from NSX manager and vlan id. + """ + LOG.info(_LI("Testing l2_gateway_create api")) + device_name, interface_name = self.nsx_bridge_cluster_info() + l2gw_name = data_utils.rand_name(constants.L2GW) + devices = {"devices": [ + {"device_name": device_name, + "interfaces": [{"name": interface_name, + "segmentation_id": [ + self.VLAN_1, + self.VLAN_2 + ] + }] + }] + } + self.operate_l2gw(name=l2gw_name, devices=devices, task="create") + self.resource_cleanup() + + @test.attr(type="nsxv3") + @test.idempotent_id("670cacb5-134e-467d-ba41-0d7cdbcf3903") + def test_l2_gateway_delete(self): + """ + Delete l2gw will create l2gw and delete recently created l2gw. To + delete l2gw we need l2gw id. + """ + LOG.info(_LI("Testing l2_gateway_delete api")) + device_name, interface_name = self.nsx_bridge_cluster_info() + l2gw_name = data_utils.rand_name(constants.L2GW) + devices = {"devices": [{"device_name": device_name, + "interfaces": [{"name": interface_name}]}] + } + # Creating l2gw. + self.operate_l2gw(name=l2gw_name, devices=devices, task="create") + # Deleting already created l2gw. + self.operate_l2gw(name=l2gw_name, devices=devices, task="delete") + self.resource_cleanup() + + @test.attr(type="nsxv3") + @test.idempotent_id("fa76f6e6-8aa7-46d8-9af4-2206d0773dc3") + def test_l2_gateway_update_l2gw_name(self): + """ + Update l2gw will update info in already created l2gw. To + update l2gw we need l2gw id and payload to update. + """ + LOG.info(_LI("Testing l2_gateway_update api")) + device_name, interface_name = self.nsx_bridge_cluster_info() + l2gw_name = data_utils.rand_name(constants.L2GW) + devices = {"devices": [{"device_name": device_name, + "interfaces": [{"name": interface_name}]}] + } + # Creating l2gw. + self.operate_l2gw(name=l2gw_name, devices=devices, task="create") + # Updating already created l2gw with new l2gw name. + self.operate_l2gw(name=l2gw_name + "_updated", devices=devices, + task="update") + self.resource_cleanup() + + @test.attr(type="nsxv3") + @test.idempotent_id("c4977df8-8e3a-4b7e-a8d2-5aa757117658") + def test_l2_gateway_update_interface(self): + """ + Update l2gw will update info in already created l2gw. To + update l2gw we need l2gw id and payload to update. + """ + LOG.info(_LI("Testing l2_gateway_update api")) + device_name, interface_name = self.nsx_bridge_cluster_info() + l2gw_name = data_utils.rand_name(constants.L2GW) + devices = {"devices": [{"device_name": device_name, + "interfaces": [{"name": interface_name}]}] + } + # Creating l2gw. + self.operate_l2gw(name=l2gw_name, devices=devices, task="create") + # Updating Interfaces. + devices = {"devices": [ + {"device_name": device_name, + + "interfaces": [{"name": "new_name", + "segmentation_id": [ + self.VLAN_1]}], + "deleted_interfaces": [ + {"name": interface_name}]} + ] + } + # Updating already created l2gw with new interface. + self.operate_l2gw(name=l2gw_name, devices=devices, task="update") + self.resource_cleanup() + + @test.attr(type="nsxv3") + @test.idempotent_id("5a3cef97-c91c-4e03-92c8-d180f9269f27") + def test_l2_gateway_show(self): + """ + show l2gw based on UUID. To see l2gw info we need l2gw id. + """ + LOG.info(_LI("Testing l2_gateway_show api")) + device_name, interface_name = self.nsx_bridge_cluster_info() + l2gw_name = data_utils.rand_name(constants.L2GW) + devices = {"devices": [ + {"device_name": device_name, + "interfaces": [{"name": interface_name, + "segmentation_id": [ + self.VLAN_1, + self.VLAN_2]}] + }] + } + # Creating l2gw. + self.operate_l2gw(name=l2gw_name, devices=devices, task="create") + # Show already created l2gw with l2gw id. + self.operate_l2gw(name=l2gw_name, devices=devices, task="show") + self.resource_cleanup()