diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py index 2a3b3f71d2..19c5f846ec 100644 --- a/tempest/api/network/base.py +++ b/tempest/api/network/base.py @@ -48,7 +48,7 @@ class BaseNetworkTest(tempest.test.BaseTestCase): @classmethod def setUpClass(cls): super(BaseNetworkTest, cls).setUpClass() - os = clients.Manager() + os = clients.Manager(interface=cls._interface) cls.network_cfg = os.config.network if not cls.config.service_available.neutron: raise cls.skipException("Neutron support is required") diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py index 7dcbbd8491..7f4945239a 100644 --- a/tempest/api/network/test_networks.py +++ b/tempest/api/network/test_networks.py @@ -23,7 +23,8 @@ from tempest import exceptions from tempest.test import attr -class NetworksTest(base.BaseNetworkTest): +class NetworksTestJSON(base.BaseNetworkTest): + _interface = 'json' """ Tests the following operations in the Neutron API using the REST client for @@ -55,7 +56,7 @@ class NetworksTest(base.BaseNetworkTest): @classmethod def setUpClass(cls): - super(NetworksTest, cls).setUpClass() + super(NetworksTestJSON, cls).setUpClass() cls.network = cls.create_network() cls.name = cls.network['name'] cls.subnet = cls.create_subnet(cls.network) @@ -109,7 +110,7 @@ class NetworksTest(base.BaseNetworkTest): self.assertEqual('200', resp['status']) updated_subnet = body['subnet'] self.assertEqual(updated_subnet['name'], new_subnet) - # Deletes subnet and network + # Delete subnet and network resp, body = self.client.delete_subnet(subnet_id) self.assertEqual('204', resp['status']) resp, body = self.client.delete_network(net_id) @@ -128,6 +129,7 @@ class NetworksTest(base.BaseNetworkTest): def test_list_networks(self): # Verify the network exists in the list of all networks resp, body = self.client.list_networks() + self.assertEqual('200', resp['status']) networks = body['networks'] found = None for n in networks: @@ -149,6 +151,7 @@ class NetworksTest(base.BaseNetworkTest): def test_list_subnets(self): # Verify the subnet exists in the list of all subnets resp, body = self.client.list_subnets() + self.assertEqual('200', resp['status']) subnets = body['subnets'] found = None for n in subnets: @@ -159,7 +162,7 @@ class NetworksTest(base.BaseNetworkTest): @attr(type='gate') def test_create_update_delete_port(self): - # Verify that successful port creation & deletion + # Verify that successful port creation, update & deletion resp, body = self.client.create_port(self.network['id']) self.assertEqual('201', resp['status']) port = body['port'] @@ -174,7 +177,7 @@ class NetworksTest(base.BaseNetworkTest): self.assertEqual('204', resp['status']) @attr(type='gate') - def test_show_ports(self): + def test_show_port(self): # Verify the details of port resp, body = self.client.show_port(self.port['id']) self.assertEqual('200', resp['status']) @@ -221,3 +224,7 @@ class NetworksTest(base.BaseNetworkTest): for n in created_networks: self.assertIsNotNone(n['id']) self.assertIn(n['id'], networks_list) + + +class NetworksTestXML(NetworksTestJSON): + _interface = 'xml' diff --git a/tempest/api/network/test_quotas.py b/tempest/api/network/test_quotas.py index ba70f34d92..b49cbe815e 100644 --- a/tempest/api/network/test_quotas.py +++ b/tempest/api/network/test_quotas.py @@ -23,6 +23,7 @@ from tempest.test import attr class QuotasTest(base.BaseNetworkTest): + _interface = 'json' """ Tests the following operations in the Neutron API using the REST client for diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py index df85682094..4f687b0982 100644 --- a/tempest/api/network/test_routers.py +++ b/tempest/api/network/test_routers.py @@ -21,6 +21,7 @@ from tempest.test import attr class RoutersTest(base.BaseNetworkTest): + _interface = 'json' @classmethod def setUpClass(cls): diff --git a/tempest/clients.py b/tempest/clients.py index 195cb89654..48e4939ae6 100644 --- a/tempest/clients.py +++ b/tempest/clients.py @@ -90,7 +90,8 @@ from tempest.services.identity.xml.identity_client import IdentityClientXML from tempest.services.identity.xml.identity_client import TokenClientXML from tempest.services.image.v1.json.image_client import ImageClientJSON from tempest.services.image.v2.json.image_client import ImageClientV2JSON -from tempest.services.network.json.network_client import NetworkClient +from tempest.services.network.json.network_client import NetworkClientJSON +from tempest.services.network.xml.network_client import NetworkClientXML from tempest.services.object_storage.account_client import AccountClient from tempest.services.object_storage.account_client import \ AccountClientCustomizedHeader @@ -116,6 +117,11 @@ IMAGES_CLIENTS = { "xml": ImagesClientXML, } +NETWORKS_CLIENTS = { + "json": NetworkClientJSON, + "xml": NetworkClientXML, +} + KEYPAIRS_CLIENTS = { "json": KeyPairsClientJSON, "xml": KeyPairsClientXML, @@ -295,6 +301,7 @@ class Manager(object): try: self.servers_client = SERVERS_CLIENTS[interface](*client_args) + self.network_client = NETWORKS_CLIENTS[interface](*client_args) self.limits_client = LIMITS_CLIENTS[interface](*client_args) if self.config.service_available.glance: self.images_client = IMAGES_CLIENTS[interface](*client_args) @@ -339,7 +346,6 @@ class Manager(object): except KeyError: msg = "Unsupported interface type `%s'" % interface raise exceptions.InvalidConfiguration(msg) - self.network_client = NetworkClient(*client_args) self.hosts_client = HostsClientJSON(*client_args) self.account_client = AccountClient(*client_args) if self.config.service_available.glance: diff --git a/tempest/services/network/json/network_client.py b/tempest/services/network/json/network_client.py index b19ed8d7f2..588dc8f282 100644 --- a/tempest/services/network/json/network_client.py +++ b/tempest/services/network/json/network_client.py @@ -17,7 +17,7 @@ import json from tempest.common.rest_client import RestClient -class NetworkClient(RestClient): +class NetworkClientJSON(RestClient): """ Tempest REST client for Neutron. Uses v2 of the Neutron API, since the @@ -33,8 +33,8 @@ class NetworkClient(RestClient): """ def __init__(self, config, username, password, auth_url, tenant_name=None): - super(NetworkClient, self).__init__(config, username, password, - auth_url, tenant_name) + super(NetworkClientJSON, self).__init__(config, username, password, + auth_url, tenant_name) self.service = self.config.network.catalog_type self.version = '2.0' self.uri_prefix = "v%s" % (self.version) @@ -108,15 +108,14 @@ class NetworkClient(RestClient): body = json.loads(body) return resp, body - def create_port(self, network_id, state=None): - if not state: - state = True + def create_port(self, network_id, **kwargs): post_body = { 'port': { 'network_id': network_id, - 'admin_state_up': state, } } + for key, val in kwargs.items(): + post_body['port'][key] = val body = json.dumps(post_body) uri = '%s/ports' % (self.uri_prefix) resp, body = self.post(uri, headers=self.headers, body=body) @@ -244,7 +243,7 @@ class NetworkClient(RestClient): 'admin_state_up', body['router']['admin_state_up']) # Must uncomment/modify these lines once LP question#233187 is solved #update_body['external_gateway_info'] = kwargs.get( - # 'external_gateway_info', body['router']['external_gateway_info']) + # 'external_gateway_info', body['router']['external_gateway_info']) update_body = dict(router=update_body) update_body = json.dumps(update_body) resp, body = self.put(uri, update_body, self.headers) diff --git a/tempest/services/network/xml/__init__.py b/tempest/services/network/xml/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tempest/services/network/xml/network_client.py b/tempest/services/network/xml/network_client.py new file mode 100755 index 0000000000..d4fb6567b1 --- /dev/null +++ b/tempest/services/network/xml/network_client.py @@ -0,0 +1,172 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# 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 lxml import etree +import xml.etree.ElementTree as ET + +from tempest.common.rest_client import RestClientXML +from tempest.services.compute.xml.common import Document +from tempest.services.compute.xml.common import Element +from tempest.services.compute.xml.common import xml_to_json + + +class NetworkClientXML(RestClientXML): + + def __init__(self, config, username, password, auth_url, tenant_name=None): + super(NetworkClientXML, self).__init__(config, username, password, + auth_url, tenant_name) + self.service = self.config.network.catalog_type + self.version = '2.0' + self.uri_prefix = "v%s" % (self.version) + + def list_networks(self): + uri = '%s/networks' % (self.uri_prefix) + resp, body = self.get(uri, self.headers) + networks = self._parse_array(etree.fromstring(body)) + networks = {"networks": networks} + return resp, networks + + def create_network(self, name): + uri = '%s/networks' % (self.uri_prefix) + post_body = Element("network") + p2 = Element("name", name) + post_body.append(p2) + resp, body = self.post(uri, str(Document(post_body)), self.headers) + body = _root_tag_fetcher_and_xml_to_json_parse(body) + return resp, body + + def create_bulk_network(self, count, names): + uri = '%s/networks' % (self.uri_prefix) + post_body = Element("networks") + for i in range(count): + p1 = Element("network") + p2 = Element("name", names[i]) + p1.append(p2) + post_body.append(p1) + resp, body = self.post(uri, str(Document(post_body)), self.headers) + networks = self._parse_array(etree.fromstring(body)) + networks = {"networks": networks} + return resp, networks + + def delete_network(self, uuid): + uri = '%s/networks/%s' % (self.uri_prefix, str(uuid)) + return self.delete(uri, self.headers) + + def show_network(self, uuid): + uri = '%s/networks/%s' % (self.uri_prefix, str(uuid)) + resp, body = self.get(uri, self.headers) + body = _root_tag_fetcher_and_xml_to_json_parse(body) + return resp, body + + def create_subnet(self, net_uuid, cidr): + uri = '%s/subnets' % (self.uri_prefix) + subnet = Element("subnet") + p2 = Element("network_id", net_uuid) + p3 = Element("cidr", cidr) + p4 = Element("ip_version", 4) + subnet.append(p2) + subnet.append(p3) + subnet.append(p4) + resp, body = self.post(uri, str(Document(subnet)), self.headers) + body = _root_tag_fetcher_and_xml_to_json_parse(body) + return resp, body + + def delete_subnet(self, subnet_id): + uri = '%s/subnets/%s' % (self.uri_prefix, str(subnet_id)) + return self.delete(uri, self.headers) + + def list_subnets(self): + uri = '%s/subnets' % (self.uri_prefix) + resp, body = self.get(uri, self.headers) + subnets = self._parse_array(etree.fromstring(body)) + subnets = {"subnets": subnets} + return resp, subnets + + def show_subnet(self, uuid): + uri = '%s/subnets/%s' % (self.uri_prefix, str(uuid)) + resp, body = self.get(uri, self.headers) + body = _root_tag_fetcher_and_xml_to_json_parse(body) + return resp, body + + def create_port(self, net_uuid, **kwargs): + uri = '%s/ports' % (self.uri_prefix) + port = Element("port") + p1 = Element('network_id', net_uuid) + port.append(p1) + for key, val in kwargs.items(): + key = Element(key, val) + port.append(key) + resp, body = self.post(uri, str(Document(port)), self.headers) + body = _root_tag_fetcher_and_xml_to_json_parse(body) + return resp, body + + def delete_port(self, port_id): + uri = '%s/ports/%s' % (self.uri_prefix, str(port_id)) + return self.delete(uri, self.headers) + + def _parse_array(self, node): + array = [] + for child in node.getchildren(): + array.append(xml_to_json(child)) + return array + + def list_ports(self): + url = '%s/ports' % (self.uri_prefix) + resp, body = self.get(url, self.headers) + ports = self._parse_array(etree.fromstring(body)) + ports = {"ports": ports} + return resp, ports + + def show_port(self, port_id): + uri = '%s/ports/%s' % (self.uri_prefix, str(port_id)) + resp, body = self.get(uri, self.headers) + body = _root_tag_fetcher_and_xml_to_json_parse(body) + return resp, body + + def update_port(self, port_id, name): + uri = '%s/ports/%s' % (self.uri_prefix, str(port_id)) + port = Element("port") + p2 = Element("name", name) + port.append(p2) + resp, body = self.put(uri, str(Document(port)), self.headers) + body = _root_tag_fetcher_and_xml_to_json_parse(body) + return resp, body + + def update_subnet(self, subnet_id, name): + uri = '%s/subnets/%s' % (self.uri_prefix, str(subnet_id)) + subnet = Element("subnet") + p2 = Element("name", name) + subnet.append(p2) + resp, body = self.put(uri, str(Document(subnet)), self.headers) + body = _root_tag_fetcher_and_xml_to_json_parse(body) + return resp, body + + def update_network(self, net_id, name): + uri = '%s/networks/%s' % (self.uri_prefix, str(net_id)) + network = Element("network") + p2 = Element("name", name) + network.append(p2) + resp, body = self.put(uri, str(Document(network)), self.headers) + body = _root_tag_fetcher_and_xml_to_json_parse(body) + return resp, body + + +def _root_tag_fetcher_and_xml_to_json_parse(xml_returned_body): + body = ET.fromstring(xml_returned_body) + root_tag = body.tag + if root_tag.startswith("{"): + ns, root_tag = root_tag.split("}", 1) + body = xml_to_json(etree.fromstring(xml_returned_body)) + body = {root_tag: body} + return body