NSX-Policy: Skeleton for the new NSX Policy plugin

Change-Id: Ia3195293270ceb3af1f14fa280de43019ca44b7f
This commit is contained in:
Adit Sarfaty 2018-08-30 15:12:04 +03:00
parent dcc3e697d1
commit 3be8af0c37
10 changed files with 784 additions and 66 deletions

View File

@ -32,6 +32,7 @@ neutron.core_plugins =
vmware_nsx = vmware_nsx.plugin:NsxPlugin
vmware_nsxv = vmware_nsx.plugin:NsxVPlugin
vmware_nsxv3 = vmware_nsx.plugin:NsxV3Plugin
vmware_nsxp = vmware_nsx.plugin:NsxPolicyPlugin
vmware_dvs = vmware_nsx.plugin:NsxDvsPlugin
vmware_nsxtvd = vmware_nsx.plugin:NsxTVDPlugin
firewall_drivers =

View File

@ -263,7 +263,8 @@ nsx_common_opts = [
help=_("(Optional) List of email addresses for "
"notifications.")),
]
nsx_v3_opts = [
nsx_v3_and_p = [
cfg.ListOpt('nsx_api_user',
default=['admin'],
help=_('User names for the NSX managers')),
@ -293,27 +294,6 @@ nsx_v3_opts = [
default='nsx-db',
choices=['nsx-db', 'none'],
help=_("Storage type for client certificate sensitive data")),
cfg.StrOpt('default_overlay_tz',
help=_("This is the name or UUID of the default NSX overlay "
"transport zone that will be used for creating "
"tunneled isolated Neutron networks. It needs to be "
"created in NSX before starting Neutron with the NSX "
"plugin.")),
cfg.StrOpt('default_vlan_tz',
help=_("(Optional) Only required when creating VLAN or flat "
"provider networks. Name or UUID of default NSX VLAN "
"transport zone that will be used for bridging between "
"Neutron networks, if no physical network has been "
"specified")),
cfg.StrOpt('default_bridge_cluster',
help=_("(Optional) Name or UUID of the default NSX bridge "
"cluster that will be used to perform L2 gateway "
"bridging between VXLAN and VLAN networks. If default "
"bridge cluster UUID is not specified, admin will have "
"to manually create a L2 gateway corresponding to a "
"NSX Bridge Cluster using L2 gateway APIs. This field "
"must be specified on one of the active neutron "
"servers only.")),
cfg.IntOpt('retries',
default=10,
help=_('Maximum number of times to retry API requests upon '
@ -352,6 +332,30 @@ nsx_v3_opts = [
cfg.IntOpt('redirects',
default=2,
help=_('Number of times a HTTP redirect should be followed.')),
]
nsx_v3_opts = nsx_v3_and_p + [
cfg.StrOpt('default_overlay_tz',
help=_("This is the name or UUID of the default NSX overlay "
"transport zone that will be used for creating "
"tunneled isolated Neutron networks. It needs to be "
"created in NSX before starting Neutron with the NSX "
"plugin.")),
cfg.StrOpt('default_vlan_tz',
help=_("(Optional) Only required when creating VLAN or flat "
"provider networks. Name or UUID of default NSX VLAN "
"transport zone that will be used for bridging between "
"Neutron networks, if no physical network has been "
"specified")),
cfg.StrOpt('default_bridge_cluster',
help=_("(Optional) Name or UUID of the default NSX bridge "
"cluster that will be used to perform L2 gateway "
"bridging between VXLAN and VLAN networks. If default "
"bridge cluster UUID is not specified, admin will have "
"to manually create a L2 gateway corresponding to a "
"NSX Bridge Cluster using L2 gateway APIs. This field "
"must be specified on one of the active neutron "
"servers only.")),
cfg.StrOpt('default_tier0_router',
help=_("Name or UUID of the default tier0 router that will be "
"used for connecting to tier1 logical routers and "
@ -474,6 +478,8 @@ nsx_v3_opts = [
]
nsx_p_opts = nsx_v3_and_p + []
DEFAULT_STATUS_CHECK_INTERVAL = 2000
DEFAULT_MINIMUM_POOLED_EDGES = 1
DEFAULT_MAXIMUM_POOLED_EDGES = 3
@ -923,6 +929,7 @@ nsx_tvd_opts = [
cfg.CONF.register_opts(connection_opts)
cfg.CONF.register_opts(cluster_opts)
cfg.CONF.register_opts(nsx_common_opts)
cfg.CONF.register_opts(nsx_p_opts, group="nsx_p")
cfg.CONF.register_opts(nsx_v3_opts, group="nsx_v3")
cfg.CONF.register_opts(nsxv_opts, group="nsxv")
cfg.CONF.register_opts(nsx_tvd_opts, group="nsx_tvd")

View File

@ -32,6 +32,7 @@ class NsxPlugins(object):
NSX_V = 'nsx-v'
NSX_T = 'nsx-t'
DVS = 'dvs'
NSX_P = 'nsx-p' # Note(asarfaty) this option is missing from the DB enum
VALID_TYPES = [NsxPlugins.NSX_V,

View File

@ -23,6 +23,7 @@ from neutron.db.models import securitygroup # noqa
from vmware_nsx.plugins.dvs import plugin as dvs
from vmware_nsx.plugins.nsx import plugin as nsx
from vmware_nsx.plugins.nsx_mh import plugin as nsx_mh
from vmware_nsx.plugins.nsx_p import plugin as nsx_p
from vmware_nsx.plugins.nsx_v import plugin as nsx_v
from vmware_nsx.plugins.nsx_v3 import plugin as nsx_v3
@ -30,4 +31,5 @@ NsxDvsPlugin = dvs.NsxDvsV2
NsxPlugin = nsx_mh.NsxPluginV2
NsxVPlugin = nsx_v.NsxVPluginV2
NsxV3Plugin = nsx_v3.NsxV3Plugin
NsxPolicyPlugin = nsx_p.NsxPolicyPlugin
NsxTVDPlugin = nsx.NsxTVDPlugin

View File

@ -20,6 +20,7 @@ from neutron.db import _resource_extend as resource_extend
from neutron.db import address_scope_db
from neutron.db import api as db_api
from neutron.db import db_base_plugin_v2
from neutron.db import l3_attrs_db
from neutron.db import l3_db
from neutron.db import models_v2
from neutron_lib.api.definitions import address_scope as ext_address_scope
@ -552,6 +553,23 @@ class NsxPluginBase(db_base_plugin_v2.NeutronDbPluginV2,
self._assert_on_vpn_port_change(original_port)
def _process_extra_attr_router_create(self, context, router_db, r):
for extra_attr in l3_attrs_db.get_attr_info().keys():
if (extra_attr in r and
validators.is_attr_set(r.get(extra_attr))):
self.set_extra_attr_value(context, router_db,
extra_attr, r[extra_attr])
def _get_interface_network(self, context, interface_info):
is_port, is_sub = self._validate_interface_info(interface_info)
if is_port:
net_id = self.get_port(context,
interface_info['port_id'])['network_id']
elif is_sub:
net_id = self.get_subnet(context,
interface_info['subnet_id'])['network_id']
return net_id
def get_housekeeper(self, context, name, fields=None):
# run the job in readonly mode and get the results
self.housekeeper.run(context, name, readonly=True)

View File

View File

@ -0,0 +1,684 @@
# Copyright 2018 VMware, Inc.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_config import cfg
from oslo_log import log
from oslo_utils import excutils
import webob.exc
from neutron.db import _resource_extend as resource_extend
from neutron.db import agentschedulers_db
from neutron.db import allowedaddresspairs_db as addr_pair_db
from neutron.db import api as db_api
from neutron.db import dns_db
from neutron.db import external_net_db
from neutron.db import extradhcpopt_db
from neutron.db import extraroute_db
from neutron.db import l3_attrs_db
from neutron.db import l3_gwmode_db
from neutron.db.models import l3 as l3_db_models
from neutron.db.models import securitygroup as securitygroup_model # noqa
from neutron.db import models_v2
from neutron.db import portbindings_db
from neutron.db import portsecurity_db
from neutron.db import securitygroups_db
from neutron.db import vlantransparent_db
from neutron.extensions import providernet
from neutron.quota import resource_registry
from neutron_lib.api.definitions import external_net
from neutron_lib.api.definitions import l3 as l3_apidef
from neutron_lib.api.definitions import port_security as psec
from neutron_lib.api import faults
from neutron_lib.api import validators
from neutron_lib.callbacks import events
from neutron_lib.callbacks import registry
from neutron_lib.callbacks import resources
from neutron_lib import constants as const
from neutron_lib.db import utils as db_utils
from neutron_lib import exceptions as n_exc
from vmware_nsx._i18n import _
from vmware_nsx.common import config # noqa
from vmware_nsx.common import exceptions as nsx_exc
from vmware_nsx.common import l3_rpc_agent_api
from vmware_nsx.common import locking
from vmware_nsx.common import managers
from vmware_nsx.db import db as nsx_db
from vmware_nsx.db import extended_security_group_rule as extend_sg_rule
from vmware_nsx.db import maclearning as mac_db
from vmware_nsx.extensions import projectpluginmap
from vmware_nsx.plugins.common import plugin as nsx_plugin_common
from vmware_nsx.plugins.nsx_v3 import utils as v3_utils
from vmware_nsxlib.v3 import exceptions as nsx_lib_exc
from vmware_nsxlib.v3 import nsx_constants as nsxlib_consts
from vmware_nsxlib.v3 import utils as nsxlib_utils
LOG = log.getLogger(__name__)
@resource_extend.has_resource_extenders
class NsxPolicyPlugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
addr_pair_db.AllowedAddressPairsMixin,
nsx_plugin_common.NsxPluginBase,
extend_sg_rule.ExtendedSecurityGroupRuleMixin,
securitygroups_db.SecurityGroupDbMixin,
external_net_db.External_net_db_mixin,
extraroute_db.ExtraRoute_db_mixin,
l3_gwmode_db.L3_NAT_db_mixin,
portbindings_db.PortBindingMixin,
portsecurity_db.PortSecurityDbMixin,
extradhcpopt_db.ExtraDhcpOptMixin,
dns_db.DNSDbMixin,
vlantransparent_db.Vlantransparent_db_mixin,
mac_db.MacLearningDbMixin,
l3_attrs_db.ExtraAttributesMixin):
__native_bulk_support = True
__native_pagination_support = True
__native_sorting_support = True
supported_extension_aliases = ["allowed-address-pairs",
"address-scope",
"quotas",
"binding",
"extra_dhcp_opt",
"agent",
"dhcp_agent_scheduler",
"ext-gw-mode",
"security-group",
"secgroup-rule-local-ip-prefix",
"port-security",
"provider",
"external-net",
"extraroute",
"router",
"subnet_allocation",
"port-security-groups-filtering"]
@resource_registry.tracked_resources(
network=models_v2.Network,
port=models_v2.Port,
subnet=models_v2.Subnet,
subnetpool=models_v2.SubnetPool,
security_group=securitygroup_model.SecurityGroup,
security_group_rule=securitygroup_model.SecurityGroupRule,
router=l3_db_models.Router,
floatingip=l3_db_models.FloatingIP)
def __init__(self):
self.fwaas_callbacks = None
self.init_is_complete = False
nsxlib_utils.set_is_attr_callback(validators.is_attr_set)
self._extend_fault_map()
extension_drivers = cfg.CONF.nsx_extension_drivers
self._extension_manager = managers.ExtensionManager(
extension_drivers=extension_drivers)
super(NsxPolicyPlugin, self).__init__()
# Bind the dummy L3 notifications
self.l3_rpc_notifier = l3_rpc_agent_api.L3NotifyAPI()
LOG.info("Starting NsxPolicyPlugin (Experimental only!)")
self._extension_manager.initialize()
self.supported_extension_aliases.extend(
self._extension_manager.extension_aliases())
self.nsxpolicy = v3_utils.get_nsxpolicy_wrapper()
nsxlib_utils.set_inject_headers_callback(v3_utils.inject_headers)
self._validate_nsx_policy_version()
self.cfg_group = 'nsx_p' # group name for nsx_p section in nsx.ini
self._prepare_default_rules()
# subscribe the init complete method last, so it will be called only
# if init was successful
registry.subscribe(self.init_complete,
resources.PROCESS,
events.AFTER_INIT)
def _validate_nsx_policy_version(self):
self._nsx_version = self.nsxpolicy.get_version()
LOG.info("NSX Version: %s", self._nsx_version)
if not self.nsxpolicy.feature_supported(
nsxlib_consts.FEATURE_NSX_POLICY_NETWORKING):
msg = (_("The NSX Policy plugin cannot be used with NSX version "
"%(ver)s") % {'ver': self._nsx_version})
raise nsx_exc.NsxPluginException(err_msg=msg)
def _prepare_default_rules(self):
#TODO(asarfaty): implement
pass
@staticmethod
def plugin_type():
return projectpluginmap.NsxPlugins.NSX_P
@staticmethod
def is_tvd_plugin():
return False
def init_complete(self, resource, event, trigger, payload=None):
with locking.LockManager.get_lock('plugin-init-complete'):
if self.init_is_complete:
# Should be called only once per worker
return
# reinitialize the cluster upon fork for api workers to ensure
# each process has its own keepalive loops + state
self.nsxpolicy.reinitialize_cluster(resource, event, trigger,
payload=payload)
self.init_is_complete = True
def _extend_fault_map(self):
"""Extends the Neutron Fault Map.
Exceptions specific to the NSX Plugin are mapped to standard
HTTP Exceptions.
"""
#TODO(asarfaty): consider reusing the nsx-t code here
faults.FAULT_MAP.update({nsx_lib_exc.ManagerError:
webob.exc.HTTPBadRequest,
nsx_lib_exc.ServiceClusterUnavailable:
webob.exc.HTTPServiceUnavailable,
nsx_lib_exc.ClientCertificateNotTrusted:
webob.exc.HTTPBadRequest,
nsx_exc.SecurityGroupMaximumCapacityReached:
webob.exc.HTTPBadRequest,
nsx_lib_exc.NsxLibInvalidInput:
webob.exc.HTTPBadRequest,
})
def _create_network_at_the_backend(self, context, net_data):
#TODO(asarfaty): implement, using nsx-id the same as the neutron id
pass
def _validate_external_net_create(self, net_data):
#TODO(asarfaty): implement
pass
def create_network(self, context, network):
net_data = network['network']
#TODO(asarfaty): network validation
external = net_data.get(external_net.EXTERNAL)
is_external_net = validators.is_attr_set(external) and external
tenant_id = net_data['tenant_id']
self._ensure_default_security_group(context, tenant_id)
if is_external_net:
self._validate_external_net_create(net_data)
# Create the neutron network
with db_api.context_manager.writer.using(context):
# Create network in Neutron
created_net = super(NsxPolicyPlugin, self).create_network(
context, network)
self._extension_manager.process_create_network(
context, net_data, created_net)
if psec.PORTSECURITY not in net_data:
net_data[psec.PORTSECURITY] = True
self._process_network_port_security_create(
context, net_data, created_net)
self._process_l3_create(context, created_net, net_data)
# Create the backend NSX network
if not is_external_net:
try:
self._create_network_at_the_backend(context, net_data)
except Exception as e:
LOG.exception("Failed to create NSX network network: %s", e)
with excutils.save_and_reraise_exception():
super(NsxPolicyPlugin, self).delete_network(
context, created_net['id'])
# this extra lookup is necessary to get the
# latest db model for the extension functions
net_model = self._get_network(context, created_net['id'])
resource_extend.apply_funcs('networks', created_net, net_model)
return created_net
def delete_network(self, context, network_id):
with db_api.context_manager.writer.using(context):
self._process_l3_delete(context, network_id)
return super(NsxPolicyPlugin, self).delete_network(
context, network_id)
if not self._network_is_external(context, network_id):
# TODO(asarfaty) delete the NSX logical network
pass
def update_network(self, context, id, network):
original_net = super(NsxPolicyPlugin, self).get_network(context, id)
net_data = network['network']
LOG.debug("Updating network %s %s->%s", id, original_net, net_data)
# Neutron does not support changing provider network values
providernet._raise_if_updates_provider_attributes(net_data)
extern_net = self._network_is_external(context, id)
# Do not support changing external/non-external networks
if (external_net.EXTERNAL in net_data and
net_data[external_net.EXTERNAL] != extern_net):
err_msg = _("Cannot change the router:external flag of a network")
raise n_exc.InvalidInput(error_message=err_msg)
updated_net = super(NsxPolicyPlugin, self).update_network(context, id,
network)
self._extension_manager.process_update_network(context, net_data,
updated_net)
self._process_l3_update(context, updated_net, network['network'])
#TODO(asarfaty): update the Policy manager
return updated_net
def get_network(self, context, id, fields=None):
with db_api.context_manager.reader.using(context):
# Get network from Neutron database
network = self._get_network(context, id)
# Don't do field selection here otherwise we won't be able to add
# provider networks fields
net = self._make_network_dict(network, context=context)
return db_utils.resource_fields(net, fields)
def get_networks(self, context, filters=None, fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
# Get networks from Neutron database
filters = filters or {}
with db_api.context_manager.reader.using(context):
networks = (
super(NsxPolicyPlugin, self).get_networks(
context, filters, fields, sorts,
limit, marker, page_reverse))
# TODO(asarfaty) Add plugin/provider network fields
return (networks if not fields else
[db_utils.resource_fields(network,
fields) for network in networks])
def create_subnet(self, context, subnet):
self._validate_host_routes_input(subnet)
created_subnet = super(
NsxPolicyPlugin, self).create_subnet(context, subnet)
# TODO(asarfaty): Handle dhcp on the policy manager
return created_subnet
def delete_subnet(self, context, subnet_id):
# TODO(asarfaty): cleanup dhcp on the policy manager
super(NsxPolicyPlugin, self).delete_subnet(context, subnet_id)
def update_subnet(self, context, subnet_id, subnet):
updated_subnet = None
orig = self._get_subnet(context, subnet_id)
self._validate_host_routes_input(subnet,
orig_enable_dhcp=orig['enable_dhcp'],
orig_host_routes=orig['routes'])
# TODO(asarfaty): Handle dhcp updates on the policy manager
updated_subnet = super(NsxPolicyPlugin, self).update_subnet(
context, subnet_id, subnet)
self._extension_manager.process_update_subnet(
context, subnet['subnet'], updated_subnet)
return updated_subnet
def _create_port_at_the_backend(self, context, port_data):
#TODO(asarfaty): implement
pass
def _cleanup_port(self, context, port_id, lport_id):
super(NsxPolicyPlugin, self).delete_port(context, port_id)
#TODO(asarfaty): Delete the NSX logical port
def base_create_port(self, context, port):
neutron_db = super(NsxPolicyPlugin, self).create_port(context, port)
self._extension_manager.process_create_port(
context, port['port'], neutron_db)
return neutron_db
def create_port(self, context, port, l2gw_port_check=False):
port_data = port['port']
self._validate_max_ips_per_port(port_data.get('fixed_ips', []),
port_data.get('device_owner'))
with db_api.context_manager.writer.using(context):
is_external_net = self._network_is_external(
context, port_data['network_id'])
if is_external_net:
self._assert_on_external_net_with_compute(port_data)
neutron_db = self.base_create_port(context, port)
port["port"].update(neutron_db)
if not is_external_net:
try:
self._create_port_at_the_backend(context, port_data)
except Exception as e:
with excutils.save_and_reraise_exception():
LOG.error('Failed to create port %(id)s on NSX '
'backend. Exception: %(e)s',
{'id': neutron_db['id'], 'e': e})
self._cleanup_port(context, neutron_db['id'], None)
# this extra lookup is necessary to get the
# latest db model for the extension functions
port_model = self._get_port(context, port_data['id'])
resource_extend.apply_funcs('ports', port_data, port_model)
kwargs = {'context': context, 'port': neutron_db}
registry.notify(resources.PORT, events.AFTER_CREATE, self, **kwargs)
return neutron_db
def delete_port(self, context, port_id,
l3_port_check=True, l2gw_port_check=True,
force_delete_dhcp=False,
force_delete_vpn=False):
port = self.get_port(context, port_id)
if not self._network_is_external(context, port['network_id']):
#TODO(asarfaty): Delete the NSX logical port
pass
self.disassociate_floatingips(context, port_id)
super(NsxPolicyPlugin, self).delete_port(context, port_id)
def _update_port_on_backend(self, context, lport_id,
original_port, updated_port):
#TODO(asarfaty): implement
pass
def update_port(self, context, id, port):
with db_api.context_manager.writer.using(context):
# get the original port, and keep it honest as it is later used
# for notifications
original_port = super(NsxPolicyPlugin, self).get_port(context, id)
port_data = port['port']
is_external_net = self._network_is_external(
context, original_port['network_id'])
if is_external_net:
self._assert_on_external_net_with_compute(port_data)
device_owner = (port_data['device_owner']
if 'device_owner' in port_data
else original_port.get('device_owner'))
self._validate_max_ips_per_port(
port_data.get('fixed_ips', []), device_owner)
updated_port = super(NsxPolicyPlugin, self).update_port(context,
id, port)
self._extension_manager.process_update_port(context, port_data,
updated_port)
# copy values over - except fixed_ips as
# they've already been processed
port_data.pop('fixed_ips', None)
updated_port.update(port_data)
# update the port in the backend, only if it exists in the DB
# (i.e not external net)
if not is_external_net:
self._update_port_on_backend(context, id,
original_port, updated_port)
# Make sure the port revision is updated
if 'revision_number' in updated_port:
port_model = self._get_port(context, id)
updated_port['revision_number'] = port_model.revision_number
# Notifications must be sent after the above transaction is complete
kwargs = {
'context': context,
'port': updated_port,
'mac_address_updated': False,
'original_port': original_port,
}
registry.notify(resources.PORT, events.AFTER_UPDATE, self, **kwargs)
return updated_port
def get_port(self, context, id, fields=None):
port = super(NsxPolicyPlugin, self).get_port(context, id, fields=None)
if 'id' in port:
port_model = self._get_port(context, port['id'])
resource_extend.apply_funcs('ports', port, port_model)
return db_utils.resource_fields(port, fields)
def get_ports(self, context, filters=None, fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
filters = filters or {}
self._update_filters_with_sec_group(context, filters)
with db_api.context_manager.reader.using(context):
ports = (
super(NsxPolicyPlugin, self).get_ports(
context, filters, fields, sorts,
limit, marker, page_reverse))
# Add port extensions
for port in ports[:]:
if 'id' in port:
try:
port_model = self._get_port(context, port['id'])
resource_extend.apply_funcs('ports', port, port_model)
except n_exc.PortNotFound:
# Port might have been deleted by now
LOG.debug("Port %s was deleted during the get_ports "
"process, and is being skipped", port['id'])
ports.remove(port)
continue
return (ports if not fields else
[db_utils.resource_fields(port, fields) for port in ports])
def _update_router_gw_info(self, context, router_id, info):
router = self._get_router(context, router_id)
super(NsxPolicyPlugin, self)._update_router_gw_info(
context, router_id, info, router=router)
#TODO(asarfaty): Update the NSX
def create_router(self, context, router):
r = router['router']
gw_info = self._extract_external_gw(context, router, is_extract=True)
with db_api.context_manager.writer.using(context):
router = super(NsxPolicyPlugin, self).create_router(
context, router)
router_db = self._get_router(context, router['id'])
self._process_extra_attr_router_create(context, router_db, r)
#TODO(asarfaty): Create the NSX logical router and add DB mapping
LOG.debug("Created router %s: %s. GW info %s",
router['id'], r, gw_info)
return self.get_router(context, router['id'])
def delete_router(self, context, router_id):
router = self.get_router(context, router_id)
if router.get(l3_apidef.EXTERNAL_GW_INFO):
self._update_router_gw_info(context, router_id, {})
nsx_router_id = nsx_db.get_nsx_router_id(
context.session, router_id)
ret_val = super(NsxPolicyPlugin, self).delete_router(
context, router_id)
if nsx_router_id:
#TODO(asarfaty): delete the NSX logical router
pass
return ret_val
def update_router(self, context, router_id, router):
gw_info = self._extract_external_gw(context, router, is_extract=False)
router_data = router['router']
LOG.debug("Updating router %s: %s. GW info %s",
router_id, router_data, gw_info)
#TODO(asarfaty) update the NSX logical router & interfaces
return super(NsxPolicyPlugin, self).update_router(
context, router_id, router)
def add_router_interface(self, context, router_id, interface_info):
network_id = self._get_interface_network(context, interface_info)
extern_net = self._network_is_external(context, network_id)
router_db = self._get_router(context, router_id)
gw_network_id = (router_db.gw_port.network_id if router_db.gw_port
else None)
LOG.debug("Adding router %s interface %s with GW %s",
router_id, network_id, gw_network_id)
# A router interface cannot be an external network
if extern_net:
msg = _("An external network cannot be attached as "
"an interface to a router")
raise n_exc.InvalidInput(error_message=msg)
# Update the interface of the neutron router
info = super(NsxPolicyPlugin, self).add_router_interface(
context, router_id, interface_info)
#TODO(asarfaty) Update the NSX logical router ports
return info
def remove_router_interface(self, context, router_id, interface_info):
#TODO(asarfaty) Update the NSX logical router ports
info = super(NsxPolicyPlugin, self).remove_router_interface(
context, router_id, interface_info)
return info
def create_floatingip(self, context, floatingip):
new_fip = super(NsxPolicyPlugin, self).create_floatingip(
context, floatingip, initial_status=(
const.FLOATINGIP_STATUS_ACTIVE
if floatingip['floatingip']['port_id']
else const.FLOATINGIP_STATUS_DOWN))
router_id = new_fip['router_id']
if not router_id:
return new_fip
#TODO(asarfaty): Update the NSX router
return new_fip
def delete_floatingip(self, context, fip_id):
fip = self.get_floatingip(context, fip_id)
router_id = fip['router_id']
port_id = fip['port_id']
LOG.debug("Deleting floating IP %s. Router %s, Port %s",
fip_id, router_id, port_id)
if router_id:
nsx_router_id = nsx_db.get_nsx_router_id(context.session,
router_id)
if nsx_router_id:
#TODO(asarfaty): Update the NSX router
pass
super(NsxPolicyPlugin, self).delete_floatingip(context, fip_id)
def update_floatingip(self, context, fip_id, floatingip):
old_fip = self.get_floatingip(context, fip_id)
old_port_id = old_fip['port_id']
new_status = (const.FLOATINGIP_STATUS_ACTIVE
if floatingip['floatingip'].get('port_id')
else const.FLOATINGIP_STATUS_DOWN)
new_fip = super(NsxPolicyPlugin, self).update_floatingip(
context, fip_id, floatingip)
router_id = new_fip['router_id']
new_port_id = new_fip['port_id']
nsx_router_id = nsx_db.get_nsx_router_id(context.session,
router_id)
if nsx_router_id:
#TODO(asarfaty): Update the NSX router
LOG.debug("Updating floating IP %s. Router %s, Port %s "
"(old port %s)",
fip_id, router_id, new_port_id, old_port_id)
if new_fip['status'] != new_status:
new_fip['status'] = new_status
self.update_floatingip_status(context, fip_id, new_status)
return new_fip
def disassociate_floatingips(self, context, port_id):
fip_qry = context.session.query(l3_db_models.FloatingIP)
fip_dbs = fip_qry.filter_by(fixed_port_id=port_id)
for fip_db in fip_dbs:
if not fip_db.router_id:
continue
nsx_router_id = nsx_db.get_nsx_router_id(context.session,
fip_db.router_id)
if nsx_router_id:
# TODO(asarfaty): Update the NSX logical router
pass
self.update_floatingip_status(context, fip_db.id,
const.FLOATINGIP_STATUS_DOWN)
super(NsxPolicyPlugin, self).disassociate_floatingips(
context, port_id, do_notify=False)
def _create_security_group_backend_resources(self, secgroup):
# TODO(asarfaty): implement
pass
def create_security_group(self, context, security_group, default_sg=False):
secgroup = security_group['security_group']
if not default_sg:
tenant_id = secgroup['tenant_id']
self._ensure_default_security_group(context, tenant_id)
self._create_security_group_backend_resources(secgroup)
with db_api.context_manager.writer.using(context):
secgroup_db = (
super(NsxPolicyPlugin, self).create_security_group(
context, security_group, default_sg))
# TODO(asarfaty) save NSX->Neutron mappings
self._process_security_group_properties_create(context,
secgroup_db,
secgroup,
default_sg)
return secgroup_db
def update_security_group(self, context, id, security_group):
orig_secgroup = self.get_security_group(
context, id, fields=['id', 'name', 'description'])
LOG.debug("Updating SG %s -> %s", orig_secgroup,
security_group['security_group'])
with db_api.context_manager.writer.using(context):
secgroup_res = super(NsxPolicyPlugin, self).update_security_group(
context, id, security_group)
self._process_security_group_properties_update(
context, secgroup_res, security_group['security_group'])
#TODO(asarfaty): Update the NSX backend
return secgroup_res
def delete_security_group(self, context, id):
super(NsxPolicyPlugin, self).delete_security_group(context, id)
#TODO(asarfaty): Update the nSX backend
def create_security_group_rule(self, context, security_group_rule):
bulk_rule = {'security_group_rules': [security_group_rule]}
return self.create_security_group_rule_bulk(context, bulk_rule)[0]
def create_security_group_rule_bulk(self, context, security_group_rules):
sg_rules = security_group_rules['security_group_rules']
for r in sg_rules:
# TODO(asarfaty): create rules at the NSX
pass
with db_api.context_manager.writer.using(context):
rules_db = (super(NsxPolicyPlugin,
self).create_security_group_rule_bulk_native(
context, security_group_rules))
for i, r in enumerate(sg_rules):
self._process_security_group_rule_properties(
context, rules_db[i], r['security_group_rule'])
return rules_db
def delete_security_group_rule(self, context, id):
#TODO(asarfaty): Update the nSX backend
super(NsxPolicyPlugin, self).delete_security_group_rule(context, id)

View File

@ -74,7 +74,6 @@ from neutron.db import dns_db
from neutron.db import external_net_db
from neutron.db import extradhcpopt_db
from neutron.db import extraroute_db
from neutron.db import l3_attrs_db
from neutron.db import l3_db
from neutron.db import l3_gwmode_db
from neutron.db.models import l3 as l3_db_models
@ -3170,13 +3169,6 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
":unsupported field",
{'k': k, 'v': v})
def _process_extra_attr_router_create(self, context, router_db, r):
for extra_attr in l3_attrs_db.get_attr_info().keys():
if (extra_attr in r and
validators.is_attr_set(r.get(extra_attr))):
self.set_extra_attr_value(context, router_db,
extra_attr, r[extra_attr])
def create_router(self, context, router, allow_metadata=True):
r = router['router']
self._get_router_config_from_flavor(context, r)

View File

@ -77,7 +77,6 @@ from neutron_lib import exceptions as n_exc
from neutron_lib.plugins import utils as plugin_utils
from neutron_lib.utils import helpers
from oslo_config import cfg
from oslo_context import context as context_utils
from oslo_db import exception as db_exc
from oslo_log import log
from oslo_utils import excutils
@ -143,22 +142,6 @@ NSX_V3_CLIENT_SSL_PROFILE = 'nsx-default-client-ssl-profile'
NSX_V3_OS_DFW_UUID = '00000000-def0-0000-0fed-000000000000'
def inject_headers():
ctx = context_utils.get_current()
if ctx:
ctx_dict = ctx.to_dict()
return {'X-NSX-EUSER': ctx_dict.get('user_identity'),
'X-NSX-EREQID': ctx_dict.get('request_id')}
return {}
def inject_requestid_header():
ctx = context_utils.get_current()
if ctx:
return {'X-NSX-EREQID': ctx.__dict__.get('request_id')}
return {}
# NOTE(asarfaty): the order of inheritance here is important. in order for the
# QoS notification to work, the AgentScheduler init must be called first
# NOTE(arosen): same is true with the ExtendedSecurityGroupPropertiesMixin
@ -247,9 +230,11 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
self.nsxlib = v3_utils.get_nsxlib_wrapper()
if self.nsxlib.feature_supported(nsxlib_consts.FEATURE_ON_BEHALF_OF):
nsxlib_utils.set_inject_headers_callback(inject_headers)
nsxlib_utils.set_inject_headers_callback(
v3_utils.inject_headers)
else:
nsxlib_utils.set_inject_headers_callback(inject_requestid_header)
nsxlib_utils.set_inject_headers_callback(
v3_utils.inject_requestid_header)
self.lbv2_driver = self._init_lbv2_driver()
registry.subscribe(
@ -3770,13 +3755,6 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
action="NO_DNAT",
match_destination_network=subnet['cidr'])
def _process_extra_attr_router_create(self, context, router_db, r):
for extra_attr in l3_attrs_db.get_attr_info().keys():
if (extra_attr in r and
validators.is_attr_set(r.get(extra_attr))):
self.set_extra_attr_value(context, router_db,
extra_attr, r[extra_attr])
def _assert_on_router_admin_state(self, router_data):
if router_data.get("admin_state_up") is False:
err_msg = _("admin_state_up=False routers are not supported")
@ -4206,16 +4184,6 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
address_groups.append(address_group)
return (ports, address_groups)
def _get_interface_network(self, context, interface_info):
is_port, is_sub = self._validate_interface_info(interface_info)
if is_port:
net_id = self.get_port(context,
interface_info['port_id'])['network_id']
elif is_sub:
net_id = self.get_subnet(context,
interface_info['subnet_id'])['network_id']
return net_id
def _validate_multiple_subnets_routers(self, context, router_id, net_id):
network = self.get_network(context, net_id)
net_type = network.get(pnet.NETWORK_TYPE)

View File

@ -16,6 +16,7 @@ import os
import random
from oslo_config import cfg
from oslo_context import context as context_utils
from oslo_log import log as logging
from oslo_utils import fileutils
from sqlalchemy.orm import exc
@ -164,6 +165,34 @@ def get_nsxlib_wrapper(nsx_username=None, nsx_password=None, basic_auth=False):
return v3.NsxLib(nsxlib_config)
def get_nsxpolicy_wrapper(nsx_username=None, nsx_password=None,
basic_auth=False):
#TODO(asarfaty) move to a different file?
client_cert_provider = None
if not basic_auth:
# if basic auth requested, dont use cert file even if provided
client_cert_provider = get_client_cert_provider()
nsxlib_config = config.NsxLibConfig(
username=nsx_username or cfg.CONF.nsx_p.nsx_api_user,
password=nsx_password or cfg.CONF.nsx_p.nsx_api_password,
client_cert_provider=client_cert_provider,
retries=cfg.CONF.nsx_p.http_retries,
insecure=cfg.CONF.nsx_p.insecure,
ca_file=cfg.CONF.nsx_p.ca_file,
concurrent_connections=cfg.CONF.nsx_p.concurrent_connections,
http_timeout=cfg.CONF.nsx_p.http_timeout,
http_read_timeout=cfg.CONF.nsx_p.http_read_timeout,
conn_idle_timeout=cfg.CONF.nsx_p.conn_idle_timeout,
http_provider=None,
max_attempts=cfg.CONF.nsx_p.retries,
nsx_api_managers=cfg.CONF.nsx_p.nsx_api_managers,
plugin_scope=OS_NEUTRON_ID_SCOPE,
plugin_tag=NSX_NEUTRON_PLUGIN,
plugin_ver=n_version.version_info.release_string())
return v3.NsxPolicyLib(nsxlib_config)
def get_orphaned_dhcp_servers(context, plugin, nsxlib, dhcp_profile_uuid=None):
# An orphaned DHCP server means the associated neutron network
# does not exist or has no DHCP-enabled subnet.
@ -453,3 +482,19 @@ def get_mismatch_logical_ports(context, nsxlib, plugin, get_filters=None):
'error': 'Different MAC address bindings',
'error_type': PORT_ERROR_TYPE_BINDINGS})
return problems
def inject_headers():
ctx = context_utils.get_current()
if ctx:
ctx_dict = ctx.to_dict()
return {'X-NSX-EUSER': ctx_dict.get('user_identity'),
'X-NSX-EREQID': ctx_dict.get('request_id')}
return {}
def inject_requestid_header():
ctx = context_utils.get_current()
if ctx:
return {'X-NSX-EREQID': ctx.__dict__.get('request_id')}
return {}