From 437e782ea59032ffe4f1456087782736fcc5794f Mon Sep 17 00:00:00 2001 From: Adit Sarfaty Date: Sun, 9 Oct 2016 16:04:29 +0300 Subject: [PATCH] Integration with nsxlib Change-Id: Ief8af0d5cad8223fb52313d26d75c1f10b13c3cf --- requirements.txt | 1 + ...2c585_nsxv3_add_nsx_dhcp_service_tables.py | 2 +- vmware_nsx/db/nsx_models.py | 2 +- vmware_nsx/nsxlib/v3/__init__.py | 468 -------------- vmware_nsx/nsxlib/v3/client.py | 212 ------- vmware_nsx/nsxlib/v3/cluster.py | 493 --------------- vmware_nsx/nsxlib/v3/config.py | 123 ---- vmware_nsx/nsxlib/v3/exceptions.py | 97 --- vmware_nsx/nsxlib/v3/native_dhcp.py | 63 -- vmware_nsx/nsxlib/v3/ns_group_manager.py | 150 ----- vmware_nsx/nsxlib/v3/nsx_constants.py | 96 --- vmware_nsx/nsxlib/v3/resources.py | 577 ------------------ vmware_nsx/nsxlib/v3/router.py | 194 ------ vmware_nsx/nsxlib/v3/security.py | 529 ---------------- vmware_nsx/nsxlib/v3/utils.py | 212 ------- vmware_nsx/plugins/nsx_v3/plugin.py | 14 +- vmware_nsx/plugins/nsx_v3/utils.py | 4 +- .../services/l2gateway/nsx_v3/driver.py | 4 +- .../services/neutron_taas/nsx_v3/driver.py | 6 +- vmware_nsx/services/trunk/nsx_v3/driver.py | 4 +- .../plugins/nsxv3/resources/dhcp_binding.py | 4 +- .../plugins/nsxv3/resources/metadata_proxy.py | 4 +- .../admin/plugins/nsxv3/resources/ports.py | 2 +- .../admin/plugins/nsxv3/resources/routers.py | 2 +- .../plugins/nsxv3/resources/securitygroups.py | 6 +- .../admin/plugins/nsxv3/resources/utils.py | 2 +- .../test_secgroup_rule_local_ip_prefix.py | 2 +- .../unit/extensions/test_securitygroup.py | 46 +- .../tests/unit/nsx_v3/test_dhcp_metadata.py | 6 +- vmware_nsx/tests/unit/nsx_v3/test_plugin.py | 28 +- vmware_nsx/tests/unit/nsxlib/v3/__init__.py | 0 vmware_nsx/tests/unit/nsxlib/v3/mocks.py | 230 ------- .../tests/unit/nsxlib/v3/nsxlib_testcase.py | 322 ---------- .../tests/unit/nsxlib/v3/test_client.py | 308 ---------- .../tests/unit/nsxlib/v3/test_cluster.py | 204 ------- .../tests/unit/nsxlib/v3/test_constants.py | 162 ----- .../nsxlib/v3/test_qos_switching_profile.py | 177 ------ .../tests/unit/nsxlib/v3/test_resources.py | 552 ----------------- .../tests/unit/nsxlib/v3/test_switch.py | 93 --- vmware_nsx/tests/unit/nsxlib/v3/test_utils.py | 204 ------- .../services/l2gateway/test_nsxv3_driver.py | 4 +- .../services/qos/test_nsxv3_notification.py | 14 +- .../tests/unit/shell/test_admin_utils.py | 2 +- 43 files changed, 80 insertions(+), 5545 deletions(-) delete mode 100644 vmware_nsx/nsxlib/v3/__init__.py delete mode 100644 vmware_nsx/nsxlib/v3/client.py delete mode 100644 vmware_nsx/nsxlib/v3/cluster.py delete mode 100644 vmware_nsx/nsxlib/v3/config.py delete mode 100644 vmware_nsx/nsxlib/v3/exceptions.py delete mode 100644 vmware_nsx/nsxlib/v3/native_dhcp.py delete mode 100644 vmware_nsx/nsxlib/v3/ns_group_manager.py delete mode 100644 vmware_nsx/nsxlib/v3/nsx_constants.py delete mode 100644 vmware_nsx/nsxlib/v3/resources.py delete mode 100644 vmware_nsx/nsxlib/v3/router.py delete mode 100644 vmware_nsx/nsxlib/v3/security.py delete mode 100644 vmware_nsx/nsxlib/v3/utils.py delete mode 100644 vmware_nsx/tests/unit/nsxlib/v3/__init__.py delete mode 100644 vmware_nsx/tests/unit/nsxlib/v3/mocks.py delete mode 100644 vmware_nsx/tests/unit/nsxlib/v3/nsxlib_testcase.py delete mode 100644 vmware_nsx/tests/unit/nsxlib/v3/test_client.py delete mode 100644 vmware_nsx/tests/unit/nsxlib/v3/test_cluster.py delete mode 100644 vmware_nsx/tests/unit/nsxlib/v3/test_constants.py delete mode 100644 vmware_nsx/tests/unit/nsxlib/v3/test_qos_switching_profile.py delete mode 100644 vmware_nsx/tests/unit/nsxlib/v3/test_resources.py delete mode 100644 vmware_nsx/tests/unit/nsxlib/v3/test_switch.py delete mode 100644 vmware_nsx/tests/unit/nsxlib/v3/test_utils.py diff --git a/requirements.txt b/requirements.txt index 5e8b225ec3..1f67f67423 100644 --- a/requirements.txt +++ b/requirements.txt @@ -26,3 +26,4 @@ oslo.vmware>=2.11.0 # Apache-2.0 PrettyTable<0.8,>=0.7.1 # BSD tooz>=1.28.0 # Apache-2.0 decorator>=3.4.0 # BSD +vmware-nsxlib>=0.2.0 # Apache-2.0 diff --git a/vmware_nsx/db/migration/alembic_migrations/versions/newton/expand/c644ec62c585_nsxv3_add_nsx_dhcp_service_tables.py b/vmware_nsx/db/migration/alembic_migrations/versions/newton/expand/c644ec62c585_nsxv3_add_nsx_dhcp_service_tables.py index 42a49a4860..f7345ef036 100644 --- a/vmware_nsx/db/migration/alembic_migrations/versions/newton/expand/c644ec62c585_nsxv3_add_nsx_dhcp_service_tables.py +++ b/vmware_nsx/db/migration/alembic_migrations/versions/newton/expand/c644ec62c585_nsxv3_add_nsx_dhcp_service_tables.py @@ -27,7 +27,7 @@ down_revision = 'c288bb6a7252' from alembic import op import sqlalchemy as sa -from vmware_nsx.nsxlib.v3 import nsx_constants +from vmware_nsxlib.v3 import nsx_constants nsx_service_type_enum = sa.Enum( diff --git a/vmware_nsx/db/nsx_models.py b/vmware_nsx/db/nsx_models.py index 1ee9edc086..e5f2ed6277 100644 --- a/vmware_nsx/db/nsx_models.py +++ b/vmware_nsx/db/nsx_models.py @@ -27,7 +27,7 @@ from sqlalchemy import sql from neutron.db import models_v2 from oslo_db.sqlalchemy import models -from vmware_nsx.nsxlib.v3 import nsx_constants +from vmware_nsxlib.v3 import nsx_constants class TzNetworkBinding(model_base.BASEV2, models.TimestampMixin): diff --git a/vmware_nsx/nsxlib/v3/__init__.py b/vmware_nsx/nsxlib/v3/__init__.py deleted file mode 100644 index 776f608165..0000000000 --- a/vmware_nsx/nsxlib/v3/__init__.py +++ /dev/null @@ -1,468 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# 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 - -from vmware_nsx._i18n import _, _LW -from vmware_nsx.nsxlib.v3 import client -from vmware_nsx.nsxlib.v3 import cluster -from vmware_nsx.nsxlib.v3 import exceptions -from vmware_nsx.nsxlib.v3 import native_dhcp -from vmware_nsx.nsxlib.v3 import nsx_constants -from vmware_nsx.nsxlib.v3 import security -from vmware_nsx.nsxlib.v3 import utils - -LOG = log.getLogger(__name__) - - -class NsxLib(object): - - def __init__(self, nsxlib_config): - - self.nsxlib_config = nsxlib_config - - # create the Cluster - self.cluster = cluster.NSXClusteredAPI(nsxlib_config) - - # create the Client - self.client = client.NSX3Client( - self.cluster, - nsx_api_managers=nsxlib_config.nsx_api_managers, - max_attempts=nsxlib_config.max_attempts) - - # init the api object - self.general_apis = utils.NsxLibApiBase( - self.client, nsxlib_config) - self.port_mirror = NsxLibPortMirror( - self.client, nsxlib_config) - self.bridge_endpoint = NsxLibBridgeEndpoint( - self.client, nsxlib_config) - self.logical_switch = NsxLibLogicalSwitch( - self.client, nsxlib_config) - self.logical_router = NsxLibLogicalRouter( - self.client, nsxlib_config) - self.qos_switching_profile = NsxLibQosSwitchingProfile( - self.client, nsxlib_config) - self.edge_cluster = NsxLibEdgeCluster( - self.client, nsxlib_config) - self.bridge_cluster = NsxLibBridgeCluster( - self.client, nsxlib_config) - self.transport_zone = NsxLibTransportZone( - self.client, nsxlib_config) - self.native_dhcp_profile = NsxLibDhcpProfile( - self.client, nsxlib_config) - self.native_md_proxy = NsxLibMetadataProxy( - self.client, nsxlib_config) - self.firewall_section = security.NsxLibFirewallSection( - self.client, nsxlib_config) - self.ns_group = security.NsxLibNsGroup( - self.client, nsxlib_config, self.firewall_section) - self.native_dhcp = native_dhcp.NsxLibNativeDhcp( - self.client, nsxlib_config) - - super(NsxLib, self).__init__() - - def get_version(self): - node = self.client.get("node") - version = node.get('node_version') - return version - - def build_v3_api_version_tag(self): - return self.general_apis.build_v3_api_version_tag() - - def is_internal_resource(self, nsx_resource): - return self.general_apis.is_internal_resource(nsx_resource) - - def build_v3_tags_payload(self, resource, resource_type, project_name): - return self.general_apis.build_v3_tags_payload( - resource, resource_type, project_name) - - def reinitialize_cluster(self, resource, event, trigger, **kwargs): - self.cluster._reinit_cluster() - - -class NsxLibPortMirror(utils.NsxLibApiBase): - - def create_session(self, source_ports, dest_ports, direction, - description, name, tags): - """Create a PortMirror Session on the backend. - - :param source_ports: List of UUIDs of the ports whose traffic is to be - mirrored. - :param dest_ports: List of UUIDs of the ports where the mirrored - traffic is to be sent. - :param direction: String representing the direction of traffic to be - mirrored. [INGRESS, EGRESS, BIDIRECTIONAL] - :param description: String representing the description of the session. - :param name: String representing the name of the session. - :param tags: nsx backend specific tags. - """ - - resource = 'mirror-sessions' - body = {'direction': direction, - 'tags': tags, - 'display_name': name, - 'description': description, - 'mirror_sources': source_ports, - 'mirror_destination': dest_ports} - return self.client.create(resource, body) - - def delete_session(self, mirror_session_id): - """Delete a PortMirror session on the backend. - - :param mirror_session_id: string representing the UUID of the port - mirror session to be deleted. - """ - resource = 'mirror-sessions/%s' % mirror_session_id - self.client.delete(resource) - - -class NsxLibBridgeEndpoint(utils.NsxLibApiBase): - - def create(self, device_name, seg_id, tags): - """Create a bridge endpoint on the backend. - - Create a bridge endpoint resource on a bridge cluster for the L2 - gateway network connection. - :param device_name: device_name actually refers to the bridge cluster's - UUID. - :param seg_id: integer representing the VLAN segmentation ID. - :param tags: nsx backend specific tags. - """ - resource = 'bridge-endpoints' - body = {'bridge_cluster_id': device_name, - 'tags': tags, - 'vlan': seg_id} - return self.client.create(resource, body) - - def delete(self, bridge_endpoint_id): - """Delete a bridge endpoint on the backend. - - :param bridge_endpoint_id: string representing the UUID of the bridge - endpoint to be deleted. - """ - resource = 'bridge-endpoints/%s' % bridge_endpoint_id - self.client.delete(resource) - - -class NsxLibLogicalSwitch(utils.NsxLibApiBase): - - def create(self, display_name, transport_zone_id, tags, - replication_mode=nsx_constants.MTEP, - admin_state=True, vlan_id=None): - # TODO(salv-orlando): Validate Replication mode and admin_state - # NOTE: These checks might be moved to the API client library if one - # that performs such checks in the client is available - - resource = 'logical-switches' - body = {'transport_zone_id': transport_zone_id, - 'replication_mode': replication_mode, - 'display_name': display_name, - 'tags': tags} - - if admin_state: - body['admin_state'] = nsx_constants.ADMIN_STATE_UP - else: - body['admin_state'] = nsx_constants.ADMIN_STATE_DOWN - - if vlan_id: - body['vlan'] = vlan_id - - return self.client.create(resource, body) - - def delete(self, lswitch_id): - #Using internal method so we can access max_attempts in the decorator - @utils.retry_upon_exception( - exceptions.StaleRevision, - max_attempts=self.nsxlib_config.max_attempts) - def _do_delete(): - resource = ('logical-switches/%s?detach=true&cascade=true' % - lswitch_id) - self.client.delete(resource) - - _do_delete() - - def get(self, logical_switch_id): - resource = "logical-switches/%s" % logical_switch_id - return self.client.get(resource) - - def update(self, lswitch_id, name=None, admin_state=None, tags=None): - #Using internal method so we can access max_attempts in the decorator - @utils.retry_upon_exception( - exceptions.StaleRevision, - max_attempts=self.nsxlib_config.max_attempts) - def _do_update(): - resource = "logical-switches/%s" % lswitch_id - lswitch = self.get(lswitch_id) - if name is not None: - lswitch['display_name'] = name - if admin_state is not None: - if admin_state: - lswitch['admin_state'] = nsx_constants.ADMIN_STATE_UP - else: - lswitch['admin_state'] = nsx_constants.ADMIN_STATE_DOWN - if tags is not None: - lswitch['tags'] = tags - return self.client.update(resource, lswitch) - - return _do_update() - - -class NsxLibQosSwitchingProfile(utils.NsxLibApiBase): - - def _build_args(self, tags, name=None, description=None): - body = {"resource_type": "QosSwitchingProfile", - "tags": tags} - return self._update_args( - body, name=name, description=description) - - def _update_args(self, body, name=None, description=None): - if name: - body["display_name"] = name - if description: - body["description"] = description - return body - - def _enable_shaping_in_args(self, body, burst_size=None, - peak_bandwidth=None, average_bandwidth=None): - for shaper in body["shaper_configuration"]: - # We currently supports only shaping of Egress traffic - if shaper["resource_type"] == "EgressRateShaper": - shaper["enabled"] = True - if burst_size: - shaper["burst_size_bytes"] = burst_size - if peak_bandwidth: - shaper["peak_bandwidth_mbps"] = peak_bandwidth - if average_bandwidth: - shaper["average_bandwidth_mbps"] = average_bandwidth - break - - return body - - def _disable_shaping_in_args(self, body): - for shaper in body["shaper_configuration"]: - # We currently supports only shaping of Egress traffic - if shaper["resource_type"] == "EgressRateShaper": - shaper["enabled"] = False - shaper["burst_size_bytes"] = 0 - shaper["peak_bandwidth_mbps"] = 0 - shaper["average_bandwidth_mbps"] = 0 - break - - return body - - def _update_dscp_in_args(self, body, qos_marking, dscp): - body["dscp"] = {} - body["dscp"]["mode"] = qos_marking.upper() - if dscp: - body["dscp"]["priority"] = dscp - - return body - - def create(self, tags, name=None, description=None): - resource = 'switching-profiles' - body = self._build_args(tags, name, description) - return self.client.create(resource, body) - - def update(self, profile_id, tags, name=None, description=None): - resource = 'switching-profiles/%s' % profile_id - # get the current configuration - body = self.get(profile_id) - # update the relevant fields - body = self._update_args(body, name, description) - return self._update_resource_with_retry(resource, body) - - def update_shaping(self, profile_id, - shaping_enabled=False, - burst_size=None, - peak_bandwidth=None, - average_bandwidth=None, - qos_marking=None, dscp=None): - resource = 'switching-profiles/%s' % profile_id - # get the current configuration - body = self.get(profile_id) - # update the relevant fields - if shaping_enabled: - body = self._enable_shaping_in_args( - body, burst_size=burst_size, - peak_bandwidth=peak_bandwidth, - average_bandwidth=average_bandwidth) - else: - body = self._disable_shaping_in_args(body) - body = self._update_dscp_in_args(body, qos_marking, dscp) - return self._update_resource_with_retry(resource, body) - - def get(self, profile_id): - resource = 'switching-profiles/%s' % profile_id - return self.client.get(resource) - - def delete(self, profile_id): - resource = 'switching-profiles/%s' % profile_id - self.client.delete(resource) - - -class NsxLibLogicalRouter(utils.NsxLibApiBase): - - def _delete_resource_by_values(self, resource, - skip_not_found=True, **kwargs): - resources_get = self.client.get(resource) - matched_num = 0 - for res in resources_get['results']: - if utils.dict_match(kwargs, res): - LOG.debug("Deleting %s from resource %s", res, resource) - delete_resource = resource + "/" + str(res['id']) - self.client.delete(delete_resource) - matched_num = matched_num + 1 - if matched_num == 0: - if skip_not_found: - LOG.warning(_LW("No resource in %(res)s matched for values: " - "%(values)s"), {'res': resource, - 'values': kwargs}) - else: - err_msg = (_("No resource in %(res)s matched for values: " - "%(values)s") % {'res': resource, - 'values': kwargs}) - raise exceptions.ResourceNotFound( - manager=self.cluster.nsx_api_managers, - operation=err_msg) - elif matched_num > 1: - LOG.warning(_LW("%(num)s resources in %(res)s matched for values: " - "%(values)s"), {'num': matched_num, - 'res': resource, - 'values': kwargs}) - - def add_nat_rule(self, logical_router_id, action, translated_network, - source_net=None, dest_net=None, - enabled=True, rule_priority=None): - resource = 'logical-routers/%s/nat/rules' % logical_router_id - body = {'action': action, - 'enabled': enabled, - 'translated_network': translated_network} - if source_net: - body['match_source_network'] = source_net - if dest_net: - body['match_destination_network'] = dest_net - if rule_priority: - body['rule_priority'] = rule_priority - return self.client.create(resource, body) - - def add_static_route(self, logical_router_id, dest_cidr, nexthop): - resource = ('logical-routers/%s/routing/static-routes' % - logical_router_id) - body = {} - if dest_cidr: - body['network'] = dest_cidr - if nexthop: - body['next_hops'] = [{"ip_address": nexthop}] - return self.client.create(resource, body) - - def delete_static_route(self, logical_router_id, static_route_id): - resource = 'logical-routers/%s/routing/static-routes/%s' % ( - logical_router_id, static_route_id) - self.client.delete(resource) - - def delete_static_route_by_values(self, logical_router_id, - dest_cidr=None, nexthop=None): - resource = ('logical-routers/%s/routing/static-routes' % - logical_router_id) - kwargs = {} - if dest_cidr: - kwargs['network'] = dest_cidr - if nexthop: - kwargs['next_hops'] = [{"ip_address": nexthop}] - return self._delete_resource_by_values(resource, **kwargs) - - def delete_nat_rule(self, logical_router_id, nat_rule_id): - resource = 'logical-routers/%s/nat/rules/%s' % (logical_router_id, - nat_rule_id) - self.client.delete(resource) - - def delete_nat_rule_by_values(self, logical_router_id, **kwargs): - resource = 'logical-routers/%s/nat/rules' % logical_router_id - return self._delete_resource_by_values(resource, **kwargs) - - def update_advertisement(self, logical_router_id, **kwargs): - resource = ('logical-routers/%s/routing/advertisement' % - logical_router_id) - return self._update_resource_with_retry(resource, kwargs) - - def get_id_by_name_or_id(self, name_or_id): - """Get a logical router by it's display name or uuid - - Return the logical router data, or raise an exception if not found or - not unique - """ - - return self._get_resource_by_name_or_id(name_or_id, - 'logical-routers') - - -class NsxLibEdgeCluster(utils.NsxLibApiBase): - - def get(self, edge_cluster_uuid): - resource = "edge-clusters/%s" % edge_cluster_uuid - return self.client.get(resource) - - -class NsxLibTransportZone(utils.NsxLibApiBase): - - def get_id_by_name_or_id(self, name_or_id): - """Get a transport zone by it's display name or uuid - - Return the transport zone data, or raise an exception if not found or - not unique - """ - - return self._get_resource_by_name_or_id(name_or_id, - 'transport-zones') - - -class NsxLibDhcpProfile(utils.NsxLibApiBase): - - def get_id_by_name_or_id(self, name_or_id): - """Get a dhcp profile by it's display name or uuid - - Return the dhcp profile data, or raise an exception if not found or - not unique - """ - - return self._get_resource_by_name_or_id(name_or_id, - 'dhcp/server-profiles') - - -class NsxLibMetadataProxy(utils.NsxLibApiBase): - - def get_id_by_name_or_id(self, name_or_id): - """Get a metadata proxy by it's display name or uuid - - Return the metadata proxy data, or raise an exception if not found or - not unique - """ - - return self._get_resource_by_name_or_id(name_or_id, - 'md-proxies') - - -class NsxLibBridgeCluster(utils.NsxLibApiBase): - - def get_id_by_name_or_id(self, name_or_id): - """Get a bridge cluster by it's display name or uuid - - Return the bridge cluster data, or raise an exception if not found or - not unique - """ - - return self._get_resource_by_name_or_id(name_or_id, - 'bridge-clusters') diff --git a/vmware_nsx/nsxlib/v3/client.py b/vmware_nsx/nsxlib/v3/client.py deleted file mode 100644 index 2f6274311f..0000000000 --- a/vmware_nsx/nsxlib/v3/client.py +++ /dev/null @@ -1,212 +0,0 @@ -# Copyright 2015 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. -# -import requests -import six.moves.urllib.parse as urlparse - -from oslo_log import log -from oslo_serialization import jsonutils -from vmware_nsx._i18n import _, _LW -from vmware_nsx.nsxlib.v3 import exceptions -from vmware_nsx.nsxlib.v3 import utils - -LOG = log.getLogger(__name__) - -ERRORS = {requests.codes.NOT_FOUND: exceptions.ResourceNotFound, - requests.codes.PRECONDITION_FAILED: exceptions.StaleRevision} -DEFAULT_ERROR = exceptions.ManagerError - - -class RESTClient(object): - - _VERB_RESP_CODES = { - 'get': [requests.codes.ok], - 'post': [requests.codes.created, requests.codes.ok], - 'put': [requests.codes.ok], - 'delete': [requests.codes.ok] - } - - def __init__(self, connection, url_prefix=None, - default_headers=None, - client_obj=None): - self._conn = connection - self._url_prefix = url_prefix or "" - self._default_headers = default_headers or {} - - def new_client_for(self, *uri_segments): - uri = self._build_url('/'.join(uri_segments)) - - return self.__class__( - self._conn, - url_prefix=uri, - default_headers=self._default_headers, - client_obj=self) - - def list(self, headers=None): - return self.url_list('') - - def get(self, uuid, headers=None): - return self.url_get(uuid, headers=headers) - - def delete(self, uuid, headers=None): - return self.url_delete(uuid, headers=headers) - - def update(self, uuid, body=None, headers=None): - return self.url_put(uuid, body, headers=headers) - - def create(self, resource='', body=None, headers=None): - return self.url_post(resource, body, headers=headers) - - def url_list(self, url, headers=None): - return self.url_get(url, headers=headers) - - def url_get(self, url, headers=None): - return self._rest_call(url, method='GET', headers=headers) - - def url_delete(self, url, headers=None): - return self._rest_call(url, method='DELETE', headers=headers) - - def url_put(self, url, body, headers=None): - return self._rest_call(url, method='PUT', body=body, headers=headers) - - def url_post(self, url, body, headers=None): - return self._rest_call(url, method='POST', body=body, headers=headers) - - def _raise_error(self, status_code, operation, result_msg): - error = ERRORS.get(status_code, DEFAULT_ERROR) - raise error(manager='', operation=operation, details=result_msg) - - def _validate_result(self, result, expected, operation): - if result.status_code not in expected: - result_msg = result.json() if result.content else '' - LOG.warning(_LW("The HTTP request returned error code " - "%(result)s, whereas %(expected)s response " - "codes were expected. Response body %(body)s"), - {'result': result.status_code, - 'expected': '/'.join([str(code) - for code in expected]), - 'body': result_msg}) - - if isinstance(result_msg, dict) and 'error_message' in result_msg: - related_errors = [error['error_message'] for error in - result_msg.get('related_errors', [])] - result_msg = result_msg['error_message'] - if related_errors: - result_msg += " relatedErrors: %s" % ' '.join( - related_errors) - self._raise_error(result.status_code, operation, result_msg) - - @classmethod - def merge_headers(cls, *headers): - merged = {} - for header in headers: - if header: - merged.update(header) - return merged - - def _build_url(self, uri): - prefix = urlparse.urlparse(self._url_prefix) - uri = ("/%s/%s" % (prefix.path, uri)).replace('//', '/').strip('/') - if prefix.netloc: - uri = "%s/%s" % (prefix.netloc, uri) - if prefix.scheme: - uri = "%s://%s" % (prefix.scheme, uri) - return uri - - def _rest_call(self, url, method='GET', body=None, headers=None): - request_headers = headers.copy() if headers else {} - request_headers.update(self._default_headers) - request_url = self._build_url(url) - - do_request = getattr(self._conn, method.lower()) - LOG.debug("REST call: %s %s\nHeaders: %s\nBody: %s", - method, request_url, request_headers, body) - - result = do_request( - request_url, - data=body, - headers=request_headers) - - LOG.debug("REST call: %s %s\nResponse: %s", - method, request_url, result.json() if result.content else '') - - self._validate_result( - result, RESTClient._VERB_RESP_CODES[method.lower()], - _("%(verb)s %(url)s") % {'verb': method, 'url': request_url}) - return result - - -class JSONRESTClient(RESTClient): - - _DEFAULT_HEADERS = { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - } - - def __init__(self, connection, url_prefix=None, - default_headers=None, - client_obj=None): - - super(JSONRESTClient, self).__init__( - connection, - url_prefix=url_prefix, - default_headers=RESTClient.merge_headers( - JSONRESTClient._DEFAULT_HEADERS, default_headers), - client_obj=client_obj) - - def _rest_call(self, *args, **kwargs): - if kwargs.get('body') is not None: - kwargs['body'] = jsonutils.dumps(kwargs['body'], sort_keys=True) - result = super(JSONRESTClient, self)._rest_call(*args, **kwargs) - return result.json() if result.content else result - - -class NSX3Client(JSONRESTClient): - - _NSX_V1_API_PREFIX = 'api/v1/' - - def __init__(self, connection, url_prefix=None, - default_headers=None, - nsx_api_managers=None, - max_attempts=utils.DEFAULT_MAX_ATTEMPTS, - client_obj=None): - - # If the client obj is defined - copy configuration from it - if client_obj: - self.nsx_api_managers = client_obj.nsx_api_managers or [] - self.max_attempts = client_obj.max_attempts - else: - self.nsx_api_managers = nsx_api_managers or [] - self.max_attempts = max_attempts - - url_prefix = url_prefix or NSX3Client._NSX_V1_API_PREFIX - if url_prefix and NSX3Client._NSX_V1_API_PREFIX not in url_prefix: - if url_prefix.startswith('http'): - url_prefix += '/' + NSX3Client._NSX_V1_API_PREFIX - else: - url_prefix = "%s/%s" % (NSX3Client._NSX_V1_API_PREFIX, - url_prefix or '') - - super(NSX3Client, self).__init__( - connection, url_prefix=url_prefix, - default_headers=default_headers, - client_obj=client_obj) - - def _raise_error(self, status_code, operation, result_msg): - """Override the Rest client errors to add the manager IPs""" - error = ERRORS.get(status_code, DEFAULT_ERROR) - raise error(manager=self.nsx_api_managers, - operation=operation, - details=result_msg) diff --git a/vmware_nsx/nsxlib/v3/cluster.py b/vmware_nsx/nsxlib/v3/cluster.py deleted file mode 100644 index c3e61f879d..0000000000 --- a/vmware_nsx/nsxlib/v3/cluster.py +++ /dev/null @@ -1,493 +0,0 @@ -# Copyright 2015 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. -# -import abc -import contextlib -import copy -import datetime -import eventlet -import itertools -import logging -import requests -import six -import six.moves.urllib.parse as urlparse - -from eventlet import greenpool -from eventlet import pools -from oslo_log import log -from oslo_service import loopingcall -from requests import adapters -from requests import exceptions as requests_exceptions -from vmware_nsx._i18n import _, _LI, _LW -from vmware_nsx.nsxlib.v3 import client as nsx_client -from vmware_nsx.nsxlib.v3 import exceptions - - -LOG = log.getLogger(__name__) - -# disable warning message for each HTTP retry -logging.getLogger( - "requests.packages.urllib3.connectionpool").setLevel(logging.ERROR) - - -@six.add_metaclass(abc.ABCMeta) -class AbstractHTTPProvider(object): - """Interface for providers of HTTP connections which - are responsible for creating and validating connections - for their underlying HTTP support. - """ - - @property - def default_scheme(self): - return 'https' - - @abc.abstractproperty - def provider_id(self): - """A unique string name for this provider.""" - pass - - @abc.abstractmethod - def validate_connection(self, cluster_api, endpoint, conn): - """Validate the said connection for the given endpoint and cluster. - """ - pass - - @abc.abstractmethod - def new_connection(self, cluster_api, provider): - """Create a new http connection for the said cluster and - cluster provider. The actual connection should duck type - requests.Session http methods (get(), put(), etc.). - """ - pass - - @abc.abstractmethod - def is_connection_exception(self, exception): - """Determine if the given exception is related to connection - failure. Return True if it's a connection exception and - False otherwise. - """ - - -class TimeoutSession(requests.Session): - """Extends requests.Session to support timeout - at the session level. - """ - - def __init__(self, timeout, read_timeout): - self.timeout = timeout - self.read_timeout = read_timeout - super(TimeoutSession, self).__init__() - - # wrapper timeouts at the session level - # see: https://goo.gl/xNk7aM - def request(self, *args, **kwargs): - if 'timeout' not in kwargs: - kwargs['timeout'] = (self.timeout, self.read_timeout) - return super(TimeoutSession, self).request(*args, **kwargs) - - -class NSXRequestsHTTPProvider(AbstractHTTPProvider): - """Concrete implementation of AbstractHTTPProvider - using requests.Session() as the underlying connection. - """ - - @property - def provider_id(self): - return "%s-%s" % (requests.__title__, requests.__version__) - - def validate_connection(self, cluster_api, endpoint, conn): - client = nsx_client.NSX3Client(conn, url_prefix=endpoint.provider.url) - zones = client.get('transport-zones') - if not zones or zones['result_count'] <= 0: - msg = _("No transport zones found " - "for '%s'") % endpoint.provider.url - LOG.warning(msg) - raise exceptions.ResourceNotFound( - manager=endpoint.provider.url, operation=msg) - - def new_connection(self, cluster_api, provider): - config = cluster_api.nsxlib_config - session = TimeoutSession(config.http_timeout, - config.http_read_timeout) - session.auth = (provider.username, provider.password) - # NSX v3 doesn't use redirects - session.max_redirects = 0 - - session.verify = not config.insecure - if session.verify and provider.ca_file: - # verify using the said ca bundle path - session.verify = provider.ca_file - - # we are pooling with eventlet in the cluster class - adapter = adapters.HTTPAdapter( - pool_connections=1, pool_maxsize=1, - max_retries=config.retries, - pool_block=False) - session.mount('http://', adapter) - session.mount('https://', adapter) - - return session - - def is_connection_exception(self, exception): - return isinstance(exception, requests_exceptions.ConnectionError) - - -class ClusterHealth(object): - """Indicator of overall cluster health with respect - to the connectivity of the clusters managed endpoints. - """ - # all endpoints are UP - GREEN = 'GREEN' - # at least 1 endpoint is UP, but 1 or more are DOWN - ORANGE = 'ORANGE' - # all endpoints are DOWN - RED = 'RED' - - -class EndpointState(object): - """Tracks the connectivity state for a said endpoint. - """ - # no UP or DOWN state recorded yet - INITIALIZED = 'INITIALIZED' - # endpoint has been validate and is good - UP = 'UP' - # endpoint can't be reached or validated - DOWN = 'DOWN' - - -class Provider(object): - """Data holder for a provider which has a unique id - a connection URL, and the credential details. - """ - - def __init__(self, provider_id, provider_url, username, password, ca_file): - self.id = provider_id - self.url = provider_url - self.username = username - self.password = password - self.ca_file = ca_file - - def __str__(self): - return str(self.url) - - -class Endpoint(object): - """A single NSX manager endpoint (host) which includes - related information such as the endpoint's provider, - state, etc.. A pool is used to hold connections to the - endpoint which are doled out when proxying HTTP methods - to the underlying connections. - """ - - def __init__(self, provider, pool): - self.provider = provider - self.pool = pool - self._state = EndpointState.INITIALIZED - self._last_updated = datetime.datetime.now() - - @property - def last_updated(self): - return self._last_updated - - @property - def state(self): - return self._state - - def set_state(self, state): - if self.state != state: - LOG.info(_LI("Endpoint '%(ep)s' changing from state" - " '%(old)s' to '%(new)s'"), - {'ep': self.provider, - 'old': self.state, - 'new': state}) - old_state = self._state - self._state = state - - self._last_updated = datetime.datetime.now() - - return old_state - - def __str__(self): - return "[%s] %s" % (self.state, self.provider) - - -class EndpointConnection(object): - """Simple data holder which contains an endpoint and - a connection for that endpoint. - """ - - def __init__(self, endpoint, connection): - self.endpoint = endpoint - self.connection = connection - - -class ClusteredAPI(object): - """Duck types the major HTTP based methods of a - requests.Session such as get(), put(), post(), etc. - and transparently proxies those calls to one of - its managed NSX manager endpoints. - """ - _HTTP_VERBS = ['get', 'delete', 'head', 'put', 'post', 'patch', 'create'] - - def __init__(self, providers, - http_provider, - min_conns_per_pool=1, - max_conns_per_pool=500, - keepalive_interval=33): - - self._http_provider = http_provider - self._keepalive_interval = keepalive_interval - - def _init_cluster(*args, **kwargs): - self._init_endpoints(providers, - min_conns_per_pool, max_conns_per_pool) - - _init_cluster() - - # keep this internal method for reinitialize upon fork - # for api workers to ensure each process has its own keepalive - # loops + state - self._reinit_cluster = _init_cluster - - def _init_endpoints(self, providers, - min_conns_per_pool, max_conns_per_pool): - LOG.debug("Initializing API endpoints") - - def _create_conn(p): - def _conn(): - # called when a pool needs to create a new connection - return self._http_provider.new_connection(self, p) - return _conn - - self._endpoints = {} - for provider in providers: - pool = pools.Pool( - min_size=min_conns_per_pool, - max_size=max_conns_per_pool, - order_as_stack=True, - create=_create_conn(provider)) - - endpoint = Endpoint(provider, pool) - self._endpoints[provider.id] = endpoint - - # service requests using round robin - self._endpoint_schedule = itertools.cycle(self._endpoints.values()) - - # duck type to proxy http invocations - for method in ClusteredAPI._HTTP_VERBS: - setattr(self, method, self._proxy_stub(method)) - - conns = greenpool.GreenPool() - for endpoint in self._endpoints.values(): - conns.spawn(self._validate, endpoint) - eventlet.sleep(0) - while conns.running(): - if (self.health == ClusterHealth.GREEN - or self.health == ClusterHealth.ORANGE): - # only wait for 1 or more endpoints to reduce init time - break - eventlet.sleep(0.5) - - for endpoint in self._endpoints.values(): - # dynamic loop for each endpoint to ensure connectivity - loop = loopingcall.DynamicLoopingCall( - self._endpoint_keepalive, endpoint) - loop.start(initial_delay=self._keepalive_interval, - periodic_interval_max=self._keepalive_interval, - stop_on_exception=False) - - LOG.debug("Done initializing API endpoint(s). " - "API cluster health: %s", self.health) - - def _endpoint_keepalive(self, endpoint): - delta = datetime.datetime.now() - endpoint.last_updated - if delta.seconds >= self._keepalive_interval: - # TODO(boden): backoff on validation failure - self._validate(endpoint) - return self._keepalive_interval - return self._keepalive_interval - delta.seconds - - @property - def providers(self): - return [ep.provider for ep in self._endpoints.values()] - - @property - def endpoints(self): - return copy.copy(self._endpoints) - - @property - def http_provider(self): - return self._http_provider - - @property - def health(self): - down = 0 - up = 0 - for endpoint in self._endpoints.values(): - if endpoint.state != EndpointState.UP: - down += 1 - else: - up += 1 - - if down == len(self._endpoints): - return ClusterHealth.RED - return (ClusterHealth.GREEN - if up == len(self._endpoints) - else ClusterHealth.ORANGE) - - def _validate(self, endpoint): - try: - with endpoint.pool.item() as conn: - self._http_provider.validate_connection(self, endpoint, conn) - endpoint.set_state(EndpointState.UP) - except Exception as e: - endpoint.set_state(EndpointState.DOWN) - LOG.warning(_LW("Failed to validate API cluster endpoint " - "'%(ep)s' due to: %(err)s"), - {'ep': endpoint, 'err': e}) - - def _select_endpoint(self): - # check for UP state until exhausting all endpoints - seen, total = 0, len(self._endpoints.values()) - while seen < total: - endpoint = next(self._endpoint_schedule) - if endpoint.state == EndpointState.UP: - return endpoint - seen += 1 - - def endpoint_for_connection(self, conn): - # check all endpoint pools - for endpoint in self._endpoints.values(): - if (conn in endpoint.pool.channel.queue or - conn in endpoint.pool.free_items): - return endpoint - - @property - def cluster_id(self): - return ','.join([str(ep.provider.url) - for ep in self._endpoints.values()]) - - @contextlib.contextmanager - def connection(self): - with self.endpoint_connection() as conn_data: - yield conn_data.connection - - @contextlib.contextmanager - def endpoint_connection(self): - endpoint = self._select_endpoint() - if not endpoint: - LOG.debug("All endpoints down for: %s" % - [str(ep) for ep in self._endpoints.values()]) - # all endpoints are DOWN and will have their next - # state updated as per _endpoint_keepalive() - raise exceptions.ServiceClusterUnavailable( - cluster_id=self.cluster_id) - - if endpoint.pool.free() == 0: - LOG.info(_LI("API endpoint %(ep)s at connection " - "capacity %(max)s and has %(waiting)s waiting"), - {'ep': endpoint, - 'max': endpoint.pool.max_size, - 'waiting': endpoint.pool.waiting()}) - # pool.item() will wait if pool has 0 free - with endpoint.pool.item() as conn: - yield EndpointConnection(endpoint, conn) - - def _proxy_stub(self, proxy_for): - def _call_proxy(url, *args, **kwargs): - return self._proxy(proxy_for, url, *args, **kwargs) - return _call_proxy - - def _proxy(self, proxy_for, uri, *args, **kwargs): - # proxy http request call to an avail endpoint - with self.endpoint_connection() as conn_data: - conn = conn_data.connection - endpoint = conn_data.endpoint - - # http conn must support requests style interface - do_request = getattr(conn, proxy_for) - - if not uri.startswith('/'): - uri = "/%s" % uri - url = "%s%s" % (endpoint.provider.url, uri) - try: - LOG.debug("API cluster proxy %s %s to %s", - proxy_for.upper(), uri, url) - # call the actual connection method to do the - # http request/response over the wire - response = do_request(url, *args, **kwargs) - endpoint.set_state(EndpointState.UP) - - return response - except Exception as e: - LOG.warning(_LW("Request failed due to: %s"), e) - if not self._http_provider.is_connection_exception(e): - # only trap and retry connection errors - raise e - endpoint.set_state(EndpointState.DOWN) - LOG.debug("Connection to %s failed, checking additional " - "endpoints" % url) - # retry until exhausting endpoints - return self._proxy(proxy_for, uri, *args, **kwargs) - - -class NSXClusteredAPI(ClusteredAPI): - """Extends ClusteredAPI to get conf values and setup the - NSX v3 cluster. - """ - - def __init__(self, nsxlib_config): - self.nsxlib_config = nsxlib_config - - self._http_provider = (nsxlib_config.http_provider or - NSXRequestsHTTPProvider()) - - super(NSXClusteredAPI, self).__init__( - self._build_conf_providers(), - self._http_provider, - max_conns_per_pool=self.nsxlib_config.concurrent_connections, - keepalive_interval=self.nsxlib_config.conn_idle_timeout) - - LOG.debug("Created NSX clustered API with '%s' " - "provider", self._http_provider.provider_id) - - def _build_conf_providers(self): - - def _schemed_url(uri): - uri = uri.strip('/') - return urlparse.urlparse( - uri if uri.startswith('http') else - "%s://%s" % (self._http_provider.default_scheme, uri)) - - conf_urls = self.nsxlib_config.nsx_api_managers[:] - urls = [] - providers = [] - provider_index = -1 - for conf_url in conf_urls: - provider_index += 1 - conf_url = _schemed_url(conf_url) - if conf_url in urls: - LOG.warning(_LW("'%s' already defined in configuration file. " - "Skipping."), urlparse.urlunparse(conf_url)) - continue - urls.append(conf_url) - providers.append( - Provider( - conf_url.netloc, - urlparse.urlunparse(conf_url), - self.nsxlib_config.username(provider_index), - self.nsxlib_config.password(provider_index), - self.nsxlib_config.ca_file(provider_index))) - return providers diff --git a/vmware_nsx/nsxlib/v3/config.py b/vmware_nsx/nsxlib/v3/config.py deleted file mode 100644 index dc831f12d4..0000000000 --- a/vmware_nsx/nsxlib/v3/config.py +++ /dev/null @@ -1,123 +0,0 @@ -# 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. - - -class NsxLibConfig(object): - """Class holding all the configuration parameters used by the nsxlib code. - - :param nsx_api_managers: List of IP addresses of the NSX managers. - Each IP address should be of the form: - [://][:] - If scheme is not provided https is used. - If port is not provided port 80 is used for http - and port 443 for https. - :param username: User name for the NSX manager - :param password: Password for the NSX manager - :param insecure: If true, the NSX Manager server certificate is not - verified. If false the CA bundle specified via "ca_file" - will be used or if unsest the default system root CAs - will be used. - :param ca_file: Specify a CA bundle file to use in verifying the NSX - Manager server certificate. This option is ignored if - "insecure" is set to True. If "insecure" is set to - False and ca_file is unset, the system root CAs will - be used to verify the server certificate. - - :param concurrent_connections: Maximum concurrent connections to each NSX - manager. - :param retries: Maximum number of times to retry a HTTP connection. - :param http_timeout: The time in seconds before aborting a HTTP connection - to a NSX manager. - :param http_read_timeout: The time in seconds before aborting a HTTP read - response from a NSX manager. - :param conn_idle_timeout: The amount of time in seconds to wait before - ensuring connectivity to the NSX manager if no - manager connection has been used. - :param http_provider: HTTPProvider object, or None. - - :param max_attempts: Maximum number of times to retry API requests upon - stale revision errors. - - :param plugin_scope: The default scope for the v3 api-version tag - :param plugin_tag: The value for the v3 api-version tag - :param plugin_ver: The version of the plugin used as the 'os-api-version' - tag value in the v3 api-version tag - :param dns_nameservers: List of nameservers to configure for the DHCP - binding entries. These will be used if there are - no nameservers defined on the subnet. - :param dns_domain: Domain to use for building the hostnames. - :param dhcp_profile_uuid: The UUID of the NSX DHCP Profile that will be - used to enable native DHCP service. - - """ - - def __init__(self, - nsx_api_managers=None, - username=None, - password=None, - insecure=True, - ca_file=None, - concurrent_connections=10, - retries=3, - http_timeout=10, - http_read_timeout=180, - conn_idle_timeout=10, - http_provider=None, - max_attempts=10, - plugin_scope=None, - plugin_tag=None, - plugin_ver=None, - dns_nameservers=None, - dns_domain='openstacklocal', - dhcp_profile_uuid=None): - - self.nsx_api_managers = nsx_api_managers - self._username = username - self._password = password - self._ca_file = ca_file - self.insecure = insecure - self.concurrent_connections = concurrent_connections - self.retries = retries - self.http_timeout = http_timeout - self.http_read_timeout = http_read_timeout - self.conn_idle_timeout = conn_idle_timeout - self.http_provider = http_provider - self.max_attempts = max_attempts - self.plugin_scope = plugin_scope - self.plugin_tag = plugin_tag - self.plugin_ver = plugin_ver - self.dns_nameservers = dns_nameservers or [] - self.dns_domain = dns_domain - self.dhcp_profile_uuid = dhcp_profile_uuid - - def _attribute_by_index(self, scalar_or_list, index): - if isinstance(scalar_or_list, list): - if not len(scalar_or_list): - return None - if len(scalar_or_list) > index: - return scalar_or_list[index] - # if not long enough - use the first one as default - return scalar_or_list[0] - # this is a scalar - return scalar_or_list - - def username(self, index): - return self._attribute_by_index(self._username, index) - - def password(self, index): - return self._attribute_by_index(self._password, index) - - def ca_file(self, index): - return self._attribute_by_index(self._ca_file, index) diff --git a/vmware_nsx/nsxlib/v3/exceptions.py b/vmware_nsx/nsxlib/v3/exceptions.py deleted file mode 100644 index 8a86ea6915..0000000000 --- a/vmware_nsx/nsxlib/v3/exceptions.py +++ /dev/null @@ -1,97 +0,0 @@ -# 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_utils import excutils -import six - -from vmware_nsx._i18n import _ - - -class NsxLibException(Exception): - """Base NsxLib Exception. - - To correctly use this class, inherit from it and define - a 'message' property. That message will get printf'd - with the keyword arguments provided to the constructor. - """ - message = _("An unknown exception occurred.") - - def __init__(self, **kwargs): - try: - super(NsxLibException, self).__init__(self.message % kwargs) - self.msg = self.message % kwargs - except Exception: - with excutils.save_and_reraise_exception() as ctxt: - if not self.use_fatal_exceptions(): - ctxt.reraise = False - # at least get the core message out if something happened - super(NsxLibException, self).__init__(self.message) - - if six.PY2: - def __unicode__(self): - return unicode(self.msg) - - def __str__(self): - return self.msg - - def use_fatal_exceptions(self): - return False - - -class ManagerError(NsxLibException): - message = _("Unexpected error from backend manager (%(manager)s) " - "for %(operation)s %(details)s") - - def __init__(self, **kwargs): - kwargs['details'] = (': %s' % kwargs['details'] - if 'details' in kwargs - else '') - super(ManagerError, self).__init__(**kwargs) - self.msg = self.message % kwargs - - -class ResourceNotFound(ManagerError): - message = _("Resource could not be found on backend (%(manager)s) for " - "%(operation)s") - - -class StaleRevision(ManagerError): - pass - - -class ServiceClusterUnavailable(ManagerError): - message = _("Service cluster: '%(cluster_id)s' is unavailable. Please, " - "check NSX setup and/or configuration") - - -class NSGroupMemberNotFound(ManagerError): - message = _("Could not find NSGroup %(nsgroup_id)s member %(member_id)s " - "for removal.") - - -class NSGroupIsFull(ManagerError): - message = _("NSGroup %(nsgroup_id)s contains has reached its maximum " - "capacity, unable to add additional members.") - - -class NumberOfNsgroupCriteriaTagsReached(ManagerError): - message = _("Port can be associated with at most %(max_num)s " - "security-groups.") - - -class SecurityGroupMaximumCapacityReached(ManagerError): - message = _("Security Group %(sg_id)s has reached its maximum capacity, " - "no more ports can be associated with this security-group.") diff --git a/vmware_nsx/nsxlib/v3/native_dhcp.py b/vmware_nsx/nsxlib/v3/native_dhcp.py deleted file mode 100644 index c84b1bedc3..0000000000 --- a/vmware_nsx/nsxlib/v3/native_dhcp.py +++ /dev/null @@ -1,63 +0,0 @@ -# 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. - -import netaddr -from neutron_lib.api import validators -from neutron_lib import constants - -from vmware_nsx.nsxlib.v3 import utils - - -class NsxLibNativeDhcp(utils.NsxLibApiBase): - - def build_server_config(self, network, subnet, port, tags): - # Prepare the configuration for a new logical DHCP server. - server_ip = "%s/%u" % (port['fixed_ips'][0]['ip_address'], - netaddr.IPNetwork(subnet['cidr']).prefixlen) - dns_nameservers = subnet['dns_nameservers'] - if not dns_nameservers or not validators.is_attr_set(dns_nameservers): - dns_nameservers = self.nsxlib_config.dns_nameservers - gateway_ip = subnet['gateway_ip'] - if not validators.is_attr_set(gateway_ip): - gateway_ip = None - - # The following code is based on _generate_opts_per_subnet() in - # neutron/agent/linux/dhcp.py. It prepares DHCP options for a subnet. - - # Add route for directly connected network. - host_routes = [{'network': subnet['cidr'], 'next_hop': '0.0.0.0'}] - # Copy routes from subnet host_routes attribute. - for hr in subnet['host_routes']: - if hr['destination'] == constants.IPv4_ANY: - if not gateway_ip: - gateway_ip = hr['nexthop'] - else: - host_routes.append({'network': hr['destination'], - 'next_hop': hr['nexthop']}) - # If gateway_ip is defined, add default route via this gateway. - if gateway_ip: - host_routes.append({'network': constants.IPv4_ANY, - 'next_hop': gateway_ip}) - - options = {'option121': {'static_routes': host_routes}} - name = utils.get_name_and_uuid(network['name'] or 'dhcpserver', - network['id']) - return {'name': name, - 'server_ip': server_ip, - 'dns_nameservers': dns_nameservers, - 'domain_name': self.nsxlib_config.dns_domain, - 'gateway_ip': gateway_ip, - 'options': options, - 'tags': tags} diff --git a/vmware_nsx/nsxlib/v3/ns_group_manager.py b/vmware_nsx/nsxlib/v3/ns_group_manager.py deleted file mode 100644 index 7dcef48afa..0000000000 --- a/vmware_nsx/nsxlib/v3/ns_group_manager.py +++ /dev/null @@ -1,150 +0,0 @@ -# Copyright 2015 OpenStack Foundation - -# 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. - - -import uuid - -from oslo_log import log - -from vmware_nsx._i18n import _, _LW -from vmware_nsx.nsxlib.v3 import exceptions -from vmware_nsx.nsxlib.v3 import nsx_constants as consts - - -LOG = log.getLogger(__name__) - - -class NSGroupManager(object): - """ - This class assists with NSX integration for Neutron security-groups, - Each Neutron security-group is associated with NSX NSGroup object. - Some specific security policies are the same across all security-groups, - i.e - Default drop rule, DHCP. In order to bind these rules to all - NSGroups (security-groups), we create a nested NSGroup (which its members - are also of type NSGroups) to group the other NSGroups and associate it - with these rules. - In practice, one NSGroup (nested) can't contain all the other NSGroups, as - it has strict size limit. To overcome the limited space challenge, we - create several nested groups instead of just one, and we evenly distribute - NSGroups (security-groups) between them. - By using an hashing function on the NSGroup uuid we determine in which - group it should be added, and when deleting an NSGroup (security-group) we - use the same procedure to find which nested group it was added. - """ - - NESTED_GROUP_NAME = 'OS Nested Group' - NESTED_GROUP_DESCRIPTION = ('OpenStack NSGroup. Do not delete.') - - def __init__(self, nsxlib, size): - self.nsxlib_nsgroup = nsxlib.ns_group - self._nested_groups = self._init_nested_groups(size) - self._size = len(self._nested_groups) - - @property - def size(self): - return self._size - - @property - def nested_groups(self): - return self._nested_groups - - def _init_nested_groups(self, requested_size): - # Construct the groups dict - - # {0: ,.., n-1: } - size = requested_size - nested_groups = { - self._get_nested_group_index_from_name(nsgroup): nsgroup['id'] - for nsgroup in self.nsxlib_nsgroup.list() - if self.nsxlib_nsgroup.is_internal_resource(nsgroup)} - - if nested_groups: - size = max(requested_size, max(nested_groups) + 1) - if size > requested_size: - LOG.warning(_LW("Lowering the value of " - "nsx_v3:number_of_nested_groups isn't " - "supported, '%s' nested-groups will be used."), - size) - - absent_groups = set(range(size)) - set(nested_groups.keys()) - if absent_groups: - LOG.warning( - _LW("Found %(num_present)s Nested Groups, " - "creating %(num_absent)s more."), - {'num_present': len(nested_groups), - 'num_absent': len(absent_groups)}) - for i in absent_groups: - cont = self._create_nested_group(i) - nested_groups[i] = cont['id'] - - return nested_groups - - def _get_nested_group_index_from_name(self, nested_group): - # The name format is "Nested Group " - return int(nested_group['display_name'].split()[-1]) - 1 - - def _create_nested_group(self, index): - name_prefix = NSGroupManager.NESTED_GROUP_NAME - name = '%s %s' % (name_prefix, index + 1) - description = NSGroupManager.NESTED_GROUP_DESCRIPTION - tags = self.nsxlib_nsgroup.build_v3_api_version_tag() - return self.nsxlib_nsgroup.create(name, description, tags) - - def _hash_uuid(self, internal_id): - return hash(uuid.UUID(internal_id)) - - def _suggest_nested_group(self, internal_id): - # Suggests a nested group to use, can be iterated to find alternative - # group in case that previous suggestions did not help. - - index = self._hash_uuid(internal_id) % self.size - yield self.nested_groups[index] - - for i in range(1, self.size): - index = (index + 1) % self.size - yield self.nested_groups[index] - - def add_nsgroup(self, nsgroup_id): - for group in self._suggest_nested_group(nsgroup_id): - try: - LOG.debug("Adding NSGroup %s to nested group %s", - nsgroup_id, group) - self.nsxlib_nsgroup.add_members( - group, consts.NSGROUP, [nsgroup_id]) - break - except exceptions.NSGroupIsFull: - LOG.debug("Nested group %(group_id)s is full, trying the " - "next group..", {'group_id': group}) - else: - raise exceptions.ManagerError( - details=_("Reached the maximum supported amount of " - "security groups.")) - - def remove_nsgroup(self, nsgroup_id): - for group in self._suggest_nested_group(nsgroup_id): - try: - self.nsxlib_nsgroup.remove_member( - group, consts.NSGROUP, - nsgroup_id, verify=True) - break - except exceptions.NSGroupMemberNotFound: - LOG.warning(_LW("NSGroup %(nsgroup)s was expected to be found " - "in group %(group_id)s, but wasn't. " - "Looking in the next group.."), - {'nsgroup': nsgroup_id, 'group_id': group}) - continue - else: - LOG.warning(_LW("NSGroup %s was marked for removal, but its " - "reference is missing."), nsgroup_id) diff --git a/vmware_nsx/nsxlib/v3/nsx_constants.py b/vmware_nsx/nsxlib/v3/nsx_constants.py deleted file mode 100644 index 2a655c60b8..0000000000 --- a/vmware_nsx/nsxlib/v3/nsx_constants.py +++ /dev/null @@ -1,96 +0,0 @@ -# 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. - -# Admin statuses -ADMIN_STATE_UP = "UP" -ADMIN_STATE_DOWN = "DOWN" - -# Replication modes -MTEP = "MTEP" - -# Port attachment types -ATTACHMENT_VIF = "VIF" -ATTACHMENT_CIF = "CIF" -ATTACHMENT_LR = "LOGICALROUTER" -ATTACHMENT_DHCP = "DHCP_SERVICE" -ATTACHMENT_MDPROXY = "METADATA_PROXY" - -CIF_RESOURCE_TYPE = "CifAttachmentContext" - -# NSXv3 L2 Gateway constants -BRIDGE_ENDPOINT = "BRIDGEENDPOINT" - -# Router type -ROUTER_TYPE_TIER0 = "TIER0" -ROUTER_TYPE_TIER1 = "TIER1" - -LROUTERPORT_UPLINK = "LogicalRouterUplinkPort" -LROUTERPORT_DOWNLINK = "LogicalRouterDownLinkPort" -LROUTERPORT_LINKONTIER0 = "LogicalRouterLinkPortOnTIER0" -LROUTERPORT_LINKONTIER1 = "LogicalRouterLinkPortOnTIER1" - -# NSX service type -SERVICE_DHCP = "dhcp" - -# NSX-V3 Distributed Firewall constants -NSGROUP = 'NSGroup' -NSGROUP_SIMPLE_EXP = 'NSGroupSimpleExpression' -NSGROUP_TAG_EXP = 'NSGroupTagExpression' - -# Firewall rule position -FW_INSERT_BEFORE = 'insert_before' -FW_INSERT_BOTTOM = 'insert_bottom' -FW_INSERT_TOP = 'insert_top' - -# firewall rule actions -FW_ACTION_ALLOW = 'ALLOW' -FW_ACTION_DROP = 'DROP' -FW_ACTION_REJECT = 'REJECT' - -# nsgroup members update actions -NSGROUP_ADD_MEMBERS = 'ADD_MEMBERS' -NSGROUP_REMOVE_MEMBERS = 'REMOVE_MEMBERS' - -# NSServices resource types -L4_PORT_SET_NSSERVICE = 'L4PortSetNSService' -ICMP_TYPE_NSSERVICE = 'ICMPTypeNSService' -IP_PROTOCOL_NSSERVICE = 'IPProtocolNSService' - -# firewall section types -FW_SECTION_LAYER3 = 'LAYER3' - -TARGET_TYPE_LOGICAL_SWITCH = 'LogicalSwitch' -TARGET_TYPE_LOGICAL_PORT = 'LogicalPort' -TARGET_TYPE_IPV4ADDRESS = 'IPv4Address' -TARGET_TYPE_IPV6ADDRESS = 'IPv6Address' - -# filtering operators and expressions -EQUALS = 'EQUALS' - -IN = 'IN' -OUT = 'OUT' -IN_OUT = 'IN_OUT' - -TCP = 'TCP' -UDP = 'UDP' -ICMPV4 = 'ICMPv4' -ICMPV6 = 'ICMPv6' -IPV4 = 'IPV4' -IPV6 = 'IPV6' -IPV4_IPV6 = 'IPV4_IPV6' - -LOCAL_IP_PREFIX = 'local_ip_prefix' - -LOGGING = 'logging' diff --git a/vmware_nsx/nsxlib/v3/resources.py b/vmware_nsx/nsxlib/v3/resources.py deleted file mode 100644 index 272df3339e..0000000000 --- a/vmware_nsx/nsxlib/v3/resources.py +++ /dev/null @@ -1,577 +0,0 @@ -# Copyright 2015 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. -# -import abc -import collections -import six - -from vmware_nsx._i18n import _ -from vmware_nsx.nsxlib.v3 import exceptions -from vmware_nsx.nsxlib.v3 import nsx_constants -from vmware_nsx.nsxlib.v3 import utils - - -SwitchingProfileTypeId = collections.namedtuple( - 'SwitchingProfileTypeId', 'profile_type, profile_id') - - -PacketAddressClassifier = collections.namedtuple( - 'PacketAddressClassifier', 'ip_address, mac_address, vlan') - - -@six.add_metaclass(abc.ABCMeta) -class AbstractRESTResource(object): - - def __init__(self, rest_client, *args, **kwargs): - self._client = rest_client.new_client_for(self.uri_segment) - - @abc.abstractproperty - def uri_segment(self): - pass - - def list(self): - return self._client.list() - - def get(self, uuid): - return self._client.get(uuid) - - def delete(self, uuid): - return self._client.delete(uuid) - - @abc.abstractmethod - def create(self, *args, **kwargs): - pass - - @abc.abstractmethod - def update(self, uuid, *args, **kwargs): - pass - - def find_by_display_name(self, display_name): - found = [] - for resource in self.list()['results']: - if resource['display_name'] == display_name: - found.append(resource) - return found - - -class SwitchingProfileTypes(object): - IP_DISCOVERY = 'IpDiscoverySwitchingProfile' - MAC_LEARNING = 'MacManagementSwitchingProfile' - PORT_MIRRORING = 'PortMirroringSwitchingProfile' - QOS = 'QosSwitchingProfile' - SPOOF_GUARD = 'SpoofGuardSwitchingProfile' - SWITCH_SECURITY = 'SwitchSecuritySwitchingProfile' - - -class WhiteListAddressTypes(object): - PORT = 'LPORT_BINDINGS' - SWITCH = 'LSWITCH_BINDINGS' - - -class SwitchingProfile(AbstractRESTResource): - - @property - def uri_segment(self): - return 'switching-profiles' - - def list(self): - return self._client.url_get('?include_system_owned=True') - - def create(self, profile_type, display_name=None, - description=None, **api_args): - body = { - 'resource_type': profile_type, - 'display_name': display_name or '', - 'description': description or '' - } - body.update(api_args) - - return self._client.create(body=body) - - def update(self, uuid, profile_type, **api_args): - body = { - 'resource_type': profile_type - } - body.update(api_args) - - return self._client.update(uuid, body=body) - - def create_spoofguard_profile(self, display_name, - description, - whitelist_ports=False, - whitelist_switches=False, - tags=None): - whitelist_providers = [] - if whitelist_ports: - whitelist_providers.append(WhiteListAddressTypes.PORT) - if whitelist_switches: - whitelist_providers.append(WhiteListAddressTypes.SWITCH) - - return self.create(SwitchingProfileTypes.SPOOF_GUARD, - display_name=display_name, - description=description, - white_list_providers=whitelist_providers, - tags=tags or []) - - def create_dhcp_profile(self, display_name, - description, tags=None): - dhcp_filter = { - 'client_block_enabled': True, - 'server_block_enabled': False - } - rate_limits = { - 'enabled': False, - 'rx_broadcast': 0, - 'tx_broadcast': 0, - 'rx_multicast': 0, - 'tx_multicast': 0 - } - bpdu_filter = { - 'enabled': True, - 'white_list': [] - } - return self.create(SwitchingProfileTypes.SWITCH_SECURITY, - display_name=display_name, - description=description, - tags=tags or [], - dhcp_filter=dhcp_filter, - rate_limits=rate_limits, - bpdu_filter=bpdu_filter, - block_non_ip_traffic=True) - - def create_mac_learning_profile(self, display_name, - description, tags=None): - mac_learning = { - 'enabled': True, - } - return self.create(SwitchingProfileTypes.MAC_LEARNING, - display_name=display_name, - description=description, - tags=tags or [], - mac_learning=mac_learning, - mac_change_allowed=True) - - def create_port_mirror_profile(self, display_name, description, - direction, destinations, tags=None): - return self.create(SwitchingProfileTypes.PORT_MIRRORING, - display_name=display_name, - description=description, - tags=tags or [], - direction=direction, - destinations=destinations) - - @classmethod - def build_switch_profile_ids(cls, client, *profiles): - ids = [] - for profile in profiles: - if isinstance(profile, str): - profile = client.get(profile) - if not isinstance(profile, SwitchingProfileTypeId): - profile = SwitchingProfileTypeId( - profile.get('key', profile.get('resource_type')), - profile.get('value', profile.get('id'))) - ids.append(profile) - return ids - - -class LogicalPort(AbstractRESTResource): - - @property - def uri_segment(self): - return 'logical-ports' - - def _build_body_attrs( - self, display_name=None, - admin_state=True, tags=None, - address_bindings=None, - switch_profile_ids=None, - attachment=None): - tags = tags or [] - address_bindings = address_bindings or [] - switch_profile_ids = switch_profile_ids or [] - body = {} - if tags: - body['tags'] = tags - if display_name is not None: - body['display_name'] = display_name - - if admin_state is not None: - if admin_state: - body['admin_state'] = nsx_constants.ADMIN_STATE_UP - else: - body['admin_state'] = nsx_constants.ADMIN_STATE_DOWN - - if address_bindings: - bindings = [] - for binding in address_bindings: - address_classifier = { - 'ip_address': binding.ip_address, - 'mac_address': binding.mac_address - } - if binding.vlan is not None: - address_classifier['vlan'] = int(binding.vlan) - bindings.append(address_classifier) - body['address_bindings'] = bindings - elif address_bindings == []: - # explicitly clear out address bindings - body['address_bindings'] = [] - - if switch_profile_ids: - profiles = [] - for profile in switch_profile_ids: - profiles.append({ - 'value': profile.profile_id, - 'key': profile.profile_type - }) - body['switching_profile_ids'] = profiles - - # Note that attachment could be None, meaning reset it. - if attachment is not False: - body['attachment'] = attachment - - return body - - def _prepare_attachment(self, vif_uuid, parent_vif_id, parent_tag, - address_bindings, attachment_type): - if attachment_type and vif_uuid: - attachment = {'attachment_type': attachment_type, - 'id': vif_uuid} - if parent_vif_id: - context = {'vlan_tag': parent_tag, - 'container_host_vif_id': parent_vif_id, - 'resource_type': nsx_constants.CIF_RESOURCE_TYPE} - attachment['context'] = context - return attachment - elif attachment_type is None or vif_uuid is None: - return None # reset attachment - else: - return False # no attachment change - - def create(self, lswitch_id, vif_uuid, tags=None, - attachment_type=nsx_constants.ATTACHMENT_VIF, - admin_state=True, name=None, address_bindings=None, - parent_vif_id=None, parent_tag=None, - switch_profile_ids=None): - tags = tags or [] - - body = {'logical_switch_id': lswitch_id} - # NOTE(arosen): If parent_vif_id is specified we need to use - # CIF attachment type. - if parent_vif_id: - attachment_type = nsx_constants.ATTACHMENT_CIF - attachment = self._prepare_attachment(vif_uuid, parent_vif_id, - parent_tag, address_bindings, - attachment_type) - body.update(self._build_body_attrs( - display_name=name, - admin_state=admin_state, tags=tags, - address_bindings=address_bindings, - switch_profile_ids=switch_profile_ids, - attachment=attachment)) - return self._client.create(body=body) - - def delete(self, lport_id): - #Using internal method so we can access max_attempts in the decorator - @utils.retry_upon_exception( - exceptions.StaleRevision, - max_attempts=self._client.max_attempts) - def _do_delete(): - return self._client.url_delete('%s?detach=true' % lport_id) - - return _do_delete() - - def update(self, lport_id, vif_uuid, - name=None, admin_state=None, - address_bindings=None, switch_profile_ids=None, - tags_update=None, - attachment_type=nsx_constants.ATTACHMENT_VIF, - parent_vif_id=None, parent_tag=None): - #Using internal method so we can access max_attempts in the decorator - @utils.retry_upon_exception( - exceptions.StaleRevision, - max_attempts=self._client.max_attempts) - def do_update(): - lport = self.get(lport_id) - tags = lport.get('tags', []) - if tags_update: - tags = utils.update_v3_tags(tags, tags_update) - attachment = self._prepare_attachment(vif_uuid, parent_vif_id, - parent_tag, address_bindings, - attachment_type) - lport.update(self._build_body_attrs( - display_name=name, - admin_state=admin_state, tags=tags, - address_bindings=address_bindings, - switch_profile_ids=switch_profile_ids, - attachment=attachment)) - - # If revision_id of the payload that we send is older than what - # NSX has, we will get a 412: Precondition Failed. - # In that case we need to re-fetch, patch the response and send - # it again with the new revision_id - return self._client.update(lport_id, body=lport) - return do_update() - - -class LogicalRouter(AbstractRESTResource): - - @property - def uri_segment(self): - return 'logical-routers' - - def create(self, display_name, tags, edge_cluster_uuid=None, tier_0=False): - # TODO(salv-orlando): If possible do not manage edge clusters - # in the main plugin logic. - router_type = (nsx_constants.ROUTER_TYPE_TIER0 if tier_0 else - nsx_constants.ROUTER_TYPE_TIER1) - body = {'display_name': display_name, - 'router_type': router_type, - 'tags': tags} - if edge_cluster_uuid: - body['edge_cluster_id'] = edge_cluster_uuid - return self._client.create(body=body) - - def delete(self, lrouter_id): - return self._client.url_delete(lrouter_id) - - def update(self, lrouter_id, *args, **kwargs): - #Using internal method so we can access max_attempts in the decorator - @utils.retry_upon_exception( - exceptions.StaleRevision, - max_attempts=self._client.max_attempts) - def _do_update(): - lrouter = self.get(lrouter_id) - for k in kwargs: - lrouter[k] = kwargs[k] - # If revision_id of the payload that we send is older than what - # NSX has, we will get a 412: Precondition Failed. - # In that case we need to re-fetch, patch the response and send - # it again with the new revision_id - return self._client.update(lrouter_id, body=lrouter) - - return _do_update() - - -class LogicalRouterPort(AbstractRESTResource): - - @property - def uri_segment(self): - return 'logical-router-ports' - - def create(self, logical_router_id, - display_name, - tags, - resource_type, - logical_port_id, - address_groups, - edge_cluster_member_index=None): - body = {'display_name': display_name, - 'resource_type': resource_type, - 'logical_router_id': logical_router_id, - 'tags': tags or []} - if address_groups: - body['subnets'] = address_groups - if resource_type in [nsx_constants.LROUTERPORT_UPLINK, - nsx_constants.LROUTERPORT_DOWNLINK]: - body['linked_logical_switch_port_id'] = { - 'target_id': logical_port_id} - elif resource_type == nsx_constants.LROUTERPORT_LINKONTIER1: - body['linked_logical_router_port_id'] = { - 'target_id': logical_port_id} - elif logical_port_id: - body['linked_logical_router_port_id'] = logical_port_id - if edge_cluster_member_index: - body['edge_cluster_member_index'] = edge_cluster_member_index - - return self._client.create(body=body) - - def update(self, logical_port_id, **kwargs): - #Using internal method so we can access max_attempts in the decorator - @utils.retry_upon_exception( - exceptions.StaleRevision, - max_attempts=self._client.max_attempts) - def _do_update(): - logical_router_port = self.get(logical_port_id) - for k in kwargs: - logical_router_port[k] = kwargs[k] - # If revision_id of the payload that we send is older than what - # NSX has, we will get a 412: Precondition Failed. - # In that case we need to re-fetch, patch the response and send - # it again with the new revision_id - return self._client.update(logical_port_id, - body=logical_router_port) - return _do_update() - - def delete(self, logical_port_id): - #Using internal method so we can access max_attempts in the decorator - @utils.retry_upon_exception( - exceptions.StaleRevision, - max_attempts=self._client.max_attempts) - def _do_delete(): - return self._client.url_delete(logical_port_id) - - return _do_delete() - - def get_by_lswitch_id(self, logical_switch_id): - resource = '?logical_switch_id=%s' % logical_switch_id - router_ports = self._client.url_get(resource) - result_count = int(router_ports.get('result_count', "0")) - if result_count >= 2: - raise exceptions.ManagerError( - details=_("Can't support more than one logical router ports " - "on same logical switch %s ") % logical_switch_id) - elif result_count == 1: - return router_ports['results'][0] - else: - err_msg = (_("Logical router link port not found on logical " - "switch %s") % logical_switch_id) - raise exceptions.ResourceNotFound( - manager=self._client.nsx_api_managers, - operation=err_msg) - - def update_by_lswitch_id(self, logical_router_id, ls_id, **payload): - port = self.get_by_lswitch_id(ls_id) - return self.update(port['id'], **payload) - - def delete_by_lswitch_id(self, ls_id): - port = self.get_by_lswitch_id(ls_id) - self.delete(port['id']) - - def get_by_router_id(self, logical_router_id): - resource = '?logical_router_id=%s' % logical_router_id - logical_router_ports = self._client.url_get(resource) - return logical_router_ports['results'] - - def get_tier1_link_port(self, logical_router_id): - logical_router_ports = self.get_by_router_id(logical_router_id) - for port in logical_router_ports: - if port['resource_type'] == nsx_constants.LROUTERPORT_LINKONTIER1: - return port - raise exceptions.ResourceNotFound( - manager=self._client.nsx_api_managers, - operation="get router link port") - - -class MetaDataProxy(AbstractRESTResource): - - @property - def uri_segment(self): - return 'md-proxies' - - def create(self, *args, **kwargs): - pass - - def update(self, uuid, *args, **kwargs): - pass - - -class DhcpProfile(AbstractRESTResource): - - @property - def uri_segment(self): - return 'dhcp/server-profiles' - - def create(self, *args, **kwargs): - pass - - def update(self, uuid, *args, **kwargs): - pass - - -class LogicalDhcpServer(AbstractRESTResource): - - @property - def uri_segment(self): - return 'dhcp/servers' - - def _construct_server(self, body, dhcp_profile_id=None, server_ip=None, - name=None, dns_nameservers=None, domain_name=None, - gateway_ip=False, options=None, tags=None): - if name: - body['display_name'] = name - if dhcp_profile_id: - body['dhcp_profile_id'] = dhcp_profile_id - if server_ip: - body['ipv4_dhcp_server']['dhcp_server_ip'] = server_ip - if dns_nameservers is not None: - # Note that [] is valid for dns_nameservers, means deleting it. - body['ipv4_dhcp_server']['dns_nameservers'] = dns_nameservers - if domain_name: - body['ipv4_dhcp_server']['domain_name'] = domain_name - if gateway_ip is not False: - # Note that None is valid for gateway_ip, means deleting it. - body['ipv4_dhcp_server']['gateway_ip'] = gateway_ip - if options: - body['ipv4_dhcp_server']['options'] = options - if tags: - body['tags'] = tags - - def create(self, dhcp_profile_id, server_ip, name=None, - dns_nameservers=None, domain_name=None, gateway_ip=False, - options=None, tags=None): - body = {'ipv4_dhcp_server': {}} - self._construct_server(body, dhcp_profile_id, server_ip, name, - dns_nameservers, domain_name, gateway_ip, - options, tags) - return self._client.create(body=body) - - def update(self, uuid, dhcp_profile_id=None, server_ip=None, name=None, - dns_nameservers=None, domain_name=None, gateway_ip=False, - options=None, tags=None): - #Using internal method so we can access max_attempts in the decorator - @utils.retry_upon_exception( - exceptions.StaleRevision, - max_attempts=self._client.max_attempts) - def _do_update(): - body = self._client.get(uuid) - self._construct_server(body, dhcp_profile_id, server_ip, name, - dns_nameservers, domain_name, gateway_ip, - options, tags) - return self._client.update(uuid, body=body) - - return _do_update() - - def create_binding(self, server_uuid, mac, ip, hostname=None, - lease_time=None, options=None): - body = {'mac_address': mac, 'ip_address': ip} - if hostname: - body['host_name'] = hostname - if lease_time: - body['lease_time'] = lease_time - if options: - body['options'] = options - url = "%s/static-bindings" % server_uuid - return self._client.url_post(url, body) - - def get_binding(self, server_uuid, binding_uuid): - url = "%s/static-bindings/%s" % (server_uuid, binding_uuid) - return self._client.url_get(url) - - def update_binding(self, server_uuid, binding_uuid, **kwargs): - #Using internal method so we can access max_attempts in the decorator - @utils.retry_upon_exception( - exceptions.StaleRevision, - max_attempts=self._client.max_attempts) - def _do_update(): - body = self.get_binding(server_uuid, binding_uuid) - body.update(kwargs) - url = "%s/static-bindings/%s" % (server_uuid, binding_uuid) - return self._client.url_put(url, body) - - return _do_update() - - def delete_binding(self, server_uuid, binding_uuid): - url = "%s/static-bindings/%s" % (server_uuid, binding_uuid) - return self._client.url_delete(url) diff --git a/vmware_nsx/nsxlib/v3/router.py b/vmware_nsx/nsxlib/v3/router.py deleted file mode 100644 index b4f5edc2e5..0000000000 --- a/vmware_nsx/nsxlib/v3/router.py +++ /dev/null @@ -1,194 +0,0 @@ -# Copyright 2015 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. - -""" -NSX-V3 Plugin router module -""" -import copy - -from neutron_lib import exceptions as n_exc -from oslo_log import log - -from vmware_nsx._i18n import _, _LW -from vmware_nsx.nsxlib.v3 import exceptions -from vmware_nsx.nsxlib.v3 import nsx_constants -from vmware_nsx.nsxlib.v3 import utils - -LOG = log.getLogger(__name__) - -MIN_EDGE_NODE_NUM = 1 - -TIER0_ROUTER_LINK_PORT_NAME = "TIER0-RouterLinkPort" -TIER1_ROUTER_LINK_PORT_NAME = "TIER1-RouterLinkPort" -ROUTER_INTF_PORT_NAME = "Tier1-RouterDownLinkPort" - -FIP_NAT_PRI = 900 -GW_NAT_PRI = 1000 - - -class RouterLib(object): - - def __init__(self, router_client, router_port_client, nsxlib): - self._router_client = router_client - self._router_port_client = router_port_client - self.nsxlib = nsxlib - - def validate_tier0(self, tier0_groups_dict, tier0_uuid): - err_msg = None - try: - lrouter = self._router_client.get(tier0_uuid) - except exceptions.ResourceNotFound: - err_msg = (_("Tier0 router %s not found at the backend. Either a " - "valid UUID must be specified or a default tier0 " - "router UUID must be configured in nsx.ini") % - tier0_uuid) - else: - edge_cluster_uuid = lrouter.get('edge_cluster_id') - if not edge_cluster_uuid: - err_msg = _("Failed to get edge cluster uuid from tier0 " - "router %s at the backend") % lrouter - else: - edge_cluster = self.nsxlib.edge_cluster.get(edge_cluster_uuid) - member_index_list = [member['member_index'] - for member in edge_cluster['members']] - if len(member_index_list) < MIN_EDGE_NODE_NUM: - err_msg = _("%(act_num)s edge members found in " - "edge_cluster %(cluster_id)s, however we " - "require at least %(exp_num)s edge nodes " - "in edge cluster for use.") % { - 'act_num': len(member_index_list), - 'exp_num': MIN_EDGE_NODE_NUM, - 'cluster_id': edge_cluster_uuid} - if err_msg: - raise n_exc.InvalidInput(error_message=err_msg) - else: - tier0_groups_dict[tier0_uuid] = { - 'edge_cluster_uuid': edge_cluster_uuid, - 'member_index_list': member_index_list} - - def add_router_link_port(self, tier1_uuid, tier0_uuid, tags): - # Create Tier0 logical router link port - t0_tags = copy.copy(tags) - t0_tags = utils.add_v3_tag(t0_tags, 'os-tier0-uuid', tier0_uuid) - tier0_link_port = self._router_port_client.create( - tier0_uuid, display_name=TIER0_ROUTER_LINK_PORT_NAME, tags=t0_tags, - resource_type=nsx_constants.LROUTERPORT_LINKONTIER0, - logical_port_id=None, - address_groups=None) - linked_logical_port_id = tier0_link_port['id'] - # Create Tier1 logical router link port - t1_tags = copy.copy(tags) - t1_tags = utils.add_v3_tag(t1_tags, 'os-tier1-uuid', tier1_uuid) - self._router_port_client.create( - tier1_uuid, display_name=TIER1_ROUTER_LINK_PORT_NAME, tags=t1_tags, - resource_type=nsx_constants.LROUTERPORT_LINKONTIER1, - logical_port_id=linked_logical_port_id, - address_groups=None) - - def remove_router_link_port(self, tier1_uuid, tier0_uuid): - try: - tier1_link_port = ( - self._router_port_client.get_tier1_link_port(tier1_uuid)) - except exceptions.ResourceNotFound: - LOG.warning(_LW("Logical router link port for tier1 router: %s " - "not found at the backend"), tier1_uuid) - return - tier1_link_port_id = tier1_link_port['id'] - tier0_link_port_id = ( - tier1_link_port['linked_logical_router_port_id'].get('target_id')) - self._router_port_client.delete(tier1_link_port_id) - self._router_port_client.delete(tier0_link_port_id) - - def update_advertisement(self, logical_router_id, - advertise_route_nat, - advertise_route_connected, - advertise_route_static=False, - enabled=True): - return self.nsxlib.logical_router.update_advertisement( - logical_router_id, - advertise_nat_routes=advertise_route_nat, - advertise_nsx_connected_routes=advertise_route_connected, - advertise_static_routes=advertise_route_static, - enabled=enabled) - - def delete_gw_snat_rule(self, logical_router_id, gw_ip): - return self.nsxlib.logical_router.delete_nat_rule_by_values( - logical_router_id, - translated_network=gw_ip) - - def add_gw_snat_rule(self, logical_router_id, gw_ip): - return self.nsxlib.logical_router.add_nat_rule( - logical_router_id, action="SNAT", - translated_network=gw_ip, - rule_priority=GW_NAT_PRI) - - def update_router_edge_cluster(self, nsx_router_id, edge_cluster_uuid): - return self._router_client.update(nsx_router_id, - edge_cluster_id=edge_cluster_uuid) - - def create_logical_router_intf_port_by_ls_id(self, logical_router_id, - display_name, - tags, - ls_id, - logical_switch_port_id, - address_groups): - try: - port = self._router_port_client.get_by_lswitch_id(ls_id) - except exceptions.ResourceNotFound: - return self._router_port_client.create( - logical_router_id, - display_name, - tags, - nsx_constants.LROUTERPORT_DOWNLINK, - logical_switch_port_id, - address_groups) - else: - return self._router_port_client.update( - port['id'], subnets=address_groups) - - def add_fip_nat_rules(self, logical_router_id, ext_ip, int_ip): - self.nsxlib.logical_router.add_nat_rule( - logical_router_id, action="SNAT", - translated_network=ext_ip, - source_net=int_ip, - rule_priority=FIP_NAT_PRI) - self.nsxlib.logical_router.add_nat_rule( - logical_router_id, action="DNAT", - translated_network=int_ip, - dest_net=ext_ip, - rule_priority=FIP_NAT_PRI) - - def delete_fip_nat_rules(self, logical_router_id, ext_ip, int_ip): - self.nsxlib.logical_router.delete_nat_rule_by_values( - logical_router_id, - action="SNAT", - translated_network=ext_ip, - match_source_network=int_ip) - self.nsxlib.logical_router.delete_nat_rule_by_values( - logical_router_id, - action="DNAT", - translated_network=int_ip, - match_destination_network=ext_ip) - - def add_static_routes(self, nsx_router_id, route): - return self.nsxlib.logical_router.add_static_route( - nsx_router_id, - route['destination'], - route['nexthop']) - - def delete_static_routes(self, nsx_router_id, route): - return self.nsxlib.logical_router.delete_static_route_by_values( - nsx_router_id, dest_cidr=route['destination'], - nexthop=route['nexthop']) diff --git a/vmware_nsx/nsxlib/v3/security.py b/vmware_nsx/nsxlib/v3/security.py deleted file mode 100644 index 9682ff1ae7..0000000000 --- a/vmware_nsx/nsxlib/v3/security.py +++ /dev/null @@ -1,529 +0,0 @@ -# Copyright 2015 OpenStack Foundation - -# 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. - -""" -NSX-V3 Plugin security & Distributed Firewall integration module -""" - -from neutron_lib import constants -from oslo_log import log -from oslo_utils import excutils - -from vmware_nsx._i18n import _LE, _LW -from vmware_nsx.nsxlib.v3 import exceptions -from vmware_nsx.nsxlib.v3 import nsx_constants as consts -from vmware_nsx.nsxlib.v3 import utils - - -LOG = log.getLogger(__name__) - -PORT_SG_SCOPE = 'os-security-group' -MAX_NSGROUPS_CRITERIA_TAGS = 10 - - -class NsxLibNsGroup(utils.NsxLibApiBase): - - def __init__(self, client, max_attempts, firewall_section_handler): - self.firewall_section = firewall_section_handler - super(NsxLibNsGroup, self).__init__(client, max_attempts) - - def update_on_backend(self, context, security_group, - nsgroup_id, section_id, - log_sg_allowed_traffic): - name = self.get_name(security_group) - description = security_group['description'] - logging = (log_sg_allowed_traffic or - security_group[consts.LOGGING]) - rules = self.firewall_section._process_rules_logging_for_update( - section_id, logging) - self.update(nsgroup_id, name, description) - self.firewall_section.update(section_id, name, description, - rules=rules) - - def get_name(self, security_group): - # NOTE(roeyc): We add the security-group id to the NSGroup name, - # for usability purposes. - return '%(name)s - %(id)s' % security_group - - def get_lport_tags(self, secgroups): - if len(secgroups) > MAX_NSGROUPS_CRITERIA_TAGS: - raise exceptions.NumberOfNsgroupCriteriaTagsReached( - max_num=MAX_NSGROUPS_CRITERIA_TAGS) - tags = [] - for sg in secgroups: - tags = utils.add_v3_tag(tags, PORT_SG_SCOPE, sg) - if not tags: - # This port shouldn't be associated with any security-group - tags = [{'scope': PORT_SG_SCOPE, 'tag': None}] - return tags - - def update_lport(self, context, lport_id, original, updated): - added = set(updated) - set(original) - removed = set(original) - set(updated) - for nsgroup_id in added: - try: - self.add_members( - nsgroup_id, consts.TARGET_TYPE_LOGICAL_PORT, - [lport_id]) - except exceptions.NSGroupIsFull: - for nsgroup_id in added: - # NOTE(roeyc): If the port was not added to the nsgroup - # yet, then this request will silently fail. - self.remove_member( - nsgroup_id, consts.TARGET_TYPE_LOGICAL_PORT, - lport_id) - raise exceptions.SecurityGroupMaximumCapacityReached( - sg_id=nsgroup_id) - except exceptions.ResourceNotFound: - with excutils.save_and_reraise_exception(): - LOG.error(_LE("NSGroup %s doesn't exists"), nsgroup_id) - for nsgroup_id in removed: - self.remove_member( - nsgroup_id, consts.TARGET_TYPE_LOGICAL_PORT, lport_id) - - def init_default_section(self, name, description, nested_groups, - log_sg_blocked_traffic): - fw_sections = self.list_sections() - for section in fw_sections: - if section['display_name'] == name: - break - else: - tags = utils.build_v3_api_version_tag() - section = self.create_empty_section( - name, description, nested_groups, tags) - - block_rule = self.get_firewall_rule_dict( - 'Block All', action=consts.FW_ACTION_DROP, - logged=log_sg_blocked_traffic) - # TODO(roeyc): Add additional rules to allow IPV6 NDP. - dhcp_client = self.get_nsservice( - consts.L4_PORT_SET_NSSERVICE, - l4_protocol=consts.UDP, - source_ports=[67], - destination_ports=[68]) - dhcp_client_rule_in = self.get_firewall_rule_dict( - 'DHCP Reply', - direction=consts.IN, - service=dhcp_client) - - dhcp_server = ( - self.get_nsservice(consts.L4_PORT_SET_NSSERVICE, - l4_protocol=consts.UDP, - source_ports=[68], - destination_ports=[67])) - dhcp_client_rule_out = self.get_firewall_rule_dict( - 'DHCP Request', - direction=consts.OUT, - service=dhcp_server) - - self.update_section(section['id'], - name, section['description'], - applied_tos=nested_groups, - rules=[dhcp_client_rule_out, - dhcp_client_rule_in, - block_rule]) - return section['id'] - - def get_nsservice(self, resource_type, **properties): - service = {'resource_type': resource_type} - service.update(properties) - return {'service': service} - - def get_port_tag_expression(self, scope, tag): - return {'resource_type': consts.NSGROUP_TAG_EXP, - 'target_type': consts.TARGET_TYPE_LOGICAL_PORT, - 'scope': scope, - 'tag': tag} - - def create(self, display_name, description, tags, - membership_criteria=None): - body = {'display_name': display_name, - 'description': description, - 'tags': tags, - 'members': []} - if membership_criteria: - body.update({'membership_criteria': [membership_criteria]}) - return self.client.create('ns-groups', body) - - def list(self): - return self.client.get( - 'ns-groups?populate_references=false').get('results', []) - - def update(self, nsgroup_id, display_name=None, description=None, - membership_criteria=None, members=None): - #Using internal method so we can access max_attempts in the decorator - @utils.retry_upon_exception( - exceptions.StaleRevision, - max_attempts=self.nsxlib_config.max_attempts) - def _do_update(): - nsgroup = self.read(nsgroup_id) - if display_name is not None: - nsgroup['display_name'] = display_name - if description is not None: - nsgroup['description'] = description - if members is not None: - nsgroup['members'] = members - if membership_criteria is not None: - nsgroup['membership_criteria'] = [membership_criteria] - return self.client.update( - 'ns-groups/%s' % nsgroup_id, nsgroup) - - return _do_update() - - def get_member_expression(self, target_type, target_id): - return { - 'resource_type': consts.NSGROUP_SIMPLE_EXP, - 'target_property': 'id', - 'target_type': target_type, - 'op': consts.EQUALS, - 'value': target_id} - - def _update_with_members(self, nsgroup_id, members, action): - #Using internal method so we can access max_attempts in the decorator - @utils.retry_upon_exception( - exceptions.StaleRevision, - max_attempts=self.nsxlib_config.max_attempts) - def _do_update(): - members_update = 'ns-groups/%s?action=%s' % (nsgroup_id, action) - return self.client.create(members_update, members) - - return _do_update() - - def add_members(self, nsgroup_id, target_type, target_ids): - members = [] - for target_id in target_ids: - member_expr = self.get_member_expression( - target_type, target_id) - members.append(member_expr) - members = {'members': members} - try: - return self._update_with_members( - nsgroup_id, members, consts.NSGROUP_ADD_MEMBERS) - except (exceptions.StaleRevision, exceptions.ResourceNotFound): - raise - except exceptions.ManagerError: - # REVISIT(roeyc): A ManagerError might have been raised for a - # different reason, e.g - NSGroup does not exists. - LOG.warning(_LW("Failed to add %(target_type)s resources " - "(%(target_ids))s to NSGroup %(nsgroup_id)s"), - {'target_type': target_type, - 'target_ids': target_ids, - 'nsgroup_id': nsgroup_id}) - - raise exceptions.NSGroupIsFull(nsgroup_id=nsgroup_id) - - def remove_member(self, nsgroup_id, target_type, - target_id, verify=False): - member_expr = self.get_member_expression( - target_type, target_id) - members = {'members': [member_expr]} - try: - return self._update_with_members( - nsgroup_id, members, consts.NSGROUP_REMOVE_MEMBERS) - except exceptions.ManagerError: - if verify: - raise exceptions.NSGroupMemberNotFound(member_id=target_id, - nsgroup_id=nsgroup_id) - - def read(self, nsgroup_id): - return self.client.get( - 'ns-groups/%s?populate_references=true' % nsgroup_id) - - def delete(self, nsgroup_id): - try: - return self.client.delete( - 'ns-groups/%s?force=true' % nsgroup_id) - # FIXME(roeyc): Should only except NotFound error. - except Exception: - LOG.debug("NSGroup %s does not exists for delete request.", - nsgroup_id) - - -class NsxLibFirewallSection(utils.NsxLibApiBase): - - def _get_direction(self, sg_rule): - return ( - consts.IN if sg_rule['direction'] == 'ingress' - else consts.OUT - ) - - def _get_l4_protocol_name(self, protocol_number): - if protocol_number is None: - return - protocol_number = constants.IP_PROTOCOL_MAP.get(protocol_number, - protocol_number) - protocol_number = int(protocol_number) - if protocol_number == 6: - return consts.TCP - elif protocol_number == 17: - return consts.UDP - elif protocol_number == 1: - return consts.ICMPV4 - else: - return protocol_number - - def get_nsservice(self, resource_type, **properties): - service = {'resource_type': resource_type} - service.update(properties) - return {'service': service} - - def _decide_service(self, sg_rule): - l4_protocol = self._get_l4_protocol_name(sg_rule['protocol']) - direction = self._get_direction(sg_rule) - - if l4_protocol in [consts.TCP, consts.UDP]: - # If port_range_min is not specified then we assume all ports are - # matched, relying on neutron to perform validation. - source_ports = [] - if sg_rule['port_range_min'] is None: - destination_ports = [] - elif sg_rule['port_range_min'] != sg_rule['port_range_max']: - # NSX API requires a non-empty range (e.g - '22-23') - destination_ports = ['%(port_range_min)s-%(port_range_max)s' - % sg_rule] - else: - destination_ports = ['%(port_range_min)s' % sg_rule] - - if direction == consts.OUT: - source_ports, destination_ports = destination_ports, [] - - return self.get_nsservice( - consts.L4_PORT_SET_NSSERVICE, - l4_protocol=l4_protocol, - source_ports=source_ports, - destination_ports=destination_ports) - elif l4_protocol == consts.ICMPV4: - return self.get_nsservice( - consts.ICMP_TYPE_NSSERVICE, - protocol=l4_protocol, - icmp_type=sg_rule['port_range_min'], - icmp_code=sg_rule['port_range_max']) - elif l4_protocol is not None: - return self.get_nsservice( - consts.IP_PROTOCOL_NSSERVICE, - protocol_number=l4_protocol) - - def _build(self, display_name, description, applied_tos, tags): - return {'display_name': display_name, - 'description': description, - 'stateful': True, - 'section_type': consts.FW_SECTION_LAYER3, - 'applied_tos': [self.get_nsgroup_reference(t_id) - for t_id in applied_tos], - 'tags': tags} - - def create_empty(self, display_name, description, - applied_tos, tags, - operation=consts.FW_INSERT_BOTTOM, - other_section=None): - resource = 'firewall/sections?operation=%s' % operation - body = self._build(display_name, description, - applied_tos, tags) - if other_section: - resource += '&id=%s' % other_section - return self.client.create(resource, body) - - def update(self, section_id, display_name=None, description=None, - applied_tos=None, rules=None): - #Using internal method so we can access max_attempts in the decorator - @utils.retry_upon_exception( - exceptions.StaleRevision, - max_attempts=self.nsxlib_config.max_attempts) - def _do_update(): - resource = 'firewall/sections/%s' % section_id - section = self.read(section_id) - - if rules is not None: - resource += '?action=update_with_rules' - section.update({'rules': rules}) - if display_name is not None: - section['display_name'] = display_name - if description is not None: - section['description'] = description - if applied_tos is not None: - section['applied_tos'] = [self.get_nsgroup_reference(nsg_id) - for nsg_id in applied_tos] - if rules is not None: - return self.client.create(resource, section) - elif any(p is not None for p in (display_name, description, - applied_tos)): - return self.client.update(resource, section) - - return _do_update() - - def read(self, section_id): - resource = 'firewall/sections/%s' % section_id - return self.client.get(resource) - - def list(self): - resource = 'firewall/sections' - return self.client.get(resource).get('results', []) - - def delete(self, section_id): - resource = 'firewall/sections/%s?cascade=true' % section_id - return self.client.delete(resource) - - def get_nsgroup_reference(self, nsgroup_id): - return {'target_id': nsgroup_id, - 'target_type': consts.NSGROUP} - - def get_ip_cidr_reference(self, ip_cidr_block, ip_protocol): - target_type = (consts.TARGET_TYPE_IPV4ADDRESS - if ip_protocol == consts.IPV4 - else consts.TARGET_TYPE_IPV6ADDRESS) - return {'target_id': ip_cidr_block, - 'target_type': target_type} - - def get_rule_dict( - self, display_name, source=None, - destination=None, - direction=consts.IN_OUT, - ip_protocol=consts.IPV4_IPV6, - service=None, action=consts.FW_ACTION_ALLOW, - logged=False): - return {'display_name': display_name, - 'sources': [source] if source else [], - 'destinations': [destination] if destination else [], - 'direction': direction, - 'ip_protocol': ip_protocol, - 'services': [service] if service else [], - 'action': action, - 'logged': logged} - - def add_rule(self, rule, section_id): - resource = 'firewall/sections/%s/rules' % section_id - params = '?operation=insert_bottom' - return self.client.create(resource + params, rule) - - def add_rules(self, rules, section_id): - resource = 'firewall/sections/%s/rules' % section_id - params = '?action=create_multiple&operation=insert_bottom' - return self.client.create(resource + params, {'rules': rules}) - - def delete_rule(self, section_id, rule_id): - resource = 'firewall/sections/%s/rules/%s' % (section_id, rule_id) - return self.client.delete(resource) - - def get_rules(self, section_id): - resource = 'firewall/sections/%s/rules' % section_id - return self.client.get(resource) - - def _get_fw_rule_from_sg_rule(self, sg_rule, nsgroup_id, rmt_nsgroup_id, - logged, action): - # IPV4 or IPV6 - ip_protocol = sg_rule['ethertype'].upper() - direction = self._get_direction(sg_rule) - - if sg_rule.get(consts.LOCAL_IP_PREFIX): - local_ip_prefix = self.get_ip_cidr_reference( - sg_rule[consts.LOCAL_IP_PREFIX], - ip_protocol) - else: - local_ip_prefix = None - - source = None - local_group = self.get_nsgroup_reference(nsgroup_id) - if sg_rule['remote_ip_prefix'] is not None: - source = self.get_ip_cidr_reference( - sg_rule['remote_ip_prefix'], ip_protocol) - destination = local_ip_prefix or local_group - else: - if rmt_nsgroup_id: - source = self.get_nsgroup_reference(rmt_nsgroup_id) - destination = local_ip_prefix or local_group - if direction == consts.OUT: - source, destination = destination, source - - service = self._decide_service(sg_rule) - name = sg_rule['id'] - - return self.get_rule_dict(name, source, - destination, direction, - ip_protocol, service, - action, logged) - - def create_rules(self, context, section_id, nsgroup_id, - logging_enabled, action, security_group_rules, - ruleid_2_remote_nsgroup_map): - # 1. translate rules - # 2. insert in section - # 3. return the rules - firewall_rules = [] - for sg_rule in security_group_rules: - remote_nsgroup_id = ruleid_2_remote_nsgroup_map[sg_rule['id']] - fw_rule = self._get_fw_rule_from_sg_rule( - sg_rule, nsgroup_id, remote_nsgroup_id, - logging_enabled, action) - - firewall_rules.append(fw_rule) - - return self.add_rules(firewall_rules, section_id) - - def set_rule_logging(self, section_id, logging): - rules = self._process_rules_logging_for_update( - section_id, logging) - self.update(section_id, rules=rules) - - def _process_rules_logging_for_update(self, section_id, logging_enabled): - rules = self.get_rules(section_id).get('results', []) - update_rules = False - for rule in rules: - if rule['logged'] != logging_enabled: - rule['logged'] = logging_enabled - update_rules = True - return rules if update_rules else None - - def init_default(self, name, description, nested_groups, - log_sg_blocked_traffic): - fw_sections = self.list() - for section in fw_sections: - if section['display_name'] == name: - break - else: - tags = self.build_v3_api_version_tag() - section = self.create_empty( - name, description, nested_groups, tags) - - block_rule = self.get_rule_dict( - 'Block All', action=consts.FW_ACTION_DROP, - logged=log_sg_blocked_traffic) - # TODO(roeyc): Add additional rules to allow IPV6 NDP. - dhcp_client = self.get_nsservice( - consts.L4_PORT_SET_NSSERVICE, - l4_protocol=consts.UDP, - source_ports=[67], - destination_ports=[68]) - dhcp_client_rule_in = self.get_rule_dict( - 'DHCP Reply', direction=consts.IN, - service=dhcp_client) - - dhcp_server = ( - self.get_nsservice( - consts.L4_PORT_SET_NSSERVICE, - l4_protocol=consts.UDP, - source_ports=[68], - destination_ports=[67])) - dhcp_client_rule_out = self.get_rule_dict( - 'DHCP Request', direction=consts.OUT, - service=dhcp_server) - - self.update(section['id'], - name, section['description'], - applied_tos=nested_groups, - rules=[dhcp_client_rule_out, - dhcp_client_rule_in, - block_rule]) - return section['id'] diff --git a/vmware_nsx/nsxlib/v3/utils.py b/vmware_nsx/nsxlib/v3/utils.py deleted file mode 100644 index 75d7252398..0000000000 --- a/vmware_nsx/nsxlib/v3/utils.py +++ /dev/null @@ -1,212 +0,0 @@ -# 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. - -import tenacity - -from neutron_lib import exceptions -from oslo_log import log - -from vmware_nsx._i18n import _ -from vmware_nsx.nsxlib.v3 import exceptions as nsxlib_exceptions - -LOG = log.getLogger(__name__) - -MAX_RESOURCE_TYPE_LEN = 20 -MAX_TAG_LEN = 40 -DEFAULT_MAX_ATTEMPTS = 10 - - -def _validate_resource_type_length(resource_type): - # Add in a validation to ensure that we catch this at build time - if len(resource_type) > MAX_RESOURCE_TYPE_LEN: - raise exceptions.InvalidInput( - error_message=(_('Resource type cannot exceed %(max_len)s ' - 'characters: %(resource_type)s') % - {'max_len': MAX_RESOURCE_TYPE_LEN, - 'resource_type': resource_type})) - - -def add_v3_tag(tags, resource_type, tag): - _validate_resource_type_length(resource_type) - tags.append({'scope': resource_type, 'tag': tag[:MAX_TAG_LEN]}) - return tags - - -def update_v3_tags(current_tags, tags_update): - current_scopes = set([tag['scope'] for tag in current_tags]) - updated_scopes = set([tag['scope'] for tag in tags_update]) - - tags = [{'scope': tag['scope'], 'tag': tag['tag']} - for tag in (current_tags + tags_update) - if tag['scope'] in (current_scopes ^ updated_scopes)] - - modified_scopes = current_scopes & updated_scopes - for tag in tags_update: - if tag['scope'] in modified_scopes: - # If the tag value is empty or None, then remove the tag completely - if tag['tag']: - tag['tag'] = tag['tag'][:MAX_TAG_LEN] - tags.append(tag) - - return tags - - -def retry_upon_exception(exc, delay=0.5, max_delay=2, - max_attempts=DEFAULT_MAX_ATTEMPTS): - return tenacity.retry(reraise=True, - retry=tenacity.retry_if_exception_type(exc), - wait=tenacity.wait_exponential( - multiplier=delay, max=max_delay), - stop=tenacity.stop_after_attempt(max_attempts)) - - -def list_match(list1, list2): - # Check if list1 and list2 have identical elements, but relaxed on - # dict elements where list1's dict element can be a subset of list2's - # corresponding element. - if (not isinstance(list1, list) or - not isinstance(list2, list) or - len(list1) != len(list2)): - return False - list1 = sorted(list1) - list2 = sorted(list2) - for (v1, v2) in zip(list1, list2): - if isinstance(v1, dict): - if not dict_match(v1, v2): - return False - elif isinstance(v1, list): - if not list_match(v1, v2): - return False - elif v1 != v2: - return False - return True - - -def dict_match(dict1, dict2): - # Check if dict1 is a subset of dict2. - if not isinstance(dict1, dict) or not isinstance(dict2, dict): - return False - for k1, v1 in dict1.items(): - if k1 not in dict2: - return False - v2 = dict2[k1] - if isinstance(v1, dict): - if not dict_match(v1, v2): - return False - elif isinstance(v1, list): - if not list_match(v1, v2): - return False - elif v1 != v2: - return False - return True - - -def get_name_and_uuid(name, uuid, tag=None, maxlen=80): - short_uuid = '_' + uuid[:5] + '...' + uuid[-5:] - maxlen = maxlen - len(short_uuid) - if tag: - maxlen = maxlen - len(tag) - 1 - return name[:maxlen] + '_' + tag + short_uuid - else: - return name[:maxlen] + short_uuid - - -class NsxLibApiBase(object): - """Base class for nsxlib api """ - def __init__(self, client, nsxlib_config): - self.client = client - self.nsxlib_config = nsxlib_config - super(NsxLibApiBase, self).__init__() - - def _update_resource_with_retry(self, resource, payload): - #Using internal method so we can access max_attempts in the decorator - @retry_upon_exception(nsxlib_exceptions.StaleRevision, - max_attempts=self.nsxlib_config.max_attempts) - def do_update(): - revised_payload = self.client.get(resource) - for key_name in payload.keys(): - revised_payload[key_name] = payload[key_name] - return self.client.update(resource, revised_payload) - - return do_update() - - def _get_resource_by_name_or_id(self, name_or_id, resource): - all_results = self.client.get(resource)['results'] - matched_results = [] - for rs in all_results: - if rs.get('id') == name_or_id: - # Matched by id - must be unique - return name_or_id - - if rs.get('display_name') == name_or_id: - # Matched by name - add to the list to verify it is unique - matched_results.append(rs) - - if len(matched_results) == 0: - err_msg = (_("Could not find %(resource)s %(name)s") % - {'name': name_or_id, 'resource': resource}) - # XXX improve exception handling... - raise exceptions.ManagerError(details=err_msg) - elif len(matched_results) > 1: - err_msg = (_("Found multiple %(resource)s named %(name)s") % - {'name': name_or_id, 'resource': resource}) - # XXX improve exception handling... - raise exceptions.ManagerError(details=err_msg) - - return matched_results[0].get('id') - - def build_v3_api_version_tag(self,): - """ - Some resources are created on the manager that do not have a - corresponding plugin resource. - """ - return [{'scope': self.nsxlib_config.plugin_scope, - 'tag': self.nsxlib_config.plugin_tag}, - {'scope': "os-api-version", - 'tag': self.nsxlib_config.plugin_ver}] - - def is_internal_resource(self, nsx_resource): - """ - Indicates whether the passed nsx-resource is owned by the plugin for - internal use. - """ - for tag in nsx_resource.get('tags', []): - if tag['scope'] == self.nsxlib_config.plugin_scope: - return tag['tag'] == self.nsxlib_config.plugin_tag - return False - - def build_v3_tags_payload(self, resource, resource_type, project_name): - """ - Construct the tags payload that will be pushed to NSX-v3 - Add :, os-project-id:, - os-project-name: os-api-version: - """ - _validate_resource_type_length(resource_type) - # There may be cases when the plugin creates the port, for example DHCP - if not project_name: - project_name = self.nsxlib_config.plugin_tag - tenant_id = resource.get('tenant_id', '') - # If tenant_id is present in resource and set to None, explicitly set - # the tenant_id in tags as ''. - if tenant_id is None: - tenant_id = '' - return [{'scope': resource_type, - 'tag': resource.get('id', '')[:MAX_TAG_LEN]}, - {'scope': 'os-project-id', - 'tag': tenant_id[:MAX_TAG_LEN]}, - {'scope': 'os-project-name', - 'tag': project_name[:MAX_TAG_LEN]}, - {'scope': 'os-api-version', - 'tag': self.nsxlib_config.plugin_ver}] diff --git a/vmware_nsx/plugins/nsx_v3/plugin.py b/vmware_nsx/plugins/nsx_v3/plugin.py index 49a7cc9842..e002058fde 100644 --- a/vmware_nsx/plugins/nsx_v3/plugin.py +++ b/vmware_nsx/plugins/nsx_v3/plugin.py @@ -84,17 +84,17 @@ from vmware_nsx.extensions import advancedserviceproviders as as_providers from vmware_nsx.extensions import maclearning as mac_ext from vmware_nsx.extensions import providersecuritygroup as provider_sg from vmware_nsx.extensions import securitygrouplogging as sg_logging -from vmware_nsx.nsxlib.v3 import exceptions as nsx_lib_exc -from vmware_nsx.nsxlib.v3 import ns_group_manager -from vmware_nsx.nsxlib.v3 import nsx_constants as nsxlib_consts -from vmware_nsx.nsxlib.v3 import resources as nsx_resources -from vmware_nsx.nsxlib.v3 import router -from vmware_nsx.nsxlib.v3 import security -from vmware_nsx.nsxlib.v3 import utils as nsxlib_utils from vmware_nsx.plugins.nsx_v3 import utils as v3_utils from vmware_nsx.services.qos.common import utils as qos_com_utils from vmware_nsx.services.qos.nsx_v3 import utils as qos_utils from vmware_nsx.services.trunk.nsx_v3 import driver as trunk_driver +from vmware_nsxlib.v3 import exceptions as nsx_lib_exc +from vmware_nsxlib.v3 import ns_group_manager +from vmware_nsxlib.v3 import nsx_constants as nsxlib_consts +from vmware_nsxlib.v3 import resources as nsx_resources +from vmware_nsxlib.v3 import router +from vmware_nsxlib.v3 import security +from vmware_nsxlib.v3 import utils as nsxlib_utils LOG = log.getLogger(__name__) diff --git a/vmware_nsx/plugins/nsx_v3/utils.py b/vmware_nsx/plugins/nsx_v3/utils.py index dd57019ea9..4d21e2fb1d 100644 --- a/vmware_nsx/plugins/nsx_v3/utils.py +++ b/vmware_nsx/plugins/nsx_v3/utils.py @@ -16,8 +16,8 @@ from oslo_config import cfg from neutron import version as n_version -from vmware_nsx.nsxlib import v3 -from vmware_nsx.nsxlib.v3 import config +from vmware_nsxlib import v3 +from vmware_nsxlib.v3 import config NSX_NEUTRON_PLUGIN = 'NSX Neutron plugin' diff --git a/vmware_nsx/services/l2gateway/nsx_v3/driver.py b/vmware_nsx/services/l2gateway/nsx_v3/driver.py index 3b68a64415..18ddad853b 100644 --- a/vmware_nsx/services/l2gateway/nsx_v3/driver.py +++ b/vmware_nsx/services/l2gateway/nsx_v3/driver.py @@ -36,8 +36,8 @@ from neutron_lib import exceptions as n_exc from vmware_nsx._i18n import _, _LE, _LI from vmware_nsx.common import utils as nsx_utils from vmware_nsx.db import db as nsx_db -from vmware_nsx.nsxlib.v3 import exceptions as nsxlib_exc -from vmware_nsx.nsxlib.v3 import nsx_constants +from vmware_nsxlib.v3 import exceptions as nsxlib_exc +from vmware_nsxlib.v3 import nsx_constants LOG = logging.getLogger(__name__) diff --git a/vmware_nsx/services/neutron_taas/nsx_v3/driver.py b/vmware_nsx/services/neutron_taas/nsx_v3/driver.py index 05a268f238..53c43c774f 100644 --- a/vmware_nsx/services/neutron_taas/nsx_v3/driver.py +++ b/vmware_nsx/services/neutron_taas/nsx_v3/driver.py @@ -28,10 +28,10 @@ from oslo_utils import excutils from vmware_nsx._i18n import _, _LE, _LW from vmware_nsx.common import exceptions as nsx_exc from vmware_nsx.db import db as nsx_db -from vmware_nsx.nsxlib import v3 as nsxlib -from vmware_nsx.nsxlib.v3 import exceptions as nsxlib_exc -from vmware_nsx.nsxlib.v3 import resources as nsx_resources from vmware_nsx.plugins.nsx_v3 import utils as v3_utils +from vmware_nsxlib import v3 as nsxlib +from vmware_nsxlib.v3 import exceptions as nsxlib_exc +from vmware_nsxlib.v3 import resources as nsx_resources LOG = logging.getLogger(__name__) diff --git a/vmware_nsx/services/trunk/nsx_v3/driver.py b/vmware_nsx/services/trunk/nsx_v3/driver.py index fd16d53ce4..98d65e80b7 100644 --- a/vmware_nsx/services/trunk/nsx_v3/driver.py +++ b/vmware_nsx/services/trunk/nsx_v3/driver.py @@ -28,8 +28,8 @@ from vmware_nsx._i18n import _LE from vmware_nsx.common import nsx_constants as nsx_consts from vmware_nsx.common import utils as nsx_utils from vmware_nsx.db import db as nsx_db -from vmware_nsx.nsxlib.v3 import exceptions as nsxlib_exc -from vmware_nsx.nsxlib.v3 import resources as nsx_resources +from vmware_nsxlib.v3 import exceptions as nsxlib_exc +from vmware_nsxlib.v3 import resources as nsx_resources LOG = logging.getLogger(__name__) diff --git a/vmware_nsx/shell/admin/plugins/nsxv3/resources/dhcp_binding.py b/vmware_nsx/shell/admin/plugins/nsxv3/resources/dhcp_binding.py index 1f8e8d0706..a6bd8f8a18 100644 --- a/vmware_nsx/shell/admin/plugins/nsxv3/resources/dhcp_binding.py +++ b/vmware_nsx/shell/admin/plugins/nsxv3/resources/dhcp_binding.py @@ -21,13 +21,13 @@ from oslo_config import cfg from vmware_nsx._i18n import _LE, _LI from vmware_nsx.common import utils as nsx_utils -from vmware_nsx.nsxlib.v3 import nsx_constants -from vmware_nsx.nsxlib.v3 import resources from vmware_nsx.shell.admin.plugins.common import constants from vmware_nsx.shell.admin.plugins.common import formatters from vmware_nsx.shell.admin.plugins.common import utils as admin_utils from vmware_nsx.shell.admin.plugins.nsxv3.resources import utils import vmware_nsx.shell.resources as shell +from vmware_nsxlib.v3 import nsx_constants +from vmware_nsxlib.v3 import resources LOG = logging.getLogger(__name__) neutron_client = utils.NeutronDbClient() diff --git a/vmware_nsx/shell/admin/plugins/nsxv3/resources/metadata_proxy.py b/vmware_nsx/shell/admin/plugins/nsxv3/resources/metadata_proxy.py index 3a443fd1a7..424c8057f6 100644 --- a/vmware_nsx/shell/admin/plugins/nsxv3/resources/metadata_proxy.py +++ b/vmware_nsx/shell/admin/plugins/nsxv3/resources/metadata_proxy.py @@ -21,13 +21,13 @@ from oslo_config import cfg from vmware_nsx._i18n import _LE, _LI from vmware_nsx.common import utils as nsx_utils from vmware_nsx.dhcp_meta import rpc as nsx_rpc -from vmware_nsx.nsxlib.v3 import nsx_constants -from vmware_nsx.nsxlib.v3 import resources from vmware_nsx.shell.admin.plugins.common import constants from vmware_nsx.shell.admin.plugins.common import formatters from vmware_nsx.shell.admin.plugins.common import utils as admin_utils from vmware_nsx.shell.admin.plugins.nsxv3.resources import utils import vmware_nsx.shell.resources as shell +from vmware_nsxlib.v3 import nsx_constants +from vmware_nsxlib.v3 import resources LOG = logging.getLogger(__name__) neutron_client = utils.NeutronDbClient() diff --git a/vmware_nsx/shell/admin/plugins/nsxv3/resources/ports.py b/vmware_nsx/shell/admin/plugins/nsxv3/resources/ports.py index 7a702481c0..4bd41c19e2 100644 --- a/vmware_nsx/shell/admin/plugins/nsxv3/resources/ports.py +++ b/vmware_nsx/shell/admin/plugins/nsxv3/resources/ports.py @@ -23,7 +23,6 @@ from vmware_nsx.common import exceptions as nsx_exc from vmware_nsx.db import db as nsx_db from vmware_nsx.db import nsx_models from vmware_nsx.dvs import dvs -from vmware_nsx.nsxlib.v3 import resources from vmware_nsx.plugins.nsx_v3 import plugin from vmware_nsx.services.qos.common import utils as qos_utils from vmware_nsx.shell.admin.plugins.common import constants @@ -31,6 +30,7 @@ from vmware_nsx.shell.admin.plugins.common import formatters from vmware_nsx.shell.admin.plugins.common import utils as admin_utils from vmware_nsx.shell.admin.plugins.nsxv3.resources import utils as v3_utils from vmware_nsx.shell import resources as shell +from vmware_nsxlib.v3 import resources from neutron.callbacks import registry from neutron import context as neutron_context diff --git a/vmware_nsx/shell/admin/plugins/nsxv3/resources/routers.py b/vmware_nsx/shell/admin/plugins/nsxv3/resources/routers.py index 59a3e2d6fd..59c565d33a 100644 --- a/vmware_nsx/shell/admin/plugins/nsxv3/resources/routers.py +++ b/vmware_nsx/shell/admin/plugins/nsxv3/resources/routers.py @@ -18,12 +18,12 @@ import logging from vmware_nsx._i18n import _LI from vmware_nsx.common import exceptions as nsx_exc from vmware_nsx.db import db as nsx_db -from vmware_nsx.nsxlib.v3 import resources as nsx_resources from vmware_nsx.shell.admin.plugins.common import constants from vmware_nsx.shell.admin.plugins.common import formatters from vmware_nsx.shell.admin.plugins.common import utils as admin_utils from vmware_nsx.shell.admin.plugins.nsxv3.resources import utils from vmware_nsx.shell import resources as shell +from vmware_nsxlib.v3 import resources as nsx_resources from neutron.callbacks import registry from neutron import context as neutron_context diff --git a/vmware_nsx/shell/admin/plugins/nsxv3/resources/securitygroups.py b/vmware_nsx/shell/admin/plugins/nsxv3/resources/securitygroups.py index 83e1f186e5..f73516218b 100644 --- a/vmware_nsx/shell/admin/plugins/nsxv3/resources/securitygroups.py +++ b/vmware_nsx/shell/admin/plugins/nsxv3/resources/securitygroups.py @@ -32,9 +32,9 @@ from vmware_nsx.shell.admin.plugins.nsxv3.resources import ports from vmware_nsx.shell.admin.plugins.nsxv3.resources import utils as v3_utils from vmware_nsx.shell import resources as shell from vmware_nsx._i18n import _LE, _LW -from vmware_nsx.nsxlib.v3 import nsx_constants as consts -from vmware_nsx.nsxlib.v3 import security -from vmware_nsx.nsxlib.v3 import utils as nsxlib_utils +from vmware_nsxlib.v3 import nsx_constants as consts +from vmware_nsxlib.v3 import security +from vmware_nsxlib.v3 import utils as nsxlib_utils LOG = logging.getLogger(__name__) diff --git a/vmware_nsx/shell/admin/plugins/nsxv3/resources/utils.py b/vmware_nsx/shell/admin/plugins/nsxv3/resources/utils.py index 29e6436b2d..8149beed8e 100644 --- a/vmware_nsx/shell/admin/plugins/nsxv3/resources/utils.py +++ b/vmware_nsx/shell/admin/plugins/nsxv3/resources/utils.py @@ -17,9 +17,9 @@ from neutron import context from neutron.db import db_base_plugin_v2 from vmware_nsx.db import db as nsx_db -from vmware_nsx.nsxlib.v3 import nsx_constants from vmware_nsx.plugins.nsx_v3 import plugin from vmware_nsx.plugins.nsx_v3 import utils as v3_utils +from vmware_nsxlib.v3 import nsx_constants def get_nsxv3_client(): diff --git a/vmware_nsx/tests/unit/extensions/test_secgroup_rule_local_ip_prefix.py b/vmware_nsx/tests/unit/extensions/test_secgroup_rule_local_ip_prefix.py index b4dcaac933..310964c43f 100644 --- a/vmware_nsx/tests/unit/extensions/test_secgroup_rule_local_ip_prefix.py +++ b/vmware_nsx/tests/unit/extensions/test_secgroup_rule_local_ip_prefix.py @@ -137,7 +137,7 @@ class TestNSXv3ExtendedSGRule(test_nsxv3_plugin.NsxV3PluginTestCaseMixin, 'description': ''}] with mock.patch( - "vmware_nsx.nsxlib.v3.security.NsxLibFirewallSection.create_rules", + "vmware_nsxlib.v3.security.NsxLibFirewallSection.create_rules", side_effect=test_nsxv3_plugin._mock_create_firewall_rules, ) as mock_rule: diff --git a/vmware_nsx/tests/unit/extensions/test_securitygroup.py b/vmware_nsx/tests/unit/extensions/test_securitygroup.py index d2e99cee04..9366b58f31 100644 --- a/vmware_nsx/tests/unit/extensions/test_securitygroup.py +++ b/vmware_nsx/tests/unit/extensions/test_securitygroup.py @@ -17,12 +17,12 @@ import mock from neutron.extensions import securitygroup as ext_sg from neutron.tests.unit.extensions import test_securitygroup as test_ext_sg -from vmware_nsx.nsxlib.v3 import exceptions as nsxlib_exc -from vmware_nsx.nsxlib.v3 import ns_group_manager -from vmware_nsx.nsxlib.v3 import nsx_constants as consts from vmware_nsx.plugins.nsx_v3 import plugin as nsx_plugin from vmware_nsx.tests.unit.nsx_v3 import test_plugin as test_nsxv3 -from vmware_nsx.tests.unit.nsxlib.v3 import nsxlib_testcase +from vmware_nsxlib.tests.unit.v3 import nsxlib_testcase +from vmware_nsxlib.v3 import exceptions as nsxlib_exc +from vmware_nsxlib.v3 import ns_group_manager +from vmware_nsxlib.v3 import nsx_constants as consts # Pool of fake ns-groups uuids @@ -46,11 +46,11 @@ def _mock_create_and_list_nsgroups(test_method): def wrap(*args, **kwargs): with mock.patch( - 'vmware_nsx.nsxlib.v3.security.NsxLibNsGroup.create' + 'vmware_nsxlib.v3.security.NsxLibNsGroup.create' ) as create_nsgroup_mock: create_nsgroup_mock.side_effect = _create_nsgroup_mock with mock.patch( - "vmware_nsx.nsxlib.v3.security.NsxLibNsGroup.list" + "vmware_nsxlib.v3.security.NsxLibNsGroup.list" ) as list_nsgroups_mock: list_nsgroups_mock.side_effect = lambda: nsgroups test_method(*args, **kwargs) @@ -74,8 +74,8 @@ class TestSecurityGroupsNoDynamicCriteria(test_nsxv3.NsxV3PluginTestCaseMixin, self._patchers.append(mock_nsx_version) @_mock_create_and_list_nsgroups - @mock.patch('vmware_nsx.nsxlib.v3.security.NsxLibNsGroup.remove_member') - @mock.patch('vmware_nsx.nsxlib.v3.security.NsxLibNsGroup.add_members') + @mock.patch('vmware_nsxlib.v3.security.NsxLibNsGroup.remove_member') + @mock.patch('vmware_nsxlib.v3.security.NsxLibNsGroup.add_members') def test_create_port_with_multiple_security_groups(self, add_member_mock, remove_member_mock): @@ -91,8 +91,8 @@ class TestSecurityGroupsNoDynamicCriteria(test_nsxv3.NsxV3PluginTestCaseMixin, add_member_mock.assert_has_calls(calls, any_order=True) @_mock_create_and_list_nsgroups - @mock.patch('vmware_nsx.nsxlib.v3.security.NsxLibNsGroup.remove_member') - @mock.patch('vmware_nsx.nsxlib.v3.security.NsxLibNsGroup.add_members') + @mock.patch('vmware_nsxlib.v3.security.NsxLibNsGroup.remove_member') + @mock.patch('vmware_nsxlib.v3.security.NsxLibNsGroup.add_members') def test_update_port_with_multiple_security_groups(self, add_member_mock, remove_member_mock): @@ -111,8 +111,8 @@ class TestSecurityGroupsNoDynamicCriteria(test_nsxv3.NsxV3PluginTestCaseMixin, NSG_IDS[0], consts.TARGET_TYPE_LOGICAL_PORT, mock.ANY) @_mock_create_and_list_nsgroups - @mock.patch('vmware_nsx.nsxlib.v3.security.NsxLibNsGroup.remove_member') - @mock.patch('vmware_nsx.nsxlib.v3.security.NsxLibNsGroup.add_members') + @mock.patch('vmware_nsxlib.v3.security.NsxLibNsGroup.remove_member') + @mock.patch('vmware_nsxlib.v3.security.NsxLibNsGroup.add_members') def test_update_port_remove_security_group_empty_list(self, add_member_mock, remove_member_mock): @@ -125,7 +125,7 @@ class TestSecurityGroupsNoDynamicCriteria(test_nsxv3.NsxV3PluginTestCaseMixin, NSG_IDS[1], consts.TARGET_TYPE_LOGICAL_PORT, mock.ANY) @_mock_create_and_list_nsgroups - @mock.patch('vmware_nsx.nsxlib.v3.security.NsxLibNsGroup.add_members') + @mock.patch('vmware_nsxlib.v3.security.NsxLibNsGroup.add_members') def test_create_port_with_full_security_group(self, add_member_mock): def _add_member_mock(nsgroup, target_type, target_id): @@ -143,8 +143,8 @@ class TestSecurityGroupsNoDynamicCriteria(test_nsxv3.NsxV3PluginTestCaseMixin, res_body['NeutronError']['type']) @_mock_create_and_list_nsgroups - @mock.patch('vmware_nsx.nsxlib.v3.security.NsxLibNsGroup.remove_member') - @mock.patch('vmware_nsx.nsxlib.v3.security.NsxLibNsGroup.add_members') + @mock.patch('vmware_nsxlib.v3.security.NsxLibNsGroup.remove_member') + @mock.patch('vmware_nsxlib.v3.security.NsxLibNsGroup.add_members') def test_update_port_with_full_security_group(self, add_member_mock, remove_member_mock): @@ -184,7 +184,7 @@ class TestSecurityGroupsNoDynamicCriteria(test_nsxv3.NsxV3PluginTestCaseMixin, class TestNSGroupManager(nsxlib_testcase.NsxLibTestCase): """ This test suite is responsible for unittesting of class - vmware_nsx.nsxlib.v3.ns_group_manager.NSGroupManager. + vmware_nsxlib.v3.ns_group_manager.NSGroupManager. """ @_mock_create_and_list_nsgroups @@ -214,8 +214,8 @@ class TestNSGroupManager(nsxlib_testcase.NsxLibTestCase): nested_groups) @_mock_create_and_list_nsgroups - @mock.patch('vmware_nsx.nsxlib.v3.security.NsxLibNsGroup.remove_member') - @mock.patch('vmware_nsx.nsxlib.v3.security.NsxLibNsGroup.add_members') + @mock.patch('vmware_nsxlib.v3.security.NsxLibNsGroup.remove_member') + @mock.patch('vmware_nsxlib.v3.security.NsxLibNsGroup.add_members') def test_add_and_remove_nsgroups(self, add_member_mock, remove_member_mock): @@ -239,8 +239,8 @@ class TestNSGroupManager(nsxlib_testcase.NsxLibTestCase): verify=True) @_mock_create_and_list_nsgroups - @mock.patch('vmware_nsx.nsxlib.v3.security.NsxLibNsGroup.remove_member') - @mock.patch('vmware_nsx.nsxlib.v3.security.NsxLibNsGroup.add_members') + @mock.patch('vmware_nsxlib.v3.security.NsxLibNsGroup.remove_member') + @mock.patch('vmware_nsxlib.v3.security.NsxLibNsGroup.add_members') def test_when_nested_group_is_full(self, add_member_mock, remove_member_mock): @@ -287,8 +287,8 @@ class TestNSGroupManager(nsxlib_testcase.NsxLibTestCase): remove_member_mock.assert_has_calls(calls) @_mock_create_and_list_nsgroups - @mock.patch('vmware_nsx.nsxlib.v3.security.NsxLibNsGroup.remove_member') - @mock.patch('vmware_nsx.nsxlib.v3.security.NsxLibNsGroup.add_members') + @mock.patch('vmware_nsxlib.v3.security.NsxLibNsGroup.remove_member') + @mock.patch('vmware_nsxlib.v3.security.NsxLibNsGroup.add_members') def test_initialize_with_absent_nested_groups(self, add_member_mock, remove_member_mock): @@ -296,7 +296,7 @@ class TestNSGroupManager(nsxlib_testcase.NsxLibTestCase): cont_manager = ns_group_manager.NSGroupManager(self.nsxlib, size) # list_nsgroups will return nested group 1 and 3, but not group 2. nsgroups = cont_manager.nsxlib_nsgroup.list() - with mock.patch("vmware_nsx.nsxlib.v3.security.NsxLibNsGroup.list", + with mock.patch("vmware_nsxlib.v3.security.NsxLibNsGroup.list", side_effect=lambda: nsgroups[::2]): # invoking the initialization process again, it should process # groups 1 and 3 and create group 2. diff --git a/vmware_nsx/tests/unit/nsx_v3/test_dhcp_metadata.py b/vmware_nsx/tests/unit/nsx_v3/test_dhcp_metadata.py index abd83a8b97..85b34f1f58 100644 --- a/vmware_nsx/tests/unit/nsx_v3/test_dhcp_metadata.py +++ b/vmware_nsx/tests/unit/nsx_v3/test_dhcp_metadata.py @@ -28,9 +28,9 @@ from vmware_nsx.common import exceptions as nsx_exc from vmware_nsx.common import utils from vmware_nsx.db import db as nsx_db from vmware_nsx.extensions import advancedserviceproviders as as_providers -from vmware_nsx.nsxlib.v3 import nsx_constants -from vmware_nsx.nsxlib.v3 import resources as nsx_resources from vmware_nsx.tests.unit.nsx_v3 import test_plugin +from vmware_nsxlib.v3 import nsx_constants +from vmware_nsxlib.v3 import resources as nsx_resources class NsxNativeDhcpTestCase(test_plugin.NsxV3PluginTestCaseMixin): @@ -95,7 +95,7 @@ class NsxNativeDhcpTestCase(test_plugin.NsxV3PluginTestCaseMixin): # Verify if DHCP binding is updated. with mock.patch( - 'vmware_nsx.nsxlib.v3.resources.LogicalDhcpServer.update_binding' + 'vmware_nsxlib.v3.resources.LogicalDhcpServer.update_binding' ) as update_dhcp_binding: device_owner = constants.DEVICE_OWNER_COMPUTE_PREFIX + 'None' device_id = uuidutils.generate_uuid() diff --git a/vmware_nsx/tests/unit/nsx_v3/test_plugin.py b/vmware_nsx/tests/unit/nsx_v3/test_plugin.py index 58d5a2d1c1..c18dad0c98 100644 --- a/vmware_nsx/tests/unit/nsx_v3/test_plugin.py +++ b/vmware_nsx/tests/unit/nsx_v3/test_plugin.py @@ -47,8 +47,8 @@ from vmware_nsx.common import utils from vmware_nsx.plugins.nsx_v3 import plugin as nsx_plugin from vmware_nsx.tests import unit as vmware from vmware_nsx.tests.unit.extensions import test_metadata -from vmware_nsx.tests.unit.nsxlib.v3 import mocks as nsx_v3_mocks -from vmware_nsx.tests.unit.nsxlib.v3 import nsxlib_testcase +from vmware_nsxlib.tests.unit.v3 import mocks as nsx_v3_mocks +from vmware_nsxlib.tests.unit.v3 import nsxlib_testcase PLUGIN_NAME = 'vmware_nsx.plugin.NsxV3Plugin' @@ -69,7 +69,7 @@ def _mock_create_firewall_rules(*args): def _mock_nsx_backend_calls(): - mock.patch("vmware_nsx.nsxlib.v3.client.NSX3Client").start() + mock.patch("vmware_nsxlib.v3.client.NSX3Client").start() class FakeProfile(object): profile_id = uuidutils.generate_uuid() @@ -99,47 +99,47 @@ def _mock_nsx_backend_calls(): ).start() mock.patch( - "vmware_nsx.nsxlib.v3.router.RouterLib.validate_tier0").start() + "vmware_nsxlib.v3.router.RouterLib.validate_tier0").start() mock.patch( - "vmware_nsx.nsxlib.v3.resources.SwitchingProfile." + "vmware_nsxlib.v3.resources.SwitchingProfile." "create_port_mirror_profile", side_effect=_return_id_key).start() mock.patch( - "vmware_nsx.nsxlib.v3.NsxLibBridgeCluster.get_id_by_name_or_id", + "vmware_nsxlib.v3.NsxLibBridgeCluster.get_id_by_name_or_id", return_value=uuidutils.generate_uuid()).start() mock.patch( - "vmware_nsx.nsxlib.v3.NsxLibBridgeEndpoint.create", + "vmware_nsxlib.v3.NsxLibBridgeEndpoint.create", side_effect=_return_id_key).start() mock.patch( - "vmware_nsx.nsxlib.v3.NsxLibLogicalSwitch.create", + "vmware_nsxlib.v3.NsxLibLogicalSwitch.create", side_effect=_return_id_key).start() mock.patch( - "vmware_nsx.nsxlib.v3.NsxLibDhcpProfile.get_id_by_name_or_id", + "vmware_nsxlib.v3.NsxLibDhcpProfile.get_id_by_name_or_id", return_value=NSX_DHCP_PROFILE_ID).start() mock.patch( - "vmware_nsx.nsxlib.v3.NsxLibMetadataProxy.get_id_by_name_or_id", + "vmware_nsxlib.v3.NsxLibMetadataProxy.get_id_by_name_or_id", return_value=NSX_METADATA_PROXY_ID).start() mock.patch( - "vmware_nsx.nsxlib.v3.resources.LogicalPort.create", + "vmware_nsxlib.v3.resources.LogicalPort.create", side_effect=_return_id_key).start() mock.patch( - "vmware_nsx.nsxlib.v3.resources.LogicalRouter.create", + "vmware_nsxlib.v3.resources.LogicalRouter.create", side_effect=_return_id_key).start() mock.patch( - "vmware_nsx.nsxlib.v3.resources.LogicalDhcpServer.create", + "vmware_nsxlib.v3.resources.LogicalDhcpServer.create", side_effect=_return_id_key).start() mock.patch( - "vmware_nsx.nsxlib.v3.resources.LogicalDhcpServer.create_binding", + "vmware_nsxlib.v3.resources.LogicalDhcpServer.create_binding", side_effect=_return_id_key).start() diff --git a/vmware_nsx/tests/unit/nsxlib/v3/__init__.py b/vmware_nsx/tests/unit/nsxlib/v3/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/vmware_nsx/tests/unit/nsxlib/v3/mocks.py b/vmware_nsx/tests/unit/nsxlib/v3/mocks.py deleted file mode 100644 index 94f5a00b72..0000000000 --- a/vmware_nsx/tests/unit/nsxlib/v3/mocks.py +++ /dev/null @@ -1,230 +0,0 @@ -# Copyright (c) 2015 VMware, Inc. -# -# 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 requests -import six.moves.urllib.parse as urlparse - -from oslo_serialization import jsonutils -from oslo_utils import uuidutils -from vmware_nsx.nsxlib.v3 import nsx_constants - - -FAKE_NAME = "fake_name" -DEFAULT_TIER0_ROUTER_UUID = "efad0078-9204-4b46-a2d8-d4dd31ed448f" -NSX_BRIDGE_CLUSTER_NAME = 'default bridge cluster' -FAKE_MANAGER = "fake_manager_ip" - - -def make_fake_switch(switch_uuid=None, tz_uuid=None, name=FAKE_NAME): - if not switch_uuid: - switch_uuid = uuidutils.generate_uuid() - if not tz_uuid: - tz_uuid = uuidutils.generate_uuid() - - fake_switch = { - "id": switch_uuid, - "display_name": name, - "resource_type": "LogicalSwitch", - "address_bindings": [], - "transport_zone_id": tz_uuid, - "replication_mode": nsx_constants.MTEP, - "admin_state": nsx_constants.ADMIN_STATE_UP, - "vni": 50056, - "switching_profile_ids": [ - { - "value": "64814784-7896-3901-9741-badeff705639", - "key": "IpDiscoverySwitchingProfile" - }, - { - "value": "fad98876-d7ff-11e4-b9d6-1681e6b88ec1", - "key": "SpoofGuardSwitchingProfile" - }, - { - "value": "93b4b7e8-f116-415d-a50c-3364611b5d09", - "key": "PortMirroringSwitchingProfile" - }, - { - "value": "fbc4fb17-83d9-4b53-a286-ccdf04301888", - "key": "SwitchSecuritySwitchingProfile" - }, - { - "value": "f313290b-eba8-4262-bd93-fab5026e9495", - "key": "QosSwitchingProfile" - } - ], - } - return fake_switch - - -def make_fake_dhcp_profile(): - return {"id": uuidutils.generate_uuid(), - "edge_cluster_id": uuidutils.generate_uuid(), - "edge_cluster_member_indexes": [0, 1]} - - -def make_fake_metadata_proxy(): - return {"id": uuidutils.generate_uuid(), - "metadata_server_url": "http://1.2.3.4", - "secret": "my secret", - "edge_cluster_id": uuidutils.generate_uuid(), - "edge_cluster_member_indexes": [0, 1]} - - -class MockRequestsResponse(object): - def __init__(self, status_code, content=None): - self.status_code = status_code - self.content = content - - def json(self): - return jsonutils.loads(self.content) - - -class MockRequestSessionApi(object): - - def __init__(self): - self._store = {} - - def _format_uri(self, uri): - uri = urlparse.urlparse(uri).path - while uri.endswith('/'): - uri = uri[:-1] - while uri.startswith('/'): - uri = uri[1:] - if not self._is_uuid_uri(uri): - uri = "%s/" % uri - return uri - - def _is_uuid_uri(self, uri): - return uuidutils.is_uuid_like( - urlparse.urlparse(uri).path.split('/')[-1]) - - def _query(self, search_key, copy=True): - items = [] - for uri, obj in self._store.items(): - if uri.startswith(search_key): - items.append(obj.copy() if copy else obj) - return items - - def _build_response(self, url, content=None, - status=requests.codes.ok, **kwargs): - if isinstance(content, list): - content = { - 'result_count': len(content), - 'results': content - } - - if (content is not None and kwargs.get('headers', {}).get( - 'Content-Type') == 'application/json'): - content = jsonutils.dumps(content) - - return MockRequestsResponse(status, content=content) - - def _get_content(self, **kwargs): - content = kwargs.get('data', None) - if content and kwargs.get('headers', {}).get( - 'Content-Type') == 'application/json': - content = jsonutils.loads(content) - return content - - def get(self, url, **kwargs): - url = self._format_uri(url) - - if self._is_uuid_uri(url): - item = self._store.get(url) - code = requests.codes.ok if item else requests.codes.not_found - return self._build_response( - url, content=item, status=code, **kwargs) - - return self._build_response( - url, content=self._query(url), status=requests.codes.ok, **kwargs) - - def _create(self, url, content, **kwargs): - resource_id = content.get('id') - if resource_id and self._store.get("%s%s" % (url, resource_id)): - return self._build_response( - url, content=None, status=requests.codes.bad, **kwargs) - - resource_id = resource_id or uuidutils.generate_uuid() - content['id'] = resource_id - - self._store["%s%s" % (url, resource_id)] = content.copy() - return content - - def post(self, url, **kwargs): - parsed_url = urlparse.urlparse(url) - url = self._format_uri(url) - - if self._is_uuid_uri(url): - if self._store.get(url) is None: - return self._build_response( - url, content=None, status=requests.codes.bad, **kwargs) - - body = self._get_content(**kwargs) - if body is None: - return self._build_response( - url, content=None, status=requests.codes.bad, **kwargs) - - response_content = None - - url_queries = urlparse.parse_qs(parsed_url.query) - if 'create_multiple' in url_queries.get('action', []): - response_content = {} - for resource_name, resource_body in body.items(): - for new_resource in resource_body: - created_resource = self._create( - url, new_resource, **kwargs) - if response_content.get(resource_name, None) is None: - response_content[resource_name] = [] - response_content[resource_name].append(created_resource) - else: - response_content = self._create(url, body, **kwargs) - - if isinstance(response_content, MockRequestsResponse): - return response_content - - return self._build_response( - url, content=response_content, - status=requests.codes.created, **kwargs) - - def put(self, url, **kwargs): - url = self._format_uri(url) - - item = {} - if self._is_uuid_uri(url): - item = self._store.get(url, None) - if item is None: - return self._build_response( - url, content=None, - status=requests.codes.not_found, **kwargs) - - body = self._get_content(**kwargs) - if body is None: - return self._build_response( - url, content=None, status=requests.codes.bad, **kwargs) - - item.update(body) - self._store[url] = item - return self._build_response( - url, content=item, status=requests.codes.ok, **kwargs) - - def delete(self, url, **kwargs): - url = self._format_uri(url) - - if not self._store.get(url): - return self._build_response( - url, content=None, status=requests.codes.not_found, **kwargs) - - del self._store[url] - return self._build_response( - url, content=None, status=requests.codes.ok, **kwargs) diff --git a/vmware_nsx/tests/unit/nsxlib/v3/nsxlib_testcase.py b/vmware_nsx/tests/unit/nsxlib/v3/nsxlib_testcase.py deleted file mode 100644 index 655834a75e..0000000000 --- a/vmware_nsx/tests/unit/nsxlib/v3/nsxlib_testcase.py +++ /dev/null @@ -1,322 +0,0 @@ -# Copyright (c) 2015 VMware, Inc. -# -# 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 -import mock -import unittest - -from oslo_utils import uuidutils -from requests import exceptions as requests_exceptions - -from vmware_nsx.nsxlib import v3 -from vmware_nsx.nsxlib.v3 import client as nsx_client -from vmware_nsx.nsxlib.v3 import cluster as nsx_cluster -from vmware_nsx.nsxlib.v3 import config - -NSX_USER = 'admin' -NSX_PASSWORD = 'default' -NSX_MANAGER = '1.2.3.4' -NSX_INSECURE = False -NSX_CERT = '/opt/stack/certs/nsx.pem' -NSX_HTTP_RETRIES = 10 -NSX_HTTP_TIMEOUT = 10 -NSX_HTTP_READ_TIMEOUT = 180 -NSX_CONCURENT_CONN = 10 -NSX_CONN_IDLE_TIME = 10 -NSX_MAX_ATTEMPTS = 10 - -PLUGIN_SCOPE = "plugin scope" -PLUGIN_TAG = "plugin tag" -PLUGIN_VER = "plugin ver" - - -def _mock_nsxlib(): - def _return_id_key(*args, **kwargs): - return {'id': uuidutils.generate_uuid()} - - def _mock_add_rules_in_section(*args): - # NOTE(arosen): the code in the neutron plugin expects the - # neutron rule id as the display_name. - rules = args[0] - return { - 'rules': [ - {'display_name': rule['display_name'], - 'id': uuidutils.generate_uuid()} - for rule in rules - ]} - - mock.patch( - "vmware_nsx.nsxlib.v3.cluster.NSXRequestsHTTPProvider" - ".validate_connection").start() - - mock.patch( - "vmware_nsx.nsxlib.v3.security.NsxLibNsGroup.create", - side_effect=_return_id_key - ).start() - - mock.patch( - "vmware_nsx.nsxlib.v3.security.NsxLibFirewallSection.create_empty", - side_effect=_return_id_key).start() - - mock.patch( - "vmware_nsx.nsxlib.v3.security.NsxLibFirewallSection.init_default", - side_effect=_return_id_key).start() - - mock.patch( - "vmware_nsx.nsxlib.v3.security.NsxLibNsGroup.list").start() - - mock.patch( - "vmware_nsx.nsxlib.v3.security.NsxLibFirewallSection.add_rules", - side_effect=_mock_add_rules_in_section).start() - - mock.patch( - "vmware_nsx.nsxlib.v3.NsxLibTransportZone.get_id_by_name_or_id", - side_effect=_return_id_key).start() - - mock.patch( - "vmware_nsx.nsxlib.v3.NsxLib.get_version", - return_value='1.1.0').start() - - -def get_default_nsxlib_config(): - return config.NsxLibConfig( - username=NSX_USER, - password=NSX_PASSWORD, - retries=NSX_HTTP_RETRIES, - insecure=NSX_INSECURE, - ca_file=NSX_CERT, - concurrent_connections=NSX_CONCURENT_CONN, - http_timeout=NSX_HTTP_TIMEOUT, - http_read_timeout=NSX_HTTP_READ_TIMEOUT, - conn_idle_timeout=NSX_CONN_IDLE_TIME, - http_provider=None, - nsx_api_managers=[], - plugin_scope=PLUGIN_SCOPE, - plugin_tag=PLUGIN_TAG, - plugin_ver=PLUGIN_VER) - - -class NsxLibTestCase(unittest.TestCase): - - def setUp(self, *args, **kwargs): - super(NsxLibTestCase, self).setUp() - _mock_nsxlib() - - nsxlib_config = get_default_nsxlib_config() - self.nsxlib = v3.NsxLib(nsxlib_config) - - # print diffs when assert comparisons fail - self.maxDiff = None - - -class MemoryMockAPIProvider(nsx_cluster.AbstractHTTPProvider): - """Acts as a HTTP provider for mocking which is backed - by a MockRequestSessionApi. - """ - - def __init__(self, mock_session_api): - self._store = mock_session_api - - @property - def provider_id(self): - return "Memory mock API" - - def validate_connection(self, cluster_api, endpoint, conn): - return - - def new_connection(self, cluster_api, provider): - # all callers use the same backing - return self._store - - def is_connection_exception(self, exception): - return isinstance(exception, requests_exceptions.ConnectionError) - - -class NsxClientTestCase(NsxLibTestCase): - - class MockNSXClusteredAPI(nsx_cluster.NSXClusteredAPI): - - def __init__( - self, session_response=None, - username=None, - password=None, - retries=None, - insecure=None, - ca_file=None, - concurrent_connections=None, - http_timeout=None, - http_read_timeout=None, - conn_idle_timeout=None, - nsx_api_managers=None): - - nsxlib_config = config.NsxLibConfig( - username=username or NSX_USER, - password=password or NSX_PASSWORD, - retries=retries or NSX_HTTP_RETRIES, - insecure=insecure if insecure is not None else NSX_INSECURE, - ca_file=ca_file or NSX_CERT, - concurrent_connections=(concurrent_connections or - NSX_CONCURENT_CONN), - http_timeout=http_timeout or NSX_HTTP_TIMEOUT, - http_read_timeout=http_read_timeout or NSX_HTTP_READ_TIMEOUT, - conn_idle_timeout=conn_idle_timeout or NSX_CONN_IDLE_TIME, - http_provider=NsxClientTestCase.MockHTTPProvider( - session_response=session_response), - nsx_api_managers=nsx_api_managers or [NSX_MANAGER], - plugin_scope=PLUGIN_SCOPE, - plugin_tag=PLUGIN_TAG, - plugin_ver=PLUGIN_VER) - - super(NsxClientTestCase.MockNSXClusteredAPI, self).__init__( - nsxlib_config) - self._record = mock.Mock() - - def record_call(self, request, **kwargs): - verb = request.method.lower() - - # filter out requests specific attributes - checked_kwargs = copy.copy(kwargs) - del checked_kwargs['proxies'] - del checked_kwargs['stream'] - if 'allow_redirects' in checked_kwargs: - del checked_kwargs['allow_redirects'] - - for attr in ['url', 'body']: - checked_kwargs[attr] = getattr(request, attr, None) - - # remove headers we don't need to verify - checked_kwargs['headers'] = copy.copy(request.headers) - for header in ['Accept-Encoding', 'User-Agent', - 'Connection', 'Authorization', - 'Content-Length']: - if header in checked_kwargs['headers']: - del checked_kwargs['headers'][header] - - checked_kwargs['headers'] = request.headers - - # record the call in the mock object - method = getattr(self._record, verb) - method(**checked_kwargs) - - def assert_called_once(self, verb, **kwargs): - mock_call = getattr(self._record, verb.lower()) - mock_call.assert_called_once_with(**kwargs) - - @property - def recorded_calls(self): - return self._record - - class MockHTTPProvider(nsx_cluster.NSXRequestsHTTPProvider): - - def __init__(self, session_response=None): - super(NsxClientTestCase.MockHTTPProvider, self).__init__() - self._session_response = session_response - - def new_connection(self, cluster_api, provider): - # wrapper the session so we can intercept and record calls - session = super(NsxClientTestCase.MockHTTPProvider, - self).new_connection(cluster_api, provider) - - mock_adapter = mock.Mock() - session_send = session.send - - def _adapter_send(request, **kwargs): - # record calls at the requests HTTP adapter level - mock_response = mock.Mock() - mock_response.history = None - # needed to bypass requests internal checks for mock - mock_response.raw._original_response = {} - - # record the request for later verification - cluster_api.record_call(request, **kwargs) - return mock_response - - def _session_send(request, **kwargs): - # calls at the Session level - if self._session_response: - # consumer has setup a response for the session - cluster_api.record_call(request, **kwargs) - return (self._session_response() - if hasattr(self._session_response, '__call__') - else self._session_response) - - # bypass requests redirect handling for mock - kwargs['allow_redirects'] = False - - # session send will end up calling adapter send - return session_send(request, **kwargs) - - mock_adapter.send = _adapter_send - session.send = _session_send - - def _mock_adapter(*args, **kwargs): - # use our mock adapter rather than requests adapter - return mock_adapter - - session.get_adapter = _mock_adapter - return session - - def validate_connection(self, cluster_api, endpoint, conn): - assert conn is not None - - def mock_nsx_clustered_api(self, session_response=None, **kwargs): - return NsxClientTestCase.MockNSXClusteredAPI( - session_response=session_response, **kwargs) - - def mocked_resource(self, resource_class, mock_validate=True, - session_response=None): - mocked = resource_class(nsx_client.NSX3Client( - self.mock_nsx_clustered_api(session_response=session_response), - nsx_api_managers=[NSX_MANAGER], - max_attempts=NSX_MAX_ATTEMPTS)) - if mock_validate: - mock.patch.object(mocked._client, '_validate_result').start() - - return mocked - - def new_mocked_client(self, client_class, mock_validate=True, - session_response=None, mock_cluster=None, - **kwargs): - client = client_class(mock_cluster or self.mock_nsx_clustered_api( - session_response=session_response), **kwargs) - - if mock_validate: - mock.patch.object(client, '_validate_result').start() - - new_client_for = client.new_client_for - - def _new_client_for(*args, **kwargs): - sub_client = new_client_for(*args, **kwargs) - if mock_validate: - mock.patch.object(sub_client, '_validate_result').start() - return sub_client - - client.new_client_for = _new_client_for - - return client - - def new_mocked_cluster(self, conf_managers, validate_conn_func, - concurrent_connections=None): - mock_provider = mock.Mock() - mock_provider.default_scheme = 'https' - mock_provider.validate_connection = validate_conn_func - - nsxlib_config = get_default_nsxlib_config() - if concurrent_connections: - nsxlib_config.concurrent_connections = concurrent_connections - nsxlib_config.http_provider = mock_provider - nsxlib_config.nsx_api_managers = conf_managers - - return nsx_cluster.NSXClusteredAPI(nsxlib_config) diff --git a/vmware_nsx/tests/unit/nsxlib/v3/test_client.py b/vmware_nsx/tests/unit/nsxlib/v3/test_client.py deleted file mode 100644 index 25c2dffdb4..0000000000 --- a/vmware_nsx/tests/unit/nsxlib/v3/test_client.py +++ /dev/null @@ -1,308 +0,0 @@ -# Copyright 2015 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. -# -import copy - -from oslo_log import log -from oslo_serialization import jsonutils - -from vmware_nsx.nsxlib.v3 import client -from vmware_nsx.nsxlib.v3 import exceptions as nsxlib_exc -from vmware_nsx.tests.unit.nsxlib.v3 import mocks -from vmware_nsx.tests.unit.nsxlib.v3 import nsxlib_testcase - - -LOG = log.getLogger(__name__) - -CLIENT_PKG = 'vmware_nsx.nsxlib.v3.client' - -DFT_ACCEPT_HEADERS = { - 'Accept': '*/*' -} - - -def _headers(**kwargs): - headers = copy.copy(DFT_ACCEPT_HEADERS) - headers.update(kwargs) - return headers - - -def assert_call(verb, client_or_resource, - url, verify=nsxlib_testcase.NSX_CERT, - data=None, headers=DFT_ACCEPT_HEADERS, - timeout=(nsxlib_testcase.NSX_HTTP_TIMEOUT, - nsxlib_testcase.NSX_HTTP_READ_TIMEOUT)): - nsx_client = client_or_resource - if getattr(nsx_client, '_client', None) is not None: - nsx_client = nsx_client._client - cluster = nsx_client._conn - cluster.assert_called_once( - verb, - **{'url': url, 'verify': verify, 'body': data, - 'headers': headers, 'cert': None, 'timeout': timeout}) - - -def assert_json_call(verb, client_or_resource, url, - verify=nsxlib_testcase.NSX_CERT, - data=None, - headers=client.JSONRESTClient._DEFAULT_HEADERS): - return assert_call(verb, client_or_resource, url, - verify=verify, data=data, - headers=headers) - - -class NsxV3RESTClientTestCase(nsxlib_testcase.NsxClientTestCase): - - def test_client_url_prefix(self): - api = self.new_mocked_client(client.RESTClient, - url_prefix='/cloud/api') - - api.list() - - assert_call( - 'get', api, - 'https://1.2.3.4/cloud/api') - - api = self.new_mocked_client(client.RESTClient, - url_prefix='/cloud/api') - - api.url_list('v1/ports') - - assert_call( - 'get', api, - 'https://1.2.3.4/cloud/api/v1/ports') - - def test_client_headers(self): - default_headers = {'Content-Type': 'application/golang'} - api = self.new_mocked_client( - client.RESTClient, default_headers=default_headers, - url_prefix='/v1/api') - - api.list() - - assert_call( - 'get', api, - 'https://1.2.3.4/v1/api', - headers=_headers(**default_headers)) - - api = self.new_mocked_client( - client.RESTClient, - default_headers=default_headers, - url_prefix='/v1/api') - - method_headers = {'X-API-Key': 'strong-crypt'} - api.url_list('ports/33', headers=method_headers) - method_headers.update(default_headers) - assert_call( - 'get', api, - 'https://1.2.3.4/v1/api/ports/33', - headers=_headers(**method_headers)) - - def test_client_for(self): - api = self.new_mocked_client(client.RESTClient, url_prefix='api/v1/') - sub_api = api.new_client_for('switch/ports') - - sub_api.get('11a2b') - - assert_call( - 'get', sub_api, - 'https://1.2.3.4/api/v1/switch/ports/11a2b') - - def test_client_list(self): - api = self.new_mocked_client(client.RESTClient, - url_prefix='api/v1/ports') - api.list() - - assert_call( - 'get', api, - 'https://1.2.3.4/api/v1/ports') - - def test_client_get(self): - api = self.new_mocked_client(client.RESTClient, - url_prefix='api/v1/ports') - api.get('unique-id') - - assert_call( - 'get', api, - 'https://1.2.3.4/api/v1/ports/unique-id') - - def test_client_delete(self): - api = self.new_mocked_client(client.RESTClient, - url_prefix='api/v1/ports') - api.delete('unique-id') - - assert_call( - 'delete', api, - 'https://1.2.3.4/api/v1/ports/unique-id') - - def test_client_update(self): - api = self.new_mocked_client(client.RESTClient, - url_prefix='api/v1/ports') - api.update('unique-id', jsonutils.dumps({'name': 'a-new-name'})) - - assert_call( - 'put', api, - 'https://1.2.3.4/api/v1/ports/unique-id', - data=jsonutils.dumps({'name': 'a-new-name'})) - - def test_client_create(self): - api = self.new_mocked_client(client.RESTClient, - url_prefix='api/v1/ports') - api.create(body=jsonutils.dumps({'resource-name': 'port1'})) - - assert_call( - 'post', api, - 'https://1.2.3.4/api/v1/ports', - data=jsonutils.dumps({'resource-name': 'port1'})) - - def test_client_url_list(self): - api = self.new_mocked_client(client.RESTClient, - url_prefix='api/v1/ports') - - json_headers = {'Content-Type': 'application/json'} - - api.url_list('/connections', json_headers) - - assert_call( - 'get', api, - 'https://1.2.3.4/api/v1/ports/connections', - headers=_headers(**json_headers)) - - def test_client_url_get(self): - api = self.new_mocked_client(client.RESTClient, - url_prefix='api/v1/ports') - api.url_get('connections/1') - - assert_call( - 'get', api, - 'https://1.2.3.4/api/v1/ports/connections/1') - - def test_client_url_delete(self): - api = self.new_mocked_client(client.RESTClient, - url_prefix='api/v1/ports') - api.url_delete('1') - - assert_call( - 'delete', api, - 'https://1.2.3.4/api/v1/ports/1') - - def test_client_url_put(self): - api = self.new_mocked_client(client.RESTClient, - url_prefix='api/v1/ports') - api.url_put('connections/1', jsonutils.dumps({'name': 'conn1'})) - - assert_call( - 'put', api, - 'https://1.2.3.4/api/v1/ports/connections/1', - data=jsonutils.dumps({'name': 'conn1'})) - - def test_client_url_post(self): - api = self.new_mocked_client(client.RESTClient, - url_prefix='api/v1/ports') - api.url_post('1/connections', jsonutils.dumps({'name': 'conn1'})) - - assert_call( - 'post', api, - 'https://1.2.3.4/api/v1/ports/1/connections', - data=jsonutils.dumps({'name': 'conn1'})) - - def test_client_validate_result(self): - - def _verb_response_code(http_verb, status_code): - response = mocks.MockRequestsResponse( - status_code, None) - - client_api = self.new_mocked_client( - client.RESTClient, mock_validate=False, - session_response=response) - - client_call = getattr(client_api, "url_%s" % http_verb) - client_call('', None) - - for verb in ['get', 'post', 'put', 'delete']: - for code in client.RESTClient._VERB_RESP_CODES.get(verb): - _verb_response_code(verb, code) - self.assertRaises( - nsxlib_exc.ManagerError, - _verb_response_code, verb, 500) - - -class NsxV3JSONClientTestCase(nsxlib_testcase.NsxClientTestCase): - - def test_json_request(self): - resp = mocks.MockRequestsResponse( - 200, jsonutils.dumps({'result': {'ok': 200}})) - - api = self.new_mocked_client(client.JSONRESTClient, - session_response=resp, - url_prefix='api/v2/nat') - - resp = api.create(body={'name': 'mgmt-egress'}) - - assert_json_call( - 'post', api, - 'https://1.2.3.4/api/v2/nat', - data=jsonutils.dumps({'name': 'mgmt-egress'})) - - self.assertEqual(resp, {'result': {'ok': 200}}) - - -class NsxV3APIClientTestCase(nsxlib_testcase.NsxClientTestCase): - - def test_api_call(self): - api = self.new_mocked_client(client.NSX3Client) - api.get('ports') - - assert_json_call( - 'get', api, - 'https://1.2.3.4/api/v1/ports') - - -# NOTE(boden): remove this when tmp brigding removed -class NsxV3APIClientBridgeTestCase(nsxlib_testcase.NsxClientTestCase): - - def test_get_resource(self): - api = self.new_mocked_client(client.NSX3Client) - api.get('ports') - - assert_json_call( - 'get', api, - 'https://1.2.3.4/api/v1/ports') - - def test_create_resource(self): - api = self.new_mocked_client(client.NSX3Client) - api.create('ports', {'resource-name': 'port1'}) - - assert_json_call( - 'post', api, - 'https://1.2.3.4/api/v1/ports', - data=jsonutils.dumps({'resource-name': 'port1'})) - - def test_update_resource(self): - api = self.new_mocked_client(client.NSX3Client) - api.update('ports/1', {'name': 'a-new-name'}) - - assert_json_call( - 'put', api, - 'https://1.2.3.4/api/v1/ports/1', - data=jsonutils.dumps({'name': 'a-new-name'})) - - def test_delete_resource(self): - api = self.new_mocked_client(client.NSX3Client) - api.delete('ports/11') - - assert_json_call( - 'delete', api, - 'https://1.2.3.4/api/v1/ports/11') diff --git a/vmware_nsx/tests/unit/nsxlib/v3/test_cluster.py b/vmware_nsx/tests/unit/nsxlib/v3/test_cluster.py deleted file mode 100644 index 252e133e6e..0000000000 --- a/vmware_nsx/tests/unit/nsxlib/v3/test_cluster.py +++ /dev/null @@ -1,204 +0,0 @@ -# Copyright 2015 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. -# -import mock -import six.moves.urllib.parse as urlparse -import unittest - -from oslo_serialization import jsonutils -from requests import exceptions as requests_exceptions -from vmware_nsx.nsxlib.v3 import client -from vmware_nsx.nsxlib.v3 import cluster -from vmware_nsx.nsxlib.v3 import exceptions as nsxlib_exc -from vmware_nsx.tests.unit.nsxlib.v3 import mocks -from vmware_nsx.tests.unit.nsxlib.v3 import nsxlib_testcase - - -def _validate_conn_up(*args, **kwargs): - return - - -def _validate_conn_down(*args, **kwargs): - raise requests_exceptions.ConnectionError() - - -class RequestsHTTPProviderTestCase(unittest.TestCase): - - def test_new_connection(self): - mock_api = mock.Mock() - mock_api.nsxlib_config = mock.Mock() - mock_api.nsxlib_config.username = 'nsxuser' - mock_api.nsxlib_config.password = 'nsxpassword' - mock_api.nsxlib_config.retries = 100 - mock_api.nsxlib_config.insecure = True - mock_api.nsxlib_config.ca_file = None - mock_api.nsxlib_config.http_timeout = 99 - mock_api.nsxlib_config.conn_idle_timeout = 39 - provider = cluster.NSXRequestsHTTPProvider() - session = provider.new_connection( - mock_api, cluster.Provider('9.8.7.6', 'https://9.8.7.6', - 'nsxuser', 'nsxpassword', None)) - - self.assertEqual(session.auth, ('nsxuser', 'nsxpassword')) - self.assertEqual(session.verify, False) - self.assertEqual(session.cert, None) - self.assertEqual(session.adapters['https://'].max_retries.total, 100) - self.assertEqual(session.timeout, 99) - - def test_validate_connection(self): - self.skipTest("Revist") - mock_conn = mocks.MockRequestSessionApi() - mock_ep = mock.Mock() - mock_ep.provider.url = 'https://1.2.3.4' - provider = cluster.NSXRequestsHTTPProvider() - self.assertRaises(nsxlib_exc.ResourceNotFound, - provider.validate_connection, - mock.Mock(), mock_ep, mock_conn) - - mock_conn.post('api/v1/transport-zones', - data=jsonutils.dumps({'id': 'dummy-tz'}), - headers=client.JSONRESTClient._DEFAULT_HEADERS) - provider.validate_connection(mock.Mock(), mock_ep, mock_conn) - - -class NsxV3ClusteredAPITestCase(nsxlib_testcase.NsxClientTestCase): - - def _assert_providers(self, cluster_api, provider_tuples): - self.assertEqual(len(cluster_api.providers), len(provider_tuples)) - - def _assert_provider(pid, purl): - for provider in cluster_api.providers: - if provider.id == pid and provider.url == purl: - return - self.fail("Provider: %s not found" % pid) - - for provider_tuple in provider_tuples: - _assert_provider(provider_tuple[0], provider_tuple[1]) - - def test_conf_providers_no_scheme(self): - conf_managers = ['8.9.10.11', '9.10.11.12:4433'] - api = self.new_mocked_cluster(conf_managers, _validate_conn_up) - - self._assert_providers( - api, [(p, "https://%s" % p) for p in conf_managers]) - - def test_conf_providers_with_scheme(self): - conf_managers = ['http://8.9.10.11:8080', 'https://9.10.11.12:4433'] - api = self.new_mocked_cluster(conf_managers, _validate_conn_up) - - self._assert_providers( - api, [(urlparse.urlparse(p).netloc, p) for p in conf_managers]) - - def test_http_retries(self): - api = self.mock_nsx_clustered_api(retries=9) - with api.endpoints['1.2.3.4'].pool.item() as session: - self.assertEqual( - session.adapters['https://'].max_retries.total, 9) - - def test_conns_per_pool(self): - conf_managers = ['8.9.10.11', '9.10.11.12:4433'] - api = self.new_mocked_cluster( - conf_managers, _validate_conn_up, - concurrent_connections=11) - - for ep_id, ep in api.endpoints.items(): - self.assertEqual(ep.pool.max_size, 11) - - def test_timeouts(self): - api = self.mock_nsx_clustered_api(http_read_timeout=37, http_timeout=7) - api.get('logical-ports') - mock_call = api.recorded_calls.method_calls[0] - name, args, kwargs = mock_call - self.assertEqual(kwargs['timeout'], (7, 37)) - - -class ClusteredAPITestCase(nsxlib_testcase.NsxClientTestCase): - - def _test_health(self, validate_fn, expected_health): - conf_managers = ['8.9.10.11', '9.10.11.12'] - api = self.new_mocked_cluster(conf_managers, validate_fn) - - self.assertEqual(api.health, expected_health) - - def test_orange_health(self): - - def _validate(cluster_api, endpoint, conn): - if endpoint.provider.id == '8.9.10.11': - raise Exception() - - self._test_health(_validate, cluster.ClusterHealth.ORANGE) - - def test_green_health(self): - self._test_health(_validate_conn_up, cluster.ClusterHealth.GREEN) - - def test_red_health(self): - self._test_health(_validate_conn_down, cluster.ClusterHealth.RED) - - def test_cluster_validate_with_exception(self): - conf_managers = ['8.9.10.11', '9.10.11.12', '10.11.12.13'] - api = self.new_mocked_cluster(conf_managers, _validate_conn_down) - - self.assertEqual(len(api.endpoints), 3) - self.assertRaises(nsxlib_exc.ServiceClusterUnavailable, - api.get, 'api/v1/transport-zones') - - def test_cluster_proxy_stale_revision(self): - - def stale_revision(): - raise nsxlib_exc.StaleRevision(manager='1.1.1.1', - operation='whatever') - - api = self.mock_nsx_clustered_api(session_response=stale_revision) - self.assertRaises(nsxlib_exc.StaleRevision, - api.get, 'api/v1/transport-zones') - - def test_cluster_proxy_connection_error(self): - - def connect_timeout(): - raise requests_exceptions.ConnectTimeout() - - api = self.mock_nsx_clustered_api(session_response=connect_timeout) - api._validate = mock.Mock() - self.assertRaises(nsxlib_exc.ServiceClusterUnavailable, - api.get, 'api/v1/transport-zones') - - def test_cluster_round_robin_servicing(self): - conf_managers = ['8.9.10.11', '9.10.11.12', '10.11.12.13'] - api = self.mock_nsx_clustered_api(nsx_api_managers=conf_managers) - api._validate = mock.Mock() - - eps = list(api._endpoints.values()) - - def _get_schedule(num_eps): - return [api._select_endpoint() for i in range(num_eps)] - - self.assertEqual(_get_schedule(3), eps) - - self.assertEqual(_get_schedule(6), [eps[0], eps[1], eps[2], - eps[0], eps[1], eps[2]]) - - eps[0]._state = cluster.EndpointState.DOWN - self.assertEqual(_get_schedule(4), [eps[1], eps[2], eps[1], eps[2]]) - - eps[1]._state = cluster.EndpointState.DOWN - self.assertEqual(_get_schedule(2), [eps[2], eps[2]]) - - eps[0]._state = cluster.EndpointState.UP - self.assertEqual(_get_schedule(4), [eps[0], eps[2], eps[0], eps[2]]) - - def test_reinitialize_cluster(self): - api = self.mock_nsx_clustered_api() - # just make sure this api is defined, and does not crash - api._reinit_cluster() diff --git a/vmware_nsx/tests/unit/nsxlib/v3/test_constants.py b/vmware_nsx/tests/unit/nsxlib/v3/test_constants.py deleted file mode 100644 index b51c8dfdcc..0000000000 --- a/vmware_nsx/tests/unit/nsxlib/v3/test_constants.py +++ /dev/null @@ -1,162 +0,0 @@ -# Copyright (c) 2016 VMware, Inc. -# -# 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_utils import uuidutils - -FAKE_NAME = "fake_name" -FAKE_SWITCH_UUID = uuidutils.generate_uuid() - -FAKE_PORT_UUID = uuidutils.generate_uuid() -FAKE_PORT = { - "id": FAKE_PORT_UUID, - "display_name": FAKE_NAME, - "resource_type": "LogicalPort", - "address_bindings": [], - "logical_switch_id": FAKE_SWITCH_UUID, - "admin_state": "UP", - "attachment": { - "id": "9ca8d413-f7bf-4276-b4c9-62f42516bdb2", - "attachment_type": "VIF" - }, - "switching_profile_ids": [ - { - "value": "64814784-7896-3901-9741-badeff705639", - "key": "IpDiscoverySwitchingProfile" - }, - { - "value": "fad98876-d7ff-11e4-b9d6-1681e6b88ec1", - "key": "SpoofGuardSwitchingProfile" - }, - { - "value": "93b4b7e8-f116-415d-a50c-3364611b5d09", - "key": "PortMirroringSwitchingProfile" - }, - { - "value": "fbc4fb17-83d9-4b53-a286-ccdf04301888", - "key": "SwitchSecuritySwitchingProfile" - }, - { - "value": "f313290b-eba8-4262-bd93-fab5026e9495", - "key": "QosSwitchingProfile" - } - ] -} - -FAKE_CONTAINER_PORT = { - "id": FAKE_PORT_UUID, - "display_name": FAKE_NAME, - "resource_type": "LogicalPort", - "address_bindings": [ - { - "ip_address": "192.168.1.110", - "mac_address": "aa:bb:cc:dd:ee:ff" - } - ], - "logical_switch_id": FAKE_SWITCH_UUID, - "admin_state": "UP", - "attachment": { - "id": "9ca8d413-f7bf-4276-b4c9-62f42516bdb2", - "attachment_type": "CIF", - "context": { - "vlan_tag": 122, - "container_host_vif_id": "c6f817a0-4e36-421e-98a6-8a2faed880bc", - "key_values": [], - "resource_type": "CifAttachmentContext", - } - }, - "switching_profile_ids": [ - { - "value": "64814784-7896-3901-9741-badeff705639", - "key": "IpDiscoverySwitchingProfile" - }, - { - "value": "fad98876-d7ff-11e4-b9d6-1681e6b88ec1", - "key": "SpoofGuardSwitchingProfile" - }, - { - "value": "93b4b7e8-f116-415d-a50c-3364611b5d09", - "key": "PortMirroringSwitchingProfile" - }, - { - "value": "fbc4fb17-83d9-4b53-a286-ccdf04301888", - "key": "SwitchSecuritySwitchingProfile" - }, - { - "value": "f313290b-eba8-4262-bd93-fab5026e9495", - "key": "QosSwitchingProfile" - } - ] -} - - -FAKE_ROUTER_UUID = uuidutils.generate_uuid() -FAKE_ROUTER = { - "resource_type": "LogicalRouter", - "revision": 0, - "id": FAKE_ROUTER_UUID, - "display_name": FAKE_NAME -} - -FAKE_ROUTER_PORT_UUID = uuidutils.generate_uuid() -FAKE_ROUTER_PORT = { - "resource_type": "LogicalRouterLinkPort", - "revision": 0, - "id": FAKE_ROUTER_PORT_UUID, - "display_name": FAKE_NAME, - "logical_router_id": FAKE_ROUTER_UUID -} - -FAKE_QOS_PROFILE = { - "resource_type": "QosSwitchingProfile", - "id": uuidutils.generate_uuid(), - "display_name": FAKE_NAME, - "system_defined": False, - "dscp": { - "priority": 25, - "mode": "UNTRUSTED" - }, - "tags": [], - "description": FAKE_NAME, - "class_of_service": 0, - "shaper_configuration": [ - { - "resource_type": "IngressRateShaper", - "enabled": False, - "peak_bandwidth_mbps": 0, - "burst_size_bytes": 0, - "average_bandwidth_mbps": 0 - }, - { - "resource_type": "IngressBroadcastRateShaper", - "enabled": False, - "peak_bandwidth_kbps": 0, - "average_bandwidth_kbps": 0, - "burst_size_bytes": 0 - }, - { - "resource_type": "EgressRateShaper", - "enabled": False, - "peak_bandwidth_mbps": 0, - "burst_size_bytes": 0, - "average_bandwidth_mbps": 0 - } - ], - "_last_modified_user": "admin", - "_last_modified_time": 1438383180608, - "_create_time": 1438383180608, - "_create_user": "admin", - "_revision": 0 -} diff --git a/vmware_nsx/tests/unit/nsxlib/v3/test_qos_switching_profile.py b/vmware_nsx/tests/unit/nsxlib/v3/test_qos_switching_profile.py deleted file mode 100644 index e109517f62..0000000000 --- a/vmware_nsx/tests/unit/nsxlib/v3/test_qos_switching_profile.py +++ /dev/null @@ -1,177 +0,0 @@ -# Copyright (c) 2015 VMware, Inc. -# -# 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 mock - -from oslo_log import log - -from vmware_nsx.tests.unit.nsxlib.v3 import nsxlib_testcase -from vmware_nsx.tests.unit.nsxlib.v3 import test_constants as test_constants_v3 - -LOG = log.getLogger(__name__) - - -class NsxLibQosTestCase(nsxlib_testcase.NsxClientTestCase): - - def _body(self, qos_marking=None, dscp=None, - description=test_constants_v3.FAKE_NAME): - body = { - "resource_type": "QosSwitchingProfile", - "tags": [] - } - if qos_marking: - body = self.nsxlib.qos_switching_profile._update_dscp_in_args( - body, qos_marking, dscp) - - body["display_name"] = test_constants_v3.FAKE_NAME - body["description"] = description - - return body - - def _body_with_shaping(self, shaping_enabled=False, - burst_size=None, - peak_bandwidth=None, - average_bandwidth=None, - description=test_constants_v3.FAKE_NAME, - qos_marking=None, - dscp=0): - body = test_constants_v3.FAKE_QOS_PROFILE - body["display_name"] = test_constants_v3.FAKE_NAME - body["description"] = description - - for shaper in body["shaper_configuration"]: - # We currently support only shaping of Egress traffic - if shaper["resource_type"] == "EgressRateShaper": - shaper["enabled"] = shaping_enabled - if burst_size: - shaper["burst_size_bytes"] = burst_size - if peak_bandwidth: - shaper["peak_bandwidth_mbps"] = peak_bandwidth - if average_bandwidth: - shaper["average_bandwidth_mbps"] = average_bandwidth - break - - if qos_marking: - body = self.nsxlib.qos_switching_profile._update_dscp_in_args( - body, qos_marking, dscp) - - return body - - def test_create_qos_switching_profile(self): - """ - Test creating a qos-switching profile returns the correct response - """ - - with mock.patch.object(self.nsxlib.client, 'create') as create: - self.nsxlib.qos_switching_profile.create( - tags=[], - name=test_constants_v3.FAKE_NAME, - description=test_constants_v3.FAKE_NAME) - create.assert_called_with( - 'switching-profiles', self._body()) - - def test_update_qos_switching_profile(self): - """ - Test updating a qos-switching profile returns the correct response - """ - original_profile = self._body() - new_description = "Test" - with mock.patch.object(self.nsxlib.client, 'get', - return_value=original_profile): - with mock.patch.object(self.nsxlib.client, 'update') as update: - - # update the description of the profile - self.nsxlib.qos_switching_profile.update( - test_constants_v3.FAKE_QOS_PROFILE['id'], - tags=[], - description=new_description) - update.assert_called_with( - 'switching-profiles/%s' - % test_constants_v3.FAKE_QOS_PROFILE['id'], - self._body(description=new_description)) - - def test_enable_qos_switching_profile_shaping(self): - """ - Test updating a qos-switching profile returns the correct response - """ - - original_profile = self._body_with_shaping() - burst_size = 100 - peak_bandwidth = 200 - average_bandwidth = 300 - qos_marking = "untrusted" - dscp = 10 - - with mock.patch.object(self.nsxlib.client, 'get', - return_value=original_profile): - with mock.patch.object(self.nsxlib.client, 'update') as update: - # update the bw shaping of the profile - self.nsxlib.qos_switching_profile.update_shaping( - test_constants_v3.FAKE_QOS_PROFILE['id'], - shaping_enabled=True, - burst_size=burst_size, - peak_bandwidth=peak_bandwidth, - average_bandwidth=average_bandwidth, - qos_marking=qos_marking, - dscp=dscp) - - update.assert_called_with( - 'switching-profiles/%s' - % test_constants_v3.FAKE_QOS_PROFILE['id'], - self._body_with_shaping( - shaping_enabled=True, - burst_size=burst_size, - peak_bandwidth=peak_bandwidth, - average_bandwidth=average_bandwidth, - qos_marking="untrusted", dscp=10)) - - def test_disable_qos_switching_profile_shaping(self): - """ - Test updating a qos-switching profile returns the correct response - """ - burst_size = 100 - peak_bandwidth = 200 - average_bandwidth = 300 - original_profile = self._body_with_shaping( - shaping_enabled=True, - burst_size=burst_size, - peak_bandwidth=peak_bandwidth, - average_bandwidth=average_bandwidth, - qos_marking="untrusted", - dscp=10) - - with mock.patch.object(self.nsxlib.client, 'get', - return_value=original_profile): - with mock.patch.object(self.nsxlib.client, 'update') as update: - # update the bw shaping of the profile - self.nsxlib.qos_switching_profile.update_shaping( - test_constants_v3.FAKE_QOS_PROFILE['id'], - shaping_enabled=False, qos_marking="trusted") - - update.assert_called_with( - 'switching-profiles/%s' - % test_constants_v3.FAKE_QOS_PROFILE['id'], - self._body_with_shaping(qos_marking="trusted")) - - def test_delete_qos_switching_profile(self): - """ - Test deleting qos-switching-profile - """ - with mock.patch.object(self.nsxlib.client, 'delete') as delete: - self.nsxlib.qos_switching_profile.delete( - test_constants_v3.FAKE_QOS_PROFILE['id']) - delete.assert_called_with( - 'switching-profiles/%s' - % test_constants_v3.FAKE_QOS_PROFILE['id']) diff --git a/vmware_nsx/tests/unit/nsxlib/v3/test_resources.py b/vmware_nsx/tests/unit/nsxlib/v3/test_resources.py deleted file mode 100644 index f506904491..0000000000 --- a/vmware_nsx/tests/unit/nsxlib/v3/test_resources.py +++ /dev/null @@ -1,552 +0,0 @@ -# Copyright 2015 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. -# -import copy - -import mock - -from oslo_serialization import jsonutils - -from vmware_nsx.nsxlib.v3 import exceptions -from vmware_nsx.nsxlib.v3 import resources -from vmware_nsx.tests.unit.nsxlib.v3 import mocks -from vmware_nsx.tests.unit.nsxlib.v3 import nsxlib_testcase -from vmware_nsx.tests.unit.nsxlib.v3 import test_client -from vmware_nsx.tests.unit.nsxlib.v3 import test_constants as test_constants_v3 - - -CLIENT_PKG = test_client.CLIENT_PKG -profile_types = resources.SwitchingProfileTypes - - -class TestSwitchingProfileTestCase(nsxlib_testcase.NsxClientTestCase): - - def _mocked_switching_profile(self, session_response=None): - return self.mocked_resource( - resources.SwitchingProfile, session_response=session_response) - - def test_switching_profile_create(self): - mocked_resource = self._mocked_switching_profile() - - mocked_resource.create(profile_types.PORT_MIRRORING, - 'pm-profile', 'port mirror prof') - - test_client.assert_json_call( - 'post', mocked_resource, - 'https://1.2.3.4/api/v1/switching-profiles', - data=jsonutils.dumps({ - 'resource_type': profile_types.PORT_MIRRORING, - 'display_name': 'pm-profile', - 'description': 'port mirror prof' - }, sort_keys=True)) - - def test_switching_profile_update(self): - - tags = [ - { - 'scope': 'os-project-id', - 'tag': 'tenant-1' - }, - { - 'scope': 'os-api-version', - 'tag': '2.1.1.0' - } - ] - - mocked_resource = self._mocked_switching_profile() - - mocked_resource.update( - 'a12bc1', profile_types.PORT_MIRRORING, tags=tags) - - test_client.assert_json_call( - 'put', mocked_resource, - 'https://1.2.3.4/api/v1/switching-profiles/a12bc1', - data=jsonutils.dumps({ - 'resource_type': profile_types.PORT_MIRRORING, - 'tags': tags - }, sort_keys=True)) - - def test_spoofgaurd_profile_create(self): - - tags = [ - { - 'scope': 'os-project-id', - 'tag': 'tenant-1' - }, - { - 'scope': 'os-api-version', - 'tag': '2.1.1.0' - } - ] - - mocked_resource = self._mocked_switching_profile() - - mocked_resource.create_spoofguard_profile( - 'plugin-spoof', 'spoofguard-for-plugin', - whitelist_ports=True, tags=tags) - - test_client.assert_json_call( - 'post', mocked_resource, - 'https://1.2.3.4/api/v1/switching-profiles', - data=jsonutils.dumps({ - 'resource_type': profile_types.SPOOF_GUARD, - 'display_name': 'plugin-spoof', - 'description': 'spoofguard-for-plugin', - 'white_list_providers': ['LPORT_BINDINGS'], - 'tags': tags - }, sort_keys=True)) - - def test_create_dhcp_profile(self): - - tags = [ - { - 'scope': 'os-project-id', - 'tag': 'tenant-1' - }, - { - 'scope': 'os-api-version', - 'tag': '2.1.1.0' - } - ] - - mocked_resource = self._mocked_switching_profile() - - mocked_resource.create_dhcp_profile( - 'plugin-dhcp', 'dhcp-for-plugin', - tags=tags) - - test_client.assert_json_call( - 'post', mocked_resource, - 'https://1.2.3.4/api/v1/switching-profiles', - data=jsonutils.dumps({ - 'bpdu_filter': { - 'enabled': True, - 'white_list': [] - }, - 'resource_type': profile_types.SWITCH_SECURITY, - 'display_name': 'plugin-dhcp', - 'description': 'dhcp-for-plugin', - 'tags': tags, - 'dhcp_filter': { - 'client_block_enabled': True, - 'server_block_enabled': False - }, - 'rate_limits': { - 'enabled': False, - 'rx_broadcast': 0, - 'tx_broadcast': 0, - 'rx_multicast': 0, - 'tx_multicast': 0 - }, - 'block_non_ip_traffic': True - }, sort_keys=True)) - - def test_create_mac_learning_profile(self): - - tags = [ - { - 'scope': 'os-project-id', - 'tag': 'tenant-1' - }, - { - 'scope': 'os-api-version', - 'tag': '2.1.1.0' - } - ] - - mocked_resource = self._mocked_switching_profile() - - mocked_resource.create_mac_learning_profile( - 'plugin-mac-learning', 'mac-learning-for-plugin', - tags=tags) - - test_client.assert_json_call( - 'post', mocked_resource, - 'https://1.2.3.4/api/v1/switching-profiles', - data=jsonutils.dumps({ - 'mac_learning': { - 'enabled': True, - }, - 'resource_type': profile_types.MAC_LEARNING, - 'display_name': 'plugin-mac-learning', - 'description': 'mac-learning-for-plugin', - 'tags': tags, - 'mac_change_allowed': True, - }, sort_keys=True)) - - def test_find_by_display_name(self): - resp_resources = { - 'results': [ - {'display_name': 'resource-1'}, - {'display_name': 'resource-2'}, - {'display_name': 'resource-3'} - ] - } - session_response = mocks.MockRequestsResponse( - 200, jsonutils.dumps(resp_resources)) - mocked_resource = self._mocked_switching_profile( - session_response=session_response) - - self.assertEqual([{'display_name': 'resource-1'}], - mocked_resource.find_by_display_name('resource-1')) - self.assertEqual([{'display_name': 'resource-2'}], - mocked_resource.find_by_display_name('resource-2')) - self.assertEqual([{'display_name': 'resource-3'}], - mocked_resource.find_by_display_name('resource-3')) - - resp_resources = { - 'results': [ - {'display_name': 'resource-1'}, - {'display_name': 'resource-1'}, - {'display_name': 'resource-1'} - ] - } - session_response = mocks.MockRequestsResponse( - 200, jsonutils.dumps(resp_resources)) - mocked_resource = self._mocked_switching_profile( - session_response=session_response) - self.assertEqual(resp_resources['results'], - mocked_resource.find_by_display_name('resource-1')) - - def test_list_all_profiles(self): - mocked_resource = self._mocked_switching_profile() - mocked_resource.list() - test_client.assert_json_call( - 'get', mocked_resource, - 'https://1.2.3.4/api/v1/switching-profiles/' - '?include_system_owned=True', - data=None) - - -class LogicalPortTestCase(nsxlib_testcase.NsxClientTestCase): - - def _mocked_lport(self, mock_validate=True, session_response=None): - return self.mocked_resource( - resources.LogicalPort, mock_validate=mock_validate, - session_response=session_response) - - def _get_profile_dicts(self, fake_port): - fake_profile_dicts = [] - for profile_id in fake_port['switching_profile_ids']: - fake_profile_dicts.append({'resource_type': profile_id['key'], - 'id': profile_id['value']}) - return fake_profile_dicts - - def _get_pktcls_bindings(self): - fake_pkt_classifiers = [] - fake_binding_repr = [] - for i in range(0, 3): - ip = "9.10.11.%s" % i - mac = "00:0c:29:35:4a:%sc" % i - fake_pkt_classifiers.append(resources.PacketAddressClassifier( - ip, mac, None)) - fake_binding_repr.append({ - 'ip_address': ip, - 'mac_address': mac - }) - return fake_pkt_classifiers, fake_binding_repr - - def test_create_logical_port(self): - """ - Test creating a port returns the correct response and 200 status - """ - fake_port = test_constants_v3.FAKE_PORT.copy() - - profile_dicts = self._get_profile_dicts(fake_port) - - pkt_classifiers, binding_repr = self._get_pktcls_bindings() - - fake_port['address_bindings'] = binding_repr - - mocked_resource = self._mocked_lport() - - switch_profile = resources.SwitchingProfile - mocked_resource.create( - fake_port['logical_switch_id'], - fake_port['attachment']['id'], - address_bindings=pkt_classifiers, - switch_profile_ids=switch_profile.build_switch_profile_ids( - mock.Mock(), *profile_dicts)) - - resp_body = { - 'logical_switch_id': fake_port['logical_switch_id'], - 'switching_profile_ids': fake_port['switching_profile_ids'], - 'attachment': { - 'attachment_type': 'VIF', - 'id': fake_port['attachment']['id'] - }, - 'admin_state': 'UP', - 'address_bindings': fake_port['address_bindings'] - } - - test_client.assert_json_call( - 'post', mocked_resource, - 'https://1.2.3.4/api/v1/logical-ports', - data=jsonutils.dumps(resp_body, sort_keys=True)) - - def test_create_logical_port_with_attachtype_cif(self): - """ - Test creating a port returns the correct response and 200 status - """ - fake_port = test_constants_v3.FAKE_CONTAINER_PORT.copy() - - profile_dicts = self._get_profile_dicts(fake_port) - - pkt_classifiers, binding_repr = self._get_pktcls_bindings() - - fake_port['address_bindings'] = binding_repr - - mocked_resource = self._mocked_lport() - switch_profile = resources.SwitchingProfile - fake_port_ctx = fake_port['attachment']['context'] - - fake_container_host_vif_id = fake_port_ctx['container_host_vif_id'] - - mocked_resource.create( - fake_port['logical_switch_id'], - fake_port['attachment']['id'], - parent_vif_id=fake_container_host_vif_id, - parent_tag=fake_port_ctx['vlan_tag'], - address_bindings=pkt_classifiers, - switch_profile_ids=switch_profile.build_switch_profile_ids( - mock.Mock(), *profile_dicts)) - - resp_body = { - 'logical_switch_id': fake_port['logical_switch_id'], - 'switching_profile_ids': fake_port['switching_profile_ids'], - 'attachment': { - 'attachment_type': 'CIF', - 'id': fake_port['attachment']['id'], - 'context': { - 'vlan_tag': fake_port_ctx['vlan_tag'], - 'container_host_vif_id': fake_container_host_vif_id, - 'resource_type': 'CifAttachmentContext' - } - }, - 'admin_state': 'UP', - 'address_bindings': fake_port['address_bindings'] - } - - test_client.assert_json_call( - 'post', mocked_resource, - 'https://1.2.3.4/api/v1/logical-ports', - data=jsonutils.dumps(resp_body, sort_keys=True)) - - def test_create_logical_port_admin_down(self): - """ - Test creating port with admin_state down - """ - fake_port = test_constants_v3.FAKE_PORT - fake_port['admin_state'] = "DOWN" - - mocked_resource = self._mocked_lport( - session_response=mocks.MockRequestsResponse( - 200, jsonutils.dumps(fake_port))) - - result = mocked_resource.create( - test_constants_v3.FAKE_PORT['logical_switch_id'], - test_constants_v3.FAKE_PORT['attachment']['id'], - tags={}, admin_state=False) - - self.assertEqual(fake_port, result) - - def test_delete_logical_port(self): - """ - Test deleting port - """ - mocked_resource = self._mocked_lport() - - uuid = test_constants_v3.FAKE_PORT['id'] - mocked_resource.delete(uuid) - test_client.assert_json_call( - 'delete', mocked_resource, - 'https://1.2.3.4/api/v1/logical-ports/%s?detach=true' % uuid) - - def test_clear_port_bindings(self): - fake_port = copy.copy(test_constants_v3.FAKE_PORT) - fake_port['address_bindings'] = ['a', 'b'] - mocked_resource = self._mocked_lport() - - def get_fake_port(*args): - return fake_port - - mocked_resource.get = get_fake_port - mocked_resource.update( - fake_port['id'], fake_port['id'], address_bindings=[]) - - fake_port['address_bindings'] = [] - test_client.assert_json_call( - 'put', mocked_resource, - 'https://1.2.3.4/api/v1/logical-ports/%s' % fake_port['id'], - data=jsonutils.dumps(fake_port, sort_keys=True)) - - def test_create_logical_port_fail(self): - """ - Test the failure of port creation - """ - fake_port = test_constants_v3.FAKE_PORT.copy() - - profile_dicts = self._get_profile_dicts(fake_port) - - pkt_classifiers, binding_repr = self._get_pktcls_bindings() - - fake_port['address_bindings'] = binding_repr - - mocked_resource = self._mocked_lport(mock_validate=False) - - switch_profile = resources.SwitchingProfile - try: - mocked_resource.create( - fake_port['logical_switch_id'], - fake_port['attachment']['id'], - address_bindings=pkt_classifiers, - switch_profile_ids=switch_profile.build_switch_profile_ids( - mock.Mock(), *profile_dicts)) - except exceptions.ManagerError as e: - self.assertIn(nsxlib_testcase.NSX_MANAGER, e.msg) - - -class LogicalRouterTestCase(nsxlib_testcase.NsxClientTestCase): - - def _mocked_lrouter(self, session_response=None): - return self.mocked_resource( - resources.LogicalRouter, session_response=session_response) - - def test_create_logical_router(self): - """ - Test creating a router returns the correct response and 201 status - """ - fake_router = test_constants_v3.FAKE_ROUTER.copy() - - router = self._mocked_lrouter() - - tier0_router = True - router.create(fake_router['display_name'], None, None, tier0_router) - - data = { - 'display_name': fake_router['display_name'], - 'router_type': 'TIER0' if tier0_router else 'TIER1', - 'tags': None - } - - test_client.assert_json_call( - 'post', router, - 'https://1.2.3.4/api/v1/logical-routers', - data=jsonutils.dumps(data, sort_keys=True)) - - def test_delete_logical_router(self): - """ - Test deleting router - """ - router = self._mocked_lrouter() - uuid = test_constants_v3.FAKE_ROUTER['id'] - router.delete(uuid) - test_client.assert_json_call( - 'delete', router, - 'https://1.2.3.4/api/v1/logical-routers/%s' % uuid) - - -class LogicalRouterPortTestCase(nsxlib_testcase.NsxClientTestCase): - - def _mocked_lrport(self, session_response=None): - return self.mocked_resource( - resources.LogicalRouterPort, session_response=session_response) - - def test_create_logical_router_port(self): - """ - Test creating a router port returns the correct response and 201 status - """ - fake_router_port = test_constants_v3.FAKE_ROUTER_PORT.copy() - - lrport = self._mocked_lrport() - - lrport.create(fake_router_port['logical_router_id'], - fake_router_port['display_name'], - None, - fake_router_port['resource_type'], - None, None, None) - - data = { - 'display_name': fake_router_port['display_name'], - 'logical_router_id': fake_router_port['logical_router_id'], - 'resource_type': fake_router_port['resource_type'], - 'tags': [] - } - - test_client.assert_json_call( - 'post', lrport, - 'https://1.2.3.4/api/v1/logical-router-ports', - data=jsonutils.dumps(data, sort_keys=True)) - - def test_logical_router_port_max_attempts(self): - """ - Test a router port api has the configured retries - """ - lrport = self._mocked_lrport() - - self.assertEqual(nsxlib_testcase.NSX_MAX_ATTEMPTS, - lrport._client.max_attempts) - - def test_delete_logical_router_port(self): - """ - Test deleting router port - """ - lrport = self._mocked_lrport() - - uuid = test_constants_v3.FAKE_ROUTER_PORT['id'] - lrport.delete(uuid) - test_client.assert_json_call( - 'delete', lrport, - 'https://1.2.3.4/api/v1/logical-router-ports/%s' % uuid) - - def test_get_logical_router_port_by_router_id(self): - """ - Test getting a router port by router id - """ - fake_router_port = test_constants_v3.FAKE_ROUTER_PORT.copy() - resp_resources = {'results': [fake_router_port]} - - lrport = self._mocked_lrport( - session_response=mocks.MockRequestsResponse( - 200, jsonutils.dumps(resp_resources))) - - router_id = fake_router_port['logical_router_id'] - result = lrport.get_by_router_id(router_id) - self.assertEqual(fake_router_port, result[0]) - test_client.assert_json_call( - 'get', lrport, - 'https://1.2.3.4/api/v1/logical-router-ports/?' - 'logical_router_id=%s' % router_id) - - def test_get_logical_router_port_by_switch_id(self): - """ - Test getting a router port by switch id - """ - fake_router_port = test_constants_v3.FAKE_ROUTER_PORT.copy() - resp_resources = { - 'result_count': 1, - 'results': [fake_router_port] - } - - lrport = self._mocked_lrport( - session_response=mocks.MockRequestsResponse( - 200, jsonutils.dumps(resp_resources))) - - switch_id = test_constants_v3.FAKE_SWITCH_UUID - lrport.get_by_lswitch_id(switch_id) - test_client.assert_json_call( - 'get', lrport, - 'https://1.2.3.4/api/v1/logical-router-ports/?' - 'logical_switch_id=%s' % switch_id) diff --git a/vmware_nsx/tests/unit/nsxlib/v3/test_switch.py b/vmware_nsx/tests/unit/nsxlib/v3/test_switch.py deleted file mode 100644 index b43843014d..0000000000 --- a/vmware_nsx/tests/unit/nsxlib/v3/test_switch.py +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright (c) 2015 VMware, Inc. -# -# 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 mock -from oslo_log import log - -from vmware_nsx.nsxlib.v3 import nsx_constants -from vmware_nsx.tests.unit.nsxlib.v3 import mocks as nsx_v3_mocks -from vmware_nsx.tests.unit.nsxlib.v3 import nsxlib_testcase - - -LOG = log.getLogger(__name__) - - -class NsxLibSwitchTestCase(nsxlib_testcase.NsxClientTestCase): - _tz_id = "8f602f97-ee3e-46b0-9d9f-358955f03608" - - def _create_body(self, admin_state=nsx_constants.ADMIN_STATE_UP, - vlan_id=None): - body = { - "transport_zone_id": NsxLibSwitchTestCase._tz_id, - "replication_mode": "MTEP", - "display_name": "fake_name", - "tags": [], - "admin_state": admin_state - } - if vlan_id: - body['vlan'] = vlan_id - return body - - def test_create_logical_switch(self): - """ - Test creating a switch returns the correct response and 200 status - """ - - with mock.patch.object(self.nsxlib.client, 'create') as create: - self.nsxlib.logical_switch.create( - nsx_v3_mocks.FAKE_NAME, NsxLibSwitchTestCase._tz_id, []) - create.assert_called_with('logical-switches', self._create_body()) - - def test_create_logical_switch_admin_down(self): - """ - Test creating switch with admin_state down - """ - - with mock.patch.object(self.nsxlib.client, 'create') as create: - self.nsxlib.logical_switch.create( - nsx_v3_mocks.FAKE_NAME, NsxLibSwitchTestCase._tz_id, - [], admin_state=False) - - create.assert_called_with( - 'logical-switches', - self._create_body( - admin_state=nsx_constants.ADMIN_STATE_DOWN)) - - def test_create_logical_switch_vlan(self): - """ - Test creating switch with provider:network_type VLAN - """ - - with mock.patch.object(self.nsxlib.client, 'create') as create: - self.nsxlib.logical_switch.create( - nsx_v3_mocks.FAKE_NAME, NsxLibSwitchTestCase._tz_id, - [], vlan_id='123') - - create.assert_called_with( - 'logical-switches', - self._create_body(vlan_id='123')) - - def test_delete_logical_switch(self): - """ - Test deleting switch - """ - - with mock.patch.object(self.nsxlib.client, 'delete') as delete: - fake_switch = nsx_v3_mocks.make_fake_switch() - self.nsxlib.logical_switch.delete(fake_switch['id']) - delete.assert_called_with( - 'logical-switches/%s' - '?detach=true&cascade=true' % fake_switch['id']) diff --git a/vmware_nsx/tests/unit/nsxlib/v3/test_utils.py b/vmware_nsx/tests/unit/nsxlib/v3/test_utils.py deleted file mode 100644 index e04190f6b4..0000000000 --- a/vmware_nsx/tests/unit/nsxlib/v3/test_utils.py +++ /dev/null @@ -1,204 +0,0 @@ -# Copyright (c) 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 neutron_lib import exceptions as n_exc - -from vmware_nsx.nsxlib.v3 import utils -from vmware_nsx.tests.unit.nsxlib.v3 import nsxlib_testcase - - -class TestNsxV3Utils(nsxlib_testcase.NsxClientTestCase): - - def test_build_v3_tags_payload(self): - result = self.nsxlib.build_v3_tags_payload( - {'id': 'fake_id', - 'tenant_id': 'fake_tenant_id'}, - resource_type='os-net-id', - project_name='fake_tenant_name') - expected = [{'scope': 'os-net-id', 'tag': 'fake_id'}, - {'scope': 'os-project-id', 'tag': 'fake_tenant_id'}, - {'scope': 'os-project-name', 'tag': 'fake_tenant_name'}, - {'scope': 'os-api-version', - 'tag': nsxlib_testcase.PLUGIN_VER}] - self.assertEqual(expected, result) - - def test_build_v3_tags_payload_internal(self): - result = self.nsxlib.build_v3_tags_payload( - {'id': 'fake_id', - 'tenant_id': 'fake_tenant_id'}, - resource_type='os-net-id', - project_name=None) - expected = [{'scope': 'os-net-id', 'tag': 'fake_id'}, - {'scope': 'os-project-id', 'tag': 'fake_tenant_id'}, - {'scope': 'os-project-name', - 'tag': nsxlib_testcase.PLUGIN_TAG}, - {'scope': 'os-api-version', - 'tag': nsxlib_testcase.PLUGIN_VER}] - self.assertEqual(expected, result) - - def test_build_v3_tags_payload_invalid_length(self): - self.assertRaises(n_exc.InvalidInput, - self.nsxlib.build_v3_tags_payload, - {'id': 'fake_id', - 'tenant_id': 'fake_tenant_id'}, - resource_type='os-longer-maldini-rocks-id', - project_name='fake') - - def test_build_v3_api_version_tag(self): - result = self.nsxlib.build_v3_api_version_tag() - expected = [{'scope': nsxlib_testcase.PLUGIN_SCOPE, - 'tag': nsxlib_testcase.PLUGIN_TAG}, - {'scope': 'os-api-version', - 'tag': nsxlib_testcase.PLUGIN_VER}] - self.assertEqual(expected, result) - - def test_is_internal_resource(self): - project_tag = self.nsxlib.build_v3_tags_payload( - {'id': 'fake_id', - 'tenant_id': 'fake_tenant_id'}, - resource_type='os-net-id', - project_name=None) - internal_tag = self.nsxlib.build_v3_api_version_tag() - - expect_false = self.nsxlib.is_internal_resource({'tags': project_tag}) - self.assertFalse(expect_false) - - expect_true = self.nsxlib.is_internal_resource({'tags': internal_tag}) - self.assertTrue(expect_true) - - def test_get_name_and_uuid(self): - uuid = 'afc40f8a-4967-477e-a17a-9d560d1786c7' - suffix = '_afc40...786c7' - expected = 'maldini%s' % suffix - short_name = utils.get_name_and_uuid('maldini', uuid) - self.assertEqual(expected, short_name) - - name = 'X' * 255 - expected = '%s%s' % ('X' * (80 - len(suffix)), suffix) - short_name = utils.get_name_and_uuid(name, uuid) - self.assertEqual(expected, short_name) - - def test_build_v3_tags_max_length_payload(self): - result = self.nsxlib.build_v3_tags_payload( - {'id': 'X' * 255, - 'tenant_id': 'X' * 255}, - resource_type='os-net-id', - project_name='X' * 255) - expected = [{'scope': 'os-net-id', 'tag': 'X' * 40}, - {'scope': 'os-project-id', 'tag': 'X' * 40}, - {'scope': 'os-project-name', 'tag': 'X' * 40}, - {'scope': 'os-api-version', - 'tag': nsxlib_testcase.PLUGIN_VER}] - self.assertEqual(expected, result) - - def test_add_v3_tag(self): - result = utils.add_v3_tag([], 'fake-scope', 'fake-tag') - expected = [{'scope': 'fake-scope', 'tag': 'fake-tag'}] - self.assertEqual(expected, result) - - def test_add_v3_tag_max_length_payload(self): - result = utils.add_v3_tag([], 'fake-scope', 'X' * 255) - expected = [{'scope': 'fake-scope', 'tag': 'X' * 40}] - self.assertEqual(expected, result) - - def test_add_v3_tag_invalid_scope_length(self): - self.assertRaises(n_exc.InvalidInput, - utils.add_v3_tag, - [], - 'fake-scope-name-is-far-too-long', - 'fake-tag') - - def test_update_v3_tags_addition(self): - tags = [{'scope': 'os-net-id', 'tag': 'X' * 40}, - {'scope': 'os-project-id', 'tag': 'Y' * 40}, - {'scope': 'os-project-name', 'tag': 'Z' * 40}, - {'scope': 'os-api-version', - 'tag': nsxlib_testcase.PLUGIN_VER}] - resources = [{'scope': 'os-instance-uuid', - 'tag': 'A' * 40}] - tags = utils.update_v3_tags(tags, resources) - expected = [{'scope': 'os-net-id', 'tag': 'X' * 40}, - {'scope': 'os-project-id', 'tag': 'Y' * 40}, - {'scope': 'os-project-name', 'tag': 'Z' * 40}, - {'scope': 'os-api-version', - 'tag': nsxlib_testcase.PLUGIN_VER}, - {'scope': 'os-instance-uuid', - 'tag': 'A' * 40}] - self.assertEqual(sorted(expected, key=lambda x: x.get('tag')), - sorted(tags, key=lambda x: x.get('tag'))) - - def test_update_v3_tags_removal(self): - tags = [{'scope': 'os-net-id', 'tag': 'X' * 40}, - {'scope': 'os-project-id', 'tag': 'Y' * 40}, - {'scope': 'os-project-name', 'tag': 'Z' * 40}, - {'scope': 'os-api-version', - 'tag': nsxlib_testcase.PLUGIN_VER}] - resources = [{'scope': 'os-net-id', - 'tag': ''}] - tags = utils.update_v3_tags(tags, resources) - expected = [{'scope': 'os-project-id', 'tag': 'Y' * 40}, - {'scope': 'os-project-name', 'tag': 'Z' * 40}, - {'scope': 'os-api-version', - 'tag': nsxlib_testcase.PLUGIN_VER}] - self.assertEqual(sorted(expected, key=lambda x: x.get('tag')), - sorted(tags, key=lambda x: x.get('tag'))) - - def test_update_v3_tags_update(self): - tags = [{'scope': 'os-net-id', 'tag': 'X' * 40}, - {'scope': 'os-project-id', 'tag': 'Y' * 40}, - {'scope': 'os-project-name', 'tag': 'Z' * 40}, - {'scope': 'os-api-version', - 'tag': nsxlib_testcase.PLUGIN_VER}] - resources = [{'scope': 'os-project-id', - 'tag': 'A' * 40}] - tags = utils.update_v3_tags(tags, resources) - expected = [{'scope': 'os-net-id', 'tag': 'X' * 40}, - {'scope': 'os-project-id', 'tag': 'A' * 40}, - {'scope': 'os-project-name', 'tag': 'Z' * 40}, - {'scope': 'os-api-version', - 'tag': nsxlib_testcase.PLUGIN_VER}] - self.assertEqual(sorted(expected, key=lambda x: x.get('tag')), - sorted(tags, key=lambda x: x.get('tag'))) - - def test_update_v3_tags_repetitive_scopes(self): - tags = [{'scope': 'os-net-id', 'tag': 'X' * 40}, - {'scope': 'os-project-id', 'tag': 'Y' * 40}, - {'scope': 'os-project-name', 'tag': 'Z' * 40}, - {'scope': 'os-security-group', 'tag': 'SG1'}, - {'scope': 'os-security-group', 'tag': 'SG2'}] - tags_update = [{'scope': 'os-security-group', 'tag': 'SG3'}, - {'scope': 'os-security-group', 'tag': 'SG4'}] - tags = utils.update_v3_tags(tags, tags_update) - expected = [{'scope': 'os-net-id', 'tag': 'X' * 40}, - {'scope': 'os-project-id', 'tag': 'Y' * 40}, - {'scope': 'os-project-name', 'tag': 'Z' * 40}, - {'scope': 'os-security-group', 'tag': 'SG3'}, - {'scope': 'os-security-group', 'tag': 'SG4'}] - self.assertEqual(sorted(expected, key=lambda x: x.get('tag')), - sorted(tags, key=lambda x: x.get('tag'))) - - def test_update_v3_tags_repetitive_scopes_remove(self): - tags = [{'scope': 'os-net-id', 'tag': 'X' * 40}, - {'scope': 'os-project-id', 'tag': 'Y' * 40}, - {'scope': 'os-project-name', 'tag': 'Z' * 40}, - {'scope': 'os-security-group', 'tag': 'SG1'}, - {'scope': 'os-security-group', 'tag': 'SG2'}] - tags_update = [{'scope': 'os-security-group', 'tag': None}] - tags = utils.update_v3_tags(tags, tags_update) - expected = [{'scope': 'os-net-id', 'tag': 'X' * 40}, - {'scope': 'os-project-id', 'tag': 'Y' * 40}, - {'scope': 'os-project-name', 'tag': 'Z' * 40}] - self.assertEqual(sorted(expected, key=lambda x: x.get('tag')), - sorted(tags, key=lambda x: x.get('tag'))) diff --git a/vmware_nsx/tests/unit/services/l2gateway/test_nsxv3_driver.py b/vmware_nsx/tests/unit/services/l2gateway/test_nsxv3_driver.py index da4bc8876f..601b26dea6 100644 --- a/vmware_nsx/tests/unit/services/l2gateway/test_nsxv3_driver.py +++ b/vmware_nsx/tests/unit/services/l2gateway/test_nsxv3_driver.py @@ -31,10 +31,10 @@ from neutron import context from neutron.tests import base from neutron_lib import exceptions as n_exc -from vmware_nsx.nsxlib.v3 import nsx_constants from vmware_nsx.services.l2gateway.nsx_v3 import driver as nsx_v3_driver from vmware_nsx.tests.unit.nsx_v3 import test_plugin as test_nsx_v3_plugin -from vmware_nsx.tests.unit.nsxlib.v3 import mocks as nsx_v3_mocks +from vmware_nsxlib.tests.unit.v3 import mocks as nsx_v3_mocks +from vmware_nsxlib.v3 import nsx_constants NSX_V3_PLUGIN_CLASS = ('vmware_nsx.plugins.nsx_v3.plugin.NsxV3Plugin') diff --git a/vmware_nsx/tests/unit/services/qos/test_nsxv3_notification.py b/vmware_nsx/tests/unit/services/qos/test_nsxv3_notification.py index 78baea0205..33e030b54e 100644 --- a/vmware_nsx/tests/unit/services/qos/test_nsxv3_notification.py +++ b/vmware_nsx/tests/unit/services/qos/test_nsxv3_notification.py @@ -94,7 +94,7 @@ class TestQosNsxV3Notification(base.BaseQosTestCase, def test_policy_create_profile(self, fake_db_add, fake_rbac_create): # test the switch profile creation when a QoS policy is created with mock.patch( - 'vmware_nsx.nsxlib.v3.NsxLibQosSwitchingProfile.create', + 'vmware_nsxlib.v3.NsxLibQosSwitchingProfile.create', return_value=self.fake_profile ) as create_profile: with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object', @@ -122,7 +122,7 @@ class TestQosNsxV3Notification(base.BaseQosTestCase, fields = base_object.get_updatable_fields( policy_object.QosPolicy, self.policy_data['policy']) with mock.patch( - 'vmware_nsx.nsxlib.v3.NsxLibQosSwitchingProfile.update' + 'vmware_nsxlib.v3.NsxLibQosSwitchingProfile.update' ) as update_profile: with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object', return_value=self.policy): @@ -153,7 +153,7 @@ class TestQosNsxV3Notification(base.BaseQosTestCase, with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object', return_value=_policy): with mock.patch( - 'vmware_nsx.nsxlib.v3.NsxLibQosSwitchingProfile.update_shaping' + 'vmware_nsxlib.v3.NsxLibQosSwitchingProfile.update_shaping' ) as update_profile: with mock.patch('neutron.objects.db.api.update_object', return_value=self.rule_data): @@ -196,7 +196,7 @@ class TestQosNsxV3Notification(base.BaseQosTestCase, with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object', return_value=_policy): with mock.patch( - 'vmware_nsx.nsxlib.v3.NsxLibQosSwitchingProfile.update_shaping' + 'vmware_nsxlib.v3.NsxLibQosSwitchingProfile.update_shaping' ) as update_profile: with mock.patch('neutron.objects.db.api.update_object', return_value=rule_data): @@ -228,7 +228,7 @@ class TestQosNsxV3Notification(base.BaseQosTestCase, with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object', return_value=_policy): with mock.patch( - 'vmware_nsx.nsxlib.v3.NsxLibQosSwitchingProfile.update_shaping' + 'vmware_nsxlib.v3.NsxLibQosSwitchingProfile.update_shaping' ) as update_profile: with mock.patch('neutron.objects.db.api.' 'update_object', return_value=self.dscp_rule_data): @@ -260,7 +260,7 @@ class TestQosNsxV3Notification(base.BaseQosTestCase, with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object', return_value=_policy): with mock.patch( - "vmware_nsx.nsxlib.v3.NsxLibQosSwitchingProfile.update_shaping" + "vmware_nsxlib.v3.NsxLibQosSwitchingProfile.update_shaping" ) as update_profile: setattr(_policy, "rules", [self.rule]) self.qos_plugin.delete_policy_bandwidth_limit_rule( @@ -280,7 +280,7 @@ class TestQosNsxV3Notification(base.BaseQosTestCase, def test_policy_delete_profile(self, *mocks): # test the switch profile deletion when a QoS policy is deleted with mock.patch( - 'vmware_nsx.nsxlib.v3.NsxLibQosSwitchingProfile.delete', + 'vmware_nsxlib.v3.NsxLibQosSwitchingProfile.delete', return_value=self.fake_profile ) as delete_profile: self.qos_plugin.delete_policy(self.ctxt, self.policy.id) diff --git a/vmware_nsx/tests/unit/shell/test_admin_utils.py b/vmware_nsx/tests/unit/shell/test_admin_utils.py index c3dae4f737..e8e72643fb 100644 --- a/vmware_nsx/tests/unit/shell/test_admin_utils.py +++ b/vmware_nsx/tests/unit/shell/test_admin_utils.py @@ -30,11 +30,11 @@ from neutron.tests.unit.db import test_db_base_plugin_v2 as test_n_plugin from vmware_nsx._i18n import _ from vmware_nsx.common import config # noqa -from vmware_nsx.nsxlib.v3 import resources as nsx_v3_resources from vmware_nsx.shell import resources from vmware_nsx.tests import unit as vmware from vmware_nsx.tests.unit.nsx_v.vshield import fake_vcns from vmware_nsx.tests.unit.nsx_v3 import test_plugin as test_v3_plugin +from vmware_nsxlib.v3 import resources as nsx_v3_resources LOG = logging.getLogger(__name__) NSX_INI_PATH = vmware.get_fake_conf('nsx.ini.test')