diff --git a/vmware_nsx/nsxlib/v3/__init__.py b/vmware_nsx/nsxlib/v3/__init__.py index bda2fd1490..2956fa9b76 100644 --- a/vmware_nsx/nsxlib/v3/__init__.py +++ b/vmware_nsx/nsxlib/v3/__init__.py @@ -19,6 +19,7 @@ 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 @@ -28,60 +29,43 @@ LOG = log.getLogger(__name__) class NsxLib(object): - def __init__(self, - 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, - http_provider=None, - max_attempts=0, - nsx_api_managers=None): + def __init__(self, nsxlib_config): - self.max_attempts = max_attempts + self.nsxlib_config = nsxlib_config # create the Cluster - self.cluster = cluster.NSXClusteredAPI( - username=username, password=password, - retries=retries, insecure=insecure, - ca_file=ca_file, - concurrent_connections=concurrent_connections, - http_timeout=http_timeout, - http_read_timeout=http_read_timeout, - conn_idle_timeout=conn_idle_timeout, - http_provider=http_provider, - nsx_api_managers=nsx_api_managers) + self.cluster = cluster.NSXClusteredAPI(nsxlib_config) # create the Client self.client = client.NSX3Client( self.cluster, - max_attempts=max_attempts) + 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, self.max_attempts) + self.client, nsxlib_config) self.bridge_endpoint = NsxLibBridgeEndpoint( - self.client, self.max_attempts) + self.client, nsxlib_config) self.logical_switch = NsxLibLogicalSwitch( - self.client, self.max_attempts) + self.client, nsxlib_config) self.logical_router = NsxLibLogicalRouter( - self.client, self.max_attempts) + self.client, nsxlib_config) self.qos_switching_profile = NsxLibQosSwitchingProfile( - self.client, self.max_attempts) + self.client, nsxlib_config) self.edge_cluster = NsxLibEdgeCluster( - self.client, self.max_attempts) + self.client, nsxlib_config) self.bridge_cluster = NsxLibBridgeCluster( - self.client, self.max_attempts) + self.client, nsxlib_config) self.transport_zone = NsxLibTransportZone( - self.client, self.max_attempts) + self.client, nsxlib_config) self.firewall_section = security.NsxLibFirewallSection( - self.client, self.max_attempts) + self.client, nsxlib_config) self.ns_group = security.NsxLibNsGroup( - self.client, self.max_attempts, self.firewall_section) + self.client, nsxlib_config, self.firewall_section) + self.native_dhcp = native_dhcp.NsxLibNativeDhcp( + self.client, nsxlib_config) super(NsxLib, self).__init__() @@ -90,6 +74,19 @@ class NsxLib(object): 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): @@ -182,8 +179,9 @@ class NsxLibLogicalSwitch(utils.NsxLibApiBase): 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.max_attempts) + @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) @@ -197,8 +195,9 @@ class NsxLibLogicalSwitch(utils.NsxLibApiBase): 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.max_attempts) + @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) @@ -234,7 +233,7 @@ class NsxLibQosSwitchingProfile(utils.NsxLibApiBase): def _enable_shaping_in_args(self, body, burst_size=None, peak_bandwidth=None, average_bandwidth=None): for shaper in body["shaper_configuration"]: - # Neutron currently supports only shaping of Egress traffic + # We currently supports only shaping of Egress traffic if shaper["resource_type"] == "EgressRateShaper": shaper["enabled"] = True if burst_size: @@ -249,7 +248,7 @@ class NsxLibQosSwitchingProfile(utils.NsxLibApiBase): def _disable_shaping_in_args(self, body): for shaper in body["shaper_configuration"]: - # Neutron currently supports only shaping of Egress traffic + # We currently supports only shaping of Egress traffic if shaper["resource_type"] == "EgressRateShaper": shaper["enabled"] = False shaper["burst_size_bytes"] = 0 diff --git a/vmware_nsx/nsxlib/v3/cluster.py b/vmware_nsx/nsxlib/v3/cluster.py index b1f393ccfb..c3e61f879d 100644 --- a/vmware_nsx/nsxlib/v3/cluster.py +++ b/vmware_nsx/nsxlib/v3/cluster.py @@ -26,9 +26,6 @@ import six.moves.urllib.parse as urlparse from eventlet import greenpool from eventlet import pools -from neutron.callbacks import events -from neutron.callbacks import registry -from neutron.callbacks import resources from oslo_log import log from oslo_service import loopingcall from requests import adapters @@ -121,13 +118,14 @@ class NSXRequestsHTTPProvider(AbstractHTTPProvider): manager=endpoint.provider.url, operation=msg) def new_connection(self, cluster_api, provider): - session = TimeoutSession(cluster_api.http_timeout, - cluster_api.http_read_timeout) + 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 cluster_api.insecure + session.verify = not config.insecure if session.verify and provider.ca_file: # verify using the said ca bundle path session.verify = provider.ca_file @@ -135,7 +133,7 @@ class NSXRequestsHTTPProvider(AbstractHTTPProvider): # we are pooling with eventlet in the cluster class adapter = adapters.HTTPAdapter( pool_connections=1, pool_maxsize=1, - max_retries=cluster_api.retries, + max_retries=config.retries, pool_block=False) session.mount('http://', adapter) session.mount('https://', adapter) @@ -258,10 +256,10 @@ class ClusteredAPI(object): _init_cluster() - # reinitialize upon fork for api workers to ensure each - # process has its own keepalive loops + state - registry.subscribe( - _init_cluster, resources.PROCESS, events.AFTER_INIT) + # 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): @@ -450,40 +448,17 @@ class NSXClusteredAPI(ClusteredAPI): NSX v3 cluster. """ - def __init__(self, - 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, - http_provider=None, - nsx_api_managers=None): + def __init__(self, nsxlib_config): + self.nsxlib_config = nsxlib_config - # username, password & ca_file may be lists, in order to support - # different credentials per nsx manager - self._username = username - self._password = password - self._ca_file = ca_file - - self.retries = retries - self.insecure = insecure - self.conns_per_pool = concurrent_connections - self.http_timeout = http_timeout - self.http_read_timeout = http_read_timeout - self.conn_idle_timeout = conn_idle_timeout - self.nsx_api_managers = nsx_api_managers - - self._http_provider = http_provider or NSXRequestsHTTPProvider() + 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.conns_per_pool, - keepalive_interval=self.conn_idle_timeout) + 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) @@ -496,7 +471,7 @@ class NSXClusteredAPI(ClusteredAPI): uri if uri.startswith('http') else "%s://%s" % (self._http_provider.default_scheme, uri)) - conf_urls = self.nsx_api_managers[:] + conf_urls = self.nsxlib_config.nsx_api_managers[:] urls = [] providers = [] provider_index = -1 @@ -512,27 +487,7 @@ class NSXClusteredAPI(ClusteredAPI): Provider( conf_url.netloc, urlparse.urlunparse(conf_url), - self.username(provider_index), - self.password(provider_index), - self.ca_file(provider_index))) + self.nsxlib_config.username(provider_index), + self.nsxlib_config.password(provider_index), + self.nsxlib_config.ca_file(provider_index))) return providers - - 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/config.py b/vmware_nsx/nsxlib/v3/config.py new file mode 100644 index 0000000000..dc831f12d4 --- /dev/null +++ b/vmware_nsx/nsxlib/v3/config.py @@ -0,0 +1,123 @@ +# 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/native_dhcp.py b/vmware_nsx/nsxlib/v3/native_dhcp.py index 3f6d4a9482..dfd45e5654 100644 --- a/vmware_nsx/nsxlib/v3/native_dhcp.py +++ b/vmware_nsx/nsxlib/v3/native_dhcp.py @@ -20,46 +20,45 @@ from neutron_lib import constants from vmware_nsx.nsxlib.v3 import utils -def build_dhcp_server_config(network, subnet, port, project_name, - nameservers, dhcp_profile_uuid, dns_domain): - # 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 = nameservers - gateway_ip = subnet['gateway_ip'] - if not validators.is_attr_set(gateway_ip): - gateway_ip = None +class NsxLibNativeDhcp(utils.NsxLibApiBase): - # The following code is based on _generate_opts_per_subnet() in - # neutron/agent/linux/dhcp.py. It prepares DHCP options for a subnet. + 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 - # 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}) + # The following code is based on _generate_opts_per_subnet() in + # neutron/agent/linux/dhcp.py. It prepares DHCP options for a subnet. - options = {'option121': {'static_routes': host_routes}} - name = utils.get_name_and_uuid(network['name'] or 'dhcpserver', - network['id']) - tags = utils.build_v3_tags_payload( - network, resource_type='os-neutron-net-id', project_name=project_name) - return {'name': name, - 'dhcp_profile_id': dhcp_profile_uuid, - 'server_ip': server_ip, - 'dns_nameservers': dns_nameservers, - 'domain_name': dns_domain, - 'gateway_ip': gateway_ip, - 'options': options, - 'tags': tags} + # 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, + 'dhcp_profile_id': self.nsxlib_config.dhcp_profile_uuid, + '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 index 9f416f3275..7dcef48afa 100644 --- a/vmware_nsx/nsxlib/v3/ns_group_manager.py +++ b/vmware_nsx/nsxlib/v3/ns_group_manager.py @@ -22,7 +22,6 @@ 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 -from vmware_nsx.nsxlib.v3 import utils as nsxlib_utils LOG = log.getLogger(__name__) @@ -69,7 +68,7 @@ class NSGroupManager(object): nested_groups = { self._get_nested_group_index_from_name(nsgroup): nsgroup['id'] for nsgroup in self.nsxlib_nsgroup.list() - if nsxlib_utils.is_internal_resource(nsgroup)} + if self.nsxlib_nsgroup.is_internal_resource(nsgroup)} if nested_groups: size = max(requested_size, max(nested_groups) + 1) @@ -100,7 +99,7 @@ class NSGroupManager(object): name_prefix = NSGroupManager.NESTED_GROUP_NAME name = '%s %s' % (name_prefix, index + 1) description = NSGroupManager.NESTED_GROUP_DESCRIPTION - tags = nsxlib_utils.build_v3_api_version_tag() + tags = self.nsxlib_nsgroup.build_v3_api_version_tag() return self.nsxlib_nsgroup.create(name, description, tags) def _hash_uuid(self, internal_id): diff --git a/vmware_nsx/nsxlib/v3/security.py b/vmware_nsx/nsxlib/v3/security.py index c54fd2f2e6..9682ff1ae7 100644 --- a/vmware_nsx/nsxlib/v3/security.py +++ b/vmware_nsx/nsxlib/v3/security.py @@ -30,7 +30,6 @@ from vmware_nsx.nsxlib.v3 import utils LOG = log.getLogger(__name__) -DEFAULT_SECTION = 'OS Default Section for Neutron Security-Groups' PORT_SG_SCOPE = 'os-security-group' MAX_NSGROUPS_CRITERIA_TAGS = 10 @@ -168,7 +167,7 @@ class NsxLibNsGroup(utils.NsxLibApiBase): #Using internal method so we can access max_attempts in the decorator @utils.retry_upon_exception( exceptions.StaleRevision, - max_attempts=self.max_attempts) + max_attempts=self.nsxlib_config.max_attempts) def _do_update(): nsgroup = self.read(nsgroup_id) if display_name is not None: @@ -196,7 +195,7 @@ class NsxLibNsGroup(utils.NsxLibApiBase): #Using internal method so we can access max_attempts in the decorator @utils.retry_upon_exception( exceptions.StaleRevision, - max_attempts=self.max_attempts) + 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) @@ -342,7 +341,7 @@ class NsxLibFirewallSection(utils.NsxLibApiBase): #Using internal method so we can access max_attempts in the decorator @utils.retry_upon_exception( exceptions.StaleRevision, - max_attempts=self.max_attempts) + max_attempts=self.nsxlib_config.max_attempts) def _do_update(): resource = 'firewall/sections/%s' % section_id section = self.read(section_id) @@ -494,7 +493,7 @@ class NsxLibFirewallSection(utils.NsxLibApiBase): if section['display_name'] == name: break else: - tags = utils.build_v3_api_version_tag() + tags = self.build_v3_api_version_tag() section = self.create_empty( name, description, nested_groups, tags) diff --git a/vmware_nsx/nsxlib/v3/utils.py b/vmware_nsx/nsxlib/v3/utils.py index 81139ca290..d94836aae7 100644 --- a/vmware_nsx/nsxlib/v3/utils.py +++ b/vmware_nsx/nsxlib/v3/utils.py @@ -15,7 +15,6 @@ import retrying -from neutron import version as n_version from neutron_lib import exceptions from oslo_log import log @@ -26,33 +25,9 @@ LOG = log.getLogger(__name__) MAX_RESOURCE_TYPE_LEN = 20 MAX_TAG_LEN = 40 -NSX_NEUTRON_PLUGIN = 'NSX Neutron plugin' -OS_NEUTRON_ID_SCOPE = 'os-neutron-id' DEFAULT_MAX_ATTEMPTS = 10 -def is_internal_resource(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'] == OS_NEUTRON_ID_SCOPE: - return tag['tag'] == NSX_NEUTRON_PLUGIN - return False - - -def build_v3_api_version_tag(): - """ - Some resources are created on the manager that do not have a corresponding - Neutron resource. - """ - return [{'scope': OS_NEUTRON_ID_SCOPE, - 'tag': NSX_NEUTRON_PLUGIN}, - {'scope': "os-api-version", - 'tag': n_version.version_info.release_string()}] - - 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: @@ -63,31 +38,6 @@ def _validate_resource_type_length(resource_type): 'resource_type': resource_type})) -def build_v3_tags_payload(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 = NSX_NEUTRON_PLUGIN - 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': n_version.version_info.release_string()[:MAX_TAG_LEN]}] - - def add_v3_tag(tags, resource_type, tag): _validate_resource_type_length(resource_type) tags.append({'scope': resource_type, 'tag': tag[:MAX_TAG_LEN]}) @@ -174,15 +124,15 @@ def get_name_and_uuid(name, uuid, tag=None, maxlen=80): class NsxLibApiBase(object): """Base class for nsxlib api """ - def __init__(self, client, max_attempts): + def __init__(self, client, nsxlib_config): self.client = client - self.max_attempts = max_attempts + 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.max_attempts) + max_attempts=self.nsxlib_config.max_attempts) def do_update(): revised_payload = self.client.get(resource) for key_name in payload.keys(): @@ -215,3 +165,47 @@ class NsxLibApiBase(object): 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 5277e8c1c9..62bcb06590 100644 --- a/vmware_nsx/plugins/nsx_v3/plugin.py +++ b/vmware_nsx/plugins/nsx_v3/plugin.py @@ -84,7 +84,6 @@ 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 native_dhcp 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 @@ -102,6 +101,7 @@ NSX_V3_PSEC_PROFILE_NAME = 'neutron_port_spoof_guard_profile' NSX_V3_NO_PSEC_PROFILE_NAME = 'nsx-default-spoof-guard-vif-profile' NSX_V3_DHCP_PROFILE_NAME = 'neutron_port_dhcp_profile' NSX_V3_MAC_LEARNING_PROFILE_NAME = 'neutron_port_mac_learning_profile' +NSX_V3_FW_DEFAULT_SECTION = 'OS Default Section for Neutron Security-Groups' # NOTE(asarfaty): the order of inheritance here is important. in order for the @@ -166,6 +166,11 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, LOG.info(_LI("Starting NsxV3Plugin")) self.nsxlib = v3_utils.get_nsxlib_wrapper() + # reinitialize the cluster upon fork for api workers to ensure each + # process has its own keepalive loops + state + registry.subscribe( + self.nsxlib.reinitialize_cluster, + resources.PROCESS, events.AFTER_INIT) self._nsx_version = self.nsxlib.get_version() LOG.info(_LI("NSX Version: %s"), self._nsx_version) @@ -318,7 +323,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, if not profile: self._switching_profiles.create_dhcp_profile( NSX_V3_DHCP_PROFILE_NAME, 'Neutron DHCP Security Profile', - tags=nsxlib_utils.build_v3_api_version_tag()) + tags=self.nsxlib.build_v3_api_version_tag()) return self._get_dhcp_security_profile() def _get_dhcp_security_profile(self): @@ -338,7 +343,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, self._switching_profiles.create_mac_learning_profile( NSX_V3_MAC_LEARNING_PROFILE_NAME, 'Neutron MAC Learning Profile', - tags=nsxlib_utils.build_v3_api_version_tag()) + tags=self.nsxlib.build_v3_api_version_tag()) return self._get_mac_learning_profile() def _get_mac_learning_profile(self): @@ -378,7 +383,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, self._switching_profiles.create_spoofguard_profile( NSX_V3_PSEC_PROFILE_NAME, 'Neutron Port Security Profile', whitelist_ports=True, whitelist_switches=False, - tags=nsxlib_utils.build_v3_api_version_tag()) + tags=self.nsxlib.build_v3_api_version_tag()) return self._get_port_security_profile() def _process_security_group_logging(self): @@ -409,7 +414,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, section_description = ("This section is handled by OpenStack to " "contain default rules on security-groups.") section_id = self.nsxlib.firewall_section.init_default( - security.DEFAULT_SECTION, section_description, + NSX_V3_FW_DEFAULT_SECTION, section_description, nsgroup_manager.nested_groups.values(), cfg.CONF.nsx_v3.log_security_groups_blocked_traffic) return nsgroup_manager, section_id @@ -596,7 +601,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, # update the network name to indicate the neutron id too. net_name = utils.get_name_and_uuid(net_data['name'] or 'network', neutron_net_id) - tags = nsxlib_utils.build_v3_tags_payload( + tags = self.nsxlib.build_v3_tags_payload( net_data, resource_type='os-neutron-net-id', project_name=context.tenant_name) @@ -708,7 +713,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, if is_backend_network and cfg.CONF.nsx_v3.native_dhcp_metadata: # Enable native metadata proxy for this network. - tags = nsxlib_utils.build_v3_tags_payload( + tags = self.nsxlib.build_v3_tags_payload( net_data, resource_type='os-neutron-net-id', project_name=context.tenant_name) name = utils.get_name_and_uuid('%s-%s' % ( @@ -915,13 +920,13 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, } neutron_port = super(NsxV3Plugin, self).create_port( context, {'port': port_data}) - server_data = native_dhcp.build_dhcp_server_config( - network, subnet, neutron_port, context.tenant_name, - cfg.CONF.nsx_v3.nameservers, - cfg.CONF.nsx_v3.dhcp_profile_uuid, - cfg.CONF.nsx_v3.dns_domain) + net_tags = self.nsxlib.build_v3_tags_payload( + network, resource_type='os-neutron-net-id', + project_name=context.tenant_name) + server_data = self.nsxlib.native_dhcp.build_server_config( + network, subnet, neutron_port, net_tags) nsx_net_id = self._get_network_nsx_id(context, network['id']) - tags = nsxlib_utils.build_v3_tags_payload( + port_tags = self.nsxlib.build_v3_tags_payload( neutron_port, resource_type='os-neutron-dport-id', project_name=context.tenant_name) dhcp_server = None @@ -932,7 +937,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, {'server': dhcp_server['id'], 'network': network['id']}) name = self._get_port_name(context, port_data) nsx_port = self._port_client.create( - nsx_net_id, dhcp_server['id'], tags=tags, name=name, + nsx_net_id, dhcp_server['id'], tags=port_tags, name=name, attachment_type=nsxlib_consts.ATTACHMENT_DHCP) LOG.debug("Created DHCP logical port %(port)s for " "network %(network)s", @@ -1254,7 +1259,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, resource_type = 'os-neutron-rport-id' else: resource_type = 'os-neutron-port-id' - tags = nsxlib_utils.build_v3_tags_payload( + tags = self.nsxlib.build_v3_tags_payload( port_data, resource_type=resource_type, project_name=context.tenant_name) resource_type = self._get_resource_type_for_device_id( @@ -2244,7 +2249,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, edge_cluster_uuid = self._get_edge_cluster(new_tier0_uuid) self._routerlib.update_router_edge_cluster( nsx_router_id, edge_cluster_uuid) - tags = nsxlib_utils.build_v3_tags_payload( + tags = self.nsxlib.build_v3_tags_payload( router, resource_type='os-neutron-rport', project_name=context.tenant_name) self._routerlib.add_router_link_port(nsx_router_id, new_tier0_uuid, @@ -2264,7 +2269,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, gw_info = self._extract_external_gw(context, router, is_extract=True) router['router']['id'] = (router['router'].get('id') or uuidutils.generate_uuid()) - tags = nsxlib_utils.build_v3_tags_payload( + tags = self.nsxlib.build_v3_tags_payload( router['router'], resource_type='os-neutron-router-id', project_name=context.tenant_name) result = self._router_client.create( @@ -2530,7 +2535,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, context, router_id, network_id) display_name = utils.get_name_and_uuid( subnet['name'] or 'subnet', subnet['id']) - tags = nsxlib_utils.build_v3_tags_payload( + tags = self.nsxlib.build_v3_tags_payload( port, resource_type='os-neutron-rport-id', project_name=context.tenant_name) tags.append({'scope': 'os-subnet-id', 'tag': subnet['id']}) @@ -2799,7 +2804,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, return firewall_section def _create_security_group_backend_resources(self, secgroup): - tags = nsxlib_utils.build_v3_tags_payload( + tags = self.nsxlib.build_v3_tags_payload( secgroup, resource_type='os-neutron-secgr-id', project_name=secgroup['tenant_id']) name = self.nsxlib.ns_group.get_name(secgroup) diff --git a/vmware_nsx/plugins/nsx_v3/utils.py b/vmware_nsx/plugins/nsx_v3/utils.py index c9be160c72..f7e5667618 100644 --- a/vmware_nsx/plugins/nsx_v3/utils.py +++ b/vmware_nsx/plugins/nsx_v3/utils.py @@ -14,11 +14,18 @@ # under the License. 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 + + +NSX_NEUTRON_PLUGIN = 'NSX Neutron plugin' +OS_NEUTRON_ID_SCOPE = 'os-neutron-id' def get_nsxlib_wrapper(): - return v3.NsxLib( + nsxlib_config = config.NsxLibConfig( username=cfg.CONF.nsx_v3.nsx_api_user, password=cfg.CONF.nsx_v3.nsx_api_password, retries=cfg.CONF.nsx_v3.http_retries, @@ -30,4 +37,11 @@ def get_nsxlib_wrapper(): conn_idle_timeout=cfg.CONF.nsx_v3.conn_idle_timeout, http_provider=None, max_attempts=cfg.CONF.nsx_v3.retries, - nsx_api_managers=cfg.CONF.nsx_v3.nsx_api_managers) + nsx_api_managers=cfg.CONF.nsx_v3.nsx_api_managers, + plugin_scope=OS_NEUTRON_ID_SCOPE, + plugin_tag=NSX_NEUTRON_PLUGIN, + plugin_ver=n_version.version_info.release_string(), + dns_nameservers=cfg.CONF.nsx_v3.nameservers, + dns_domain=cfg.CONF.nsx_v3.dns_domain, + dhcp_profile_uuid=cfg.CONF.nsx_v3.dhcp_profile_uuid) + return v3.NsxLib(nsxlib_config) diff --git a/vmware_nsx/services/l2gateway/nsx_v3/driver.py b/vmware_nsx/services/l2gateway/nsx_v3/driver.py index 384d806536..3b68a64415 100644 --- a/vmware_nsx/services/l2gateway/nsx_v3/driver.py +++ b/vmware_nsx/services/l2gateway/nsx_v3/driver.py @@ -38,7 +38,6 @@ 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_nsx.nsxlib.v3 import utils as nsxlib_utils LOG = logging.getLogger(__name__) @@ -220,7 +219,7 @@ class NsxV3Driver(l2gateway_db.L2GatewayMixin): tenant_id = context.tenant_id gw_connection['tenant_id'] = tenant_id try: - tags = nsxlib_utils.build_v3_tags_payload( + tags = self._core_plugin.nsxlib.build_v3_tags_payload( gw_connection, resource_type='os-neutron-l2gw-id', project_name=context.tenant_name) bridge_endpoint = self._core_plugin.nsxlib.bridge_endpoint.create( diff --git a/vmware_nsx/services/neutron_taas/nsx_v3/driver.py b/vmware_nsx/services/neutron_taas/nsx_v3/driver.py index 8fda3e1bf4..05a268f238 100644 --- a/vmware_nsx/services/neutron_taas/nsx_v3/driver.py +++ b/vmware_nsx/services/neutron_taas/nsx_v3/driver.py @@ -31,7 +31,6 @@ 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.nsxlib.v3 import utils as nsxlib_utils from vmware_nsx.plugins.nsx_v3 import utils as v3_utils LOG = logging.getLogger(__name__) @@ -178,7 +177,8 @@ class NsxV3Driver(base_driver.TaasBaseDriver, tf.get('tap_service_id')) src_port_id = tf.get('source_port') dest_port_id = ts.get('port_id') - tags = nsxlib_utils.build_v3_tags_payload( + nsxlib = v3_utils.get_nsxlib_wrapper() + tags = nsxlib.build_v3_tags_payload( tf, resource_type='os-neutron-mirror-id', project_name=context._plugin_context.tenant_name) nsx_direction = self._convert_to_backend_direction( diff --git a/vmware_nsx/services/qos/nsx_v3/utils.py b/vmware_nsx/services/qos/nsx_v3/utils.py index 69c7072c99..98e08f49d4 100644 --- a/vmware_nsx/services/qos/nsx_v3/utils.py +++ b/vmware_nsx/services/qos/nsx_v3/utils.py @@ -26,7 +26,6 @@ from oslo_log import log as logging from vmware_nsx._i18n import _, _LW from vmware_nsx.common import exceptions as nsx_exc from vmware_nsx.db import db as nsx_db -from vmware_nsx.nsxlib.v3 import utils LOG = logging.getLogger(__name__) MAX_KBPS_MIN_VALUE = 1024 @@ -90,7 +89,7 @@ class QosNotificationsHandler(object): def _get_tags(self, context, policy): policy_dict = {'id': policy.id, 'tenant_id': policy.tenant_id} - return utils.build_v3_tags_payload( + return self._nsxlib_qos.build_v3_tags_payload( policy_dict, resource_type='os-neutron-qos-id', project_name=context.tenant_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 d79c1d3c7f..1622f899f1 100644 --- a/vmware_nsx/shell/admin/plugins/nsxv3/resources/dhcp_binding.py +++ b/vmware_nsx/shell/admin/plugins/nsxv3/resources/dhcp_binding.py @@ -21,7 +21,6 @@ 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 native_dhcp from vmware_nsx.nsxlib.v3 import nsx_constants from vmware_nsx.nsxlib.v3 import resources from vmware_nsx.shell.admin.plugins.common import constants @@ -48,7 +47,8 @@ def list_dhcp_bindings(resource, event, trigger, **kwargs): def nsx_update_dhcp_bindings(resource, event, trigger, **kwargs): """Resync DHCP bindings for NSXv3 CrossHairs.""" - nsx_version = utils.get_connected_nsxlib().get_version() + nsxlib = utils.get_connected_nsxlib() + nsx_version = nsxlib.get_version() if not nsx_utils.is_nsx_version_1_1_0(nsx_version): LOG.info(_LI("This utility is not available for NSX version %s"), nsx_version) @@ -88,11 +88,11 @@ def nsx_update_dhcp_bindings(resource, event, trigger, **kwargs): # and update the attachment type to DHCP on the corresponding # logical port of the Neutron DHCP port. network = neutron_client.get_network(port['network_id']) - server_data = native_dhcp.build_dhcp_server_config( - network, subnet, port, 'admin', - cfg.CONF.nsx_v3.nameservers, - cfg.CONF.nsx_v3.dhcp_profile_uuid, - cfg.CONF.nsx_v3.dns_domain) + net_tags = nsxlib.build_v3_tags_payload( + network, resource_type='os-neutron-net-id', + project_name='admin') + server_data = nsxlib.native_dhcp.build_server_config( + network, subnet, port, net_tags) dhcp_server = dhcp_server_resource.create(**server_data) LOG.info(_LI("Created logical DHCP server %(server)s for " "network %(network)s"), 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 7fc0286352..a901b13232 100644 --- a/vmware_nsx/shell/admin/plugins/nsxv3/resources/metadata_proxy.py +++ b/vmware_nsx/shell/admin/plugins/nsxv3/resources/metadata_proxy.py @@ -23,7 +23,6 @@ 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.nsxlib.v3 import utils as nsxlib_utils 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 @@ -105,7 +104,7 @@ def nsx_update_metadata_proxy(resource, event, trigger, **kwargs): lswitch_id = neutron_client.net_id_to_lswitch_id(network['id']) if not lswitch_id: continue - tags = nsxlib_utils.build_v3_tags_payload( + tags = utils.get_connected_nsxlib().build_v3_tags_payload( network, resource_type='os-neutron-net-id', project_name='admin') name = nsx_utils.get_name_and_uuid('%s-%s' % ( 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 ae3aa4498d..c5becc0ecb 100644 --- a/vmware_nsx/tests/unit/nsx_v3/test_dhcp_metadata.py +++ b/vmware_nsx/tests/unit/nsx_v3/test_dhcp_metadata.py @@ -30,7 +30,6 @@ 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.nsxlib.v3 import utils as nsxlib_utils from vmware_nsx.tests.unit.nsx_v3 import test_plugin @@ -457,7 +456,7 @@ class NsxNativeMetadataTestCase(test_plugin.NsxV3PluginTestCaseMixin): with self.network() as network: nsx_net_id = self.plugin._get_network_nsx_id( context.get_admin_context(), network['network']['id']) - tags = nsxlib_utils.build_v3_tags_payload( + tags = self.plugin.nsxlib.build_v3_tags_payload( network['network'], resource_type='os-neutron-net-id', project_name=None) name = utils.get_name_and_uuid('%s-%s' % ( diff --git a/vmware_nsx/tests/unit/nsxlib/v3/nsxlib_testcase.py b/vmware_nsx/tests/unit/nsxlib/v3/nsxlib_testcase.py index 1238bad4c7..97f83723c8 100644 --- a/vmware_nsx/tests/unit/nsxlib/v3/nsxlib_testcase.py +++ b/vmware_nsx/tests/unit/nsxlib/v3/nsxlib_testcase.py @@ -20,9 +20,10 @@ 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.plugins.nsx_v3 import utils as v3_utils +from vmware_nsx.nsxlib.v3 import config NSX_USER = 'admin' NSX_PASSWORD = 'default' @@ -35,6 +36,10 @@ NSX_HTTP_READ_TIMEOUT = 180 NSX_CONCURENT_CONN = 10 NSX_CONN_IDLE_TIME = 10 +PLUGIN_SCOPE = "plugin scope" +PLUGIN_TAG = "plugin tag" +PLUGIN_VER = "plugin ver" + def _mock_nsxlib(): def _return_id_key(*args, **kwargs): @@ -84,13 +89,32 @@ def _mock_nsxlib(): 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() - self.nsxlib = v3_utils.get_nsxlib_wrapper() + nsxlib_config = get_default_nsxlib_config() + self.nsxlib = v3.NsxLib(nsxlib_config) # print diffs when assert comparisons fail self.maxDiff = None @@ -135,7 +159,8 @@ class NsxClientTestCase(NsxLibTestCase): http_read_timeout=None, conn_idle_timeout=None, nsx_api_managers=None): - super(NsxClientTestCase.MockNSXClusteredAPI, self).__init__( + + nsxlib_config = config.NsxLibConfig( username=username or NSX_USER, password=password or NSX_PASSWORD, retries=retries or NSX_HTTP_RETRIES, @@ -148,7 +173,13 @@ class NsxClientTestCase(NsxLibTestCase): 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]) + 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): @@ -279,16 +310,10 @@ class NsxClientTestCase(NsxLibTestCase): mock_provider.default_scheme = 'https' mock_provider.validate_connection = validate_conn_func - return nsx_cluster.NSXClusteredAPI( - username=NSX_USER, - password=NSX_PASSWORD, - retries=NSX_HTTP_RETRIES, - insecure=NSX_INSECURE, - ca_file=NSX_CERT, - concurrent_connections=(concurrent_connections or - NSX_CONCURENT_CONN), - http_timeout=NSX_HTTP_TIMEOUT, - http_read_timeout=NSX_HTTP_READ_TIMEOUT, - conn_idle_timeout=NSX_CONN_IDLE_TIME, - http_provider=mock_provider, - nsx_api_managers=conf_managers) + 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_cluster.py b/vmware_nsx/tests/unit/nsxlib/v3/test_cluster.py index fa5998f08f..252e133e6e 100644 --- a/vmware_nsx/tests/unit/nsxlib/v3/test_cluster.py +++ b/vmware_nsx/tests/unit/nsxlib/v3/test_cluster.py @@ -38,13 +38,14 @@ class RequestsHTTPProviderTestCase(unittest.TestCase): def test_new_connection(self): mock_api = mock.Mock() - mock_api._username = 'nsxuser' - mock_api._password = 'nsxpassword' - mock_api.retries = 100 - mock_api.insecure = True - mock_api._ca_file = None - mock_api.http_timeout = 99 - mock_api.conn_idle_timeout = 39 + 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', @@ -196,3 +197,8 @@ class ClusteredAPITestCase(nsxlib_testcase.NsxClientTestCase): 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_qos_switching_profile.py b/vmware_nsx/tests/unit/nsxlib/v3/test_qos_switching_profile.py index 4d49dcae13..e109517f62 100644 --- a/vmware_nsx/tests/unit/nsxlib/v3/test_qos_switching_profile.py +++ b/vmware_nsx/tests/unit/nsxlib/v3/test_qos_switching_profile.py @@ -52,7 +52,7 @@ class NsxLibQosTestCase(nsxlib_testcase.NsxClientTestCase): body["description"] = description for shaper in body["shaper_configuration"]: - # Neutron currently support only shaping of Egress traffic + # We currently support only shaping of Egress traffic if shaper["resource_type"] == "EgressRateShaper": shaper["enabled"] = shaping_enabled if burst_size: diff --git a/vmware_nsx/tests/unit/nsxlib/v3/test_resources.py b/vmware_nsx/tests/unit/nsxlib/v3/test_resources.py index 4736cec007..bbe7624aa5 100644 --- a/vmware_nsx/tests/unit/nsxlib/v3/test_resources.py +++ b/vmware_nsx/tests/unit/nsxlib/v3/test_resources.py @@ -93,7 +93,7 @@ class TestSwitchingProfileTestCase(nsxlib_testcase.NsxClientTestCase): mocked_resource = self._mocked_switching_profile() mocked_resource.create_spoofguard_profile( - 'neutron-spoof', 'spoofguard-for-neutron', + 'plugin-spoof', 'spoofguard-for-plugin', whitelist_ports=True, tags=tags) test_client.assert_json_call( @@ -101,8 +101,8 @@ class TestSwitchingProfileTestCase(nsxlib_testcase.NsxClientTestCase): 'https://1.2.3.4/api/v1/switching-profiles', data=jsonutils.dumps({ 'resource_type': profile_types.SPOOF_GUARD, - 'display_name': 'neutron-spoof', - 'description': 'spoofguard-for-neutron', + 'display_name': 'plugin-spoof', + 'description': 'spoofguard-for-plugin', 'white_list_providers': ['LPORT_BINDINGS'], 'tags': tags }, sort_keys=True)) @@ -123,7 +123,7 @@ class TestSwitchingProfileTestCase(nsxlib_testcase.NsxClientTestCase): mocked_resource = self._mocked_switching_profile() mocked_resource.create_dhcp_profile( - 'neutron-dhcp', 'dhcp-for-neutron', + 'plugin-dhcp', 'dhcp-for-plugin', tags=tags) test_client.assert_json_call( @@ -135,8 +135,8 @@ class TestSwitchingProfileTestCase(nsxlib_testcase.NsxClientTestCase): 'white_list': [] }, 'resource_type': profile_types.SWITCH_SECURITY, - 'display_name': 'neutron-dhcp', - 'description': 'dhcp-for-neutron', + 'display_name': 'plugin-dhcp', + 'description': 'dhcp-for-plugin', 'tags': tags, 'dhcp_filter': { 'client_block_enabled': True, @@ -168,7 +168,7 @@ class TestSwitchingProfileTestCase(nsxlib_testcase.NsxClientTestCase): mocked_resource = self._mocked_switching_profile() mocked_resource.create_mac_learning_profile( - 'neutron-mac-learning', 'mac-learning-for-neutron', + 'plugin-mac-learning', 'mac-learning-for-plugin', tags=tags) test_client.assert_json_call( @@ -179,8 +179,8 @@ class TestSwitchingProfileTestCase(nsxlib_testcase.NsxClientTestCase): 'enabled': True, }, 'resource_type': profile_types.MAC_LEARNING, - 'display_name': 'neutron-mac-learning', - 'description': 'mac-learning-for-neutron', + 'display_name': 'plugin-mac-learning', + 'description': 'mac-learning-for-plugin', 'tags': tags, 'source_mac_change_allowed': True, }, sort_keys=True)) diff --git a/vmware_nsx/tests/unit/nsxlib/v3/test_utils.py b/vmware_nsx/tests/unit/nsxlib/v3/test_utils.py index 3d9a7dd034..e04190f6b4 100644 --- a/vmware_nsx/tests/unit/nsxlib/v3/test_utils.py +++ b/vmware_nsx/tests/unit/nsxlib/v3/test_utils.py @@ -13,71 +13,69 @@ # See the License for the specific language governing permissions and # limitations under the License. -from neutron.tests.unit.db import test_db_base_plugin_v2 as test_plugin -from neutron import version 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(test_plugin.NeutronDbPluginV2TestCase, - nsxlib_testcase.NsxClientTestCase): +class TestNsxV3Utils(nsxlib_testcase.NsxClientTestCase): def test_build_v3_tags_payload(self): - result = utils.build_v3_tags_payload( + result = self.nsxlib.build_v3_tags_payload( {'id': 'fake_id', 'tenant_id': 'fake_tenant_id'}, - resource_type='os-neutron-net-id', + resource_type='os-net-id', project_name='fake_tenant_name') - expected = [{'scope': 'os-neutron-net-id', 'tag': 'fake_id'}, + 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': version.version_info.release_string()}] + 'tag': nsxlib_testcase.PLUGIN_VER}] self.assertEqual(expected, result) def test_build_v3_tags_payload_internal(self): - result = utils.build_v3_tags_payload( + result = self.nsxlib.build_v3_tags_payload( {'id': 'fake_id', 'tenant_id': 'fake_tenant_id'}, - resource_type='os-neutron-net-id', + resource_type='os-net-id', project_name=None) - expected = [{'scope': 'os-neutron-net-id', 'tag': 'fake_id'}, + expected = [{'scope': 'os-net-id', 'tag': 'fake_id'}, {'scope': 'os-project-id', 'tag': 'fake_tenant_id'}, - {'scope': 'os-project-name', 'tag': 'NSX Neutron plugin'}, + {'scope': 'os-project-name', + 'tag': nsxlib_testcase.PLUGIN_TAG}, {'scope': 'os-api-version', - 'tag': version.version_info.release_string()}] + 'tag': nsxlib_testcase.PLUGIN_VER}] self.assertEqual(expected, result) def test_build_v3_tags_payload_invalid_length(self): self.assertRaises(n_exc.InvalidInput, - utils.build_v3_tags_payload, + self.nsxlib.build_v3_tags_payload, {'id': 'fake_id', 'tenant_id': 'fake_tenant_id'}, - resource_type='os-neutron-maldini-rocks-id', + resource_type='os-longer-maldini-rocks-id', project_name='fake') def test_build_v3_api_version_tag(self): - result = utils.build_v3_api_version_tag() - expected = [{'scope': 'os-neutron-id', - 'tag': 'NSX Neutron plugin'}, + result = self.nsxlib.build_v3_api_version_tag() + expected = [{'scope': nsxlib_testcase.PLUGIN_SCOPE, + 'tag': nsxlib_testcase.PLUGIN_TAG}, {'scope': 'os-api-version', - 'tag': version.version_info.release_string()}] + 'tag': nsxlib_testcase.PLUGIN_VER}] self.assertEqual(expected, result) def test_is_internal_resource(self): - project_tag = utils.build_v3_tags_payload( + project_tag = self.nsxlib.build_v3_tags_payload( {'id': 'fake_id', 'tenant_id': 'fake_tenant_id'}, - resource_type='os-neutron-net-id', + resource_type='os-net-id', project_name=None) - internal_tag = utils.build_v3_api_version_tag() + internal_tag = self.nsxlib.build_v3_api_version_tag() - expect_false = utils.is_internal_resource({'tags': project_tag}) + expect_false = self.nsxlib.is_internal_resource({'tags': project_tag}) self.assertFalse(expect_false) - expect_true = utils.is_internal_resource({'tags': internal_tag}) + expect_true = self.nsxlib.is_internal_resource({'tags': internal_tag}) self.assertTrue(expect_true) def test_get_name_and_uuid(self): @@ -93,16 +91,16 @@ class TestNsxV3Utils(test_plugin.NeutronDbPluginV2TestCase, self.assertEqual(expected, short_name) def test_build_v3_tags_max_length_payload(self): - result = utils.build_v3_tags_payload( + result = self.nsxlib.build_v3_tags_payload( {'id': 'X' * 255, 'tenant_id': 'X' * 255}, - resource_type='os-neutron-net-id', + resource_type='os-net-id', project_name='X' * 255) - expected = [{'scope': 'os-neutron-net-id', 'tag': 'X' * 40}, + 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': version.version_info.release_string()}] + 'tag': nsxlib_testcase.PLUGIN_VER}] self.assertEqual(expected, result) def test_add_v3_tag(self): @@ -123,59 +121,59 @@ class TestNsxV3Utils(test_plugin.NeutronDbPluginV2TestCase, 'fake-tag') def test_update_v3_tags_addition(self): - tags = [{'scope': 'os-neutron-net-id', 'tag': 'X' * 40}, + 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': version.version_info.release_string()}] + 'tag': nsxlib_testcase.PLUGIN_VER}] resources = [{'scope': 'os-instance-uuid', 'tag': 'A' * 40}] tags = utils.update_v3_tags(tags, resources) - expected = [{'scope': 'os-neutron-net-id', 'tag': 'X' * 40}, + 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': version.version_info.release_string()}, + '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-neutron-net-id', 'tag': 'X' * 40}, + 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': version.version_info.release_string()}] - resources = [{'scope': 'os-neutron-net-id', + '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': version.version_info.release_string()}] + '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-neutron-net-id', 'tag': 'X' * 40}, + 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': version.version_info.release_string()}] + 'tag': nsxlib_testcase.PLUGIN_VER}] resources = [{'scope': 'os-project-id', 'tag': 'A' * 40}] tags = utils.update_v3_tags(tags, resources) - expected = [{'scope': 'os-neutron-net-id', 'tag': 'X' * 40}, + 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': version.version_info.release_string()}] + '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-neutron-net-id', 'tag': 'X' * 40}, + 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'}, @@ -183,7 +181,7 @@ class TestNsxV3Utils(test_plugin.NeutronDbPluginV2TestCase, 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-neutron-net-id', 'tag': 'X' * 40}, + 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'}, @@ -192,14 +190,14 @@ class TestNsxV3Utils(test_plugin.NeutronDbPluginV2TestCase, sorted(tags, key=lambda x: x.get('tag'))) def test_update_v3_tags_repetitive_scopes_remove(self): - tags = [{'scope': 'os-neutron-net-id', 'tag': 'X' * 40}, + 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-neutron-net-id', 'tag': 'X' * 40}, + 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')), 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 9bc16c4fa7..0f97a7a101 100644 --- a/vmware_nsx/tests/unit/services/qos/test_nsxv3_notification.py +++ b/vmware_nsx/tests/unit/services/qos/test_nsxv3_notification.py @@ -25,7 +25,7 @@ from neutron.services.qos import qos_plugin from neutron.tests.unit.services.qos import base from vmware_nsx.db import db as nsx_db -from vmware_nsx.nsxlib.v3 import utils +from vmware_nsx.plugins.nsx_v3 import utils as v3_utils from vmware_nsx.services.qos.nsx_v3 import utils as qos_utils from vmware_nsx.tests.unit.nsx_v3 import test_plugin @@ -85,6 +85,8 @@ class TestQosNsxV3Notification(base.BaseQosTestCase, self.peak_bw_multiplier = cfg.CONF.NSX.qos_peak_bw_multiplier + self.nsxlib = v3_utils.get_nsxlib_wrapper() + @mock.patch( 'neutron.objects.rbac_db.RbacNeutronDbObjectMixin' '.create_rbac_policy') @@ -100,7 +102,7 @@ class TestQosNsxV3Notification(base.BaseQosTestCase, with mock.patch('neutron.objects.qos.policy.QosPolicy.create'): policy = self.qos_plugin.create_policy(self.ctxt, self.policy_data) - expected_tags = utils.build_v3_tags_payload( + expected_tags = self.nsxlib.build_v3_tags_payload( policy, resource_type='os-neutron-qos-id', project_name=self.ctxt.tenant_name) @@ -129,7 +131,7 @@ class TestQosNsxV3Notification(base.BaseQosTestCase, self.ctxt, self.policy.id, {'policy': fields}) # verify that the profile was updated with the correct data self.policy_data["policy"]["id"] = self.policy.id - expected_tags = utils.build_v3_tags_payload( + expected_tags = self.nsxlib.build_v3_tags_payload( self.policy_data["policy"], resource_type='os-neutron-qos-id', project_name=self.ctxt.tenant_name)