nsxlib refactor: config + neutron deps

1. new config class was added to allow all the classes to use the same object
2. removing dependencies of the neutron project in nsxlib code & tests

Change-Id: I15ace2ab60c1e4307d7076426c48ecc7a242e792
This commit is contained in:
Adit Sarfaty 2016-09-20 15:21:09 +03:00
parent 701de5c48f
commit 34f3ee275e
21 changed files with 439 additions and 325 deletions

View File

@ -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

View File

@ -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)

View File

@ -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:
[<scheme>://]<ip_adress>[:<port>]
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)

View File

@ -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}

View File

@ -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):

View File

@ -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)

View File

@ -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 <resource_type>:<resource-id>, os-project-id:<tenant-id>,
os-project-name:<project_name> os-api-version:<neutron-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 <resource_type>:<resource-id>, os-project-id:<project-id>,
os-project-name:<project_name> os-api-version:<plugin-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}]

View File

@ -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)

View File

@ -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)

View File

@ -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(

View File

@ -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(

View File

@ -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)

View File

@ -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"),

View File

@ -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' % (

View File

@ -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' % (

View File

@ -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)

View File

@ -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()

View File

@ -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:

View File

@ -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))

View File

@ -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')),

View File

@ -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)