vmware-nsx/vmware_nsx/plugins/nsx/plugin.py

788 lines
35 KiB
Python

# Copyright 2014 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 neutron_lib.api.definitions import network as net_def
from neutron_lib.api.definitions import port as port_def
from neutron_lib.api.definitions import subnet as subnet_def
from neutron_lib.callbacks import events
from neutron_lib.callbacks import registry
from neutron_lib.callbacks import resources
from neutron_lib import context as n_context
from neutron_lib.plugins import constants as plugin_constants
from neutron_lib.plugins import directory
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import excutils
from neutron.db import _resource_extend as resource_extend
from neutron.db import _utils as db_utils
from neutron.db import agents_db
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.availability_zone import router as router_az_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_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 portsecurity_db
from neutron.db import quota_db # noqa
from neutron.db import securitygroups_db
from neutron.quota import resource_registry
from neutron_lib.api import validators
from neutron_lib import exceptions as n_exc
from vmware_nsx.common import availability_zones as nsx_com_az
from vmware_nsx.common import config
from vmware_nsx.common import exceptions as nsx_exc
from vmware_nsx.common import managers as nsx_managers
from vmware_nsx.db import (
routertype as rt_rtr)
from vmware_nsx.db import db as nsx_db
from vmware_nsx.db import nsx_portbindings_db as pbin_db
from vmware_nsx.extensions import projectpluginmap
from vmware_nsx.plugins.common import plugin as nsx_plugin_common
from vmware_nsx.plugins.dvs import plugin as dvs
from vmware_nsx.plugins.nsx_v import plugin as v
from vmware_nsx.plugins.nsx_v3 import plugin as t
from vmware_nsx.services.lbaas.nsx import lb_driver_v2
LOG = logging.getLogger(__name__)
TVD_PLUGIN_TYPE = "Nsx-TVD"
@resource_extend.has_resource_extenders
class NsxTVDPlugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
addr_pair_db.AllowedAddressPairsMixin,
agents_db.AgentDbMixin,
nsx_plugin_common.NsxPluginBase,
rt_rtr.RouterType_mixin,
external_net_db.External_net_db_mixin,
extraroute_db.ExtraRoute_db_mixin,
extradhcpopt_db.ExtraDhcpOptMixin,
router_az_db.RouterAvailabilityZoneMixin,
l3_gwmode_db.L3_NAT_db_mixin,
pbin_db.NsxPortBindingMixin,
portsecurity_db.PortSecurityDbMixin,
securitygroups_db.SecurityGroupDbMixin,
nsx_com_az.NSXAvailabilityZonesPluginCommon,
projectpluginmap.ProjectPluginMapPluginBase):
supported_extension_aliases = ['project-plugin-map']
__native_bulk_support = True
__native_pagination_support = True
__native_sorting_support = True
@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._extension_manager = nsx_managers.ExtensionManager()
LOG.info("Start NSX TVD Plugin")
LOG.info("This plugin is experimental!")
# Validate configuration
config.validate_nsx_config_options()
super(NsxTVDPlugin, self).__init__()
# init the different supported plugins
self.init_plugins()
# init the extensions supported by any of the plugins
self.init_extensions()
self.lbv2_driver = lb_driver_v2.EdgeLoadbalancerDriverV2()
self._unsubscribe_callback_events()
@staticmethod
def plugin_type():
return TVD_PLUGIN_TYPE
@staticmethod
def is_tvd_plugin():
return True
def init_plugins(self):
# initialize all supported plugins
self.plugins = {}
try:
self.plugins[projectpluginmap.NsxPlugins.NSX_T] = t.NsxV3Plugin()
except Exception as e:
LOG.info("NSX-T plugin will not be supported: %s", e)
else:
LOG.info("NSX-T plugin will be supported")
try:
self.plugins[projectpluginmap.NsxPlugins.NSX_V] = v.NsxVPluginV2()
except Exception as e:
LOG.info("NSX-V plugin will not be supported: %s", e)
else:
LOG.info("NSX-V plugin will be supported")
try:
self.plugins[projectpluginmap.NsxPlugins.DVS] = dvs.NsxDvsV2()
except Exception as e:
LOG.info("DVS plugin will not be supported: %s", e)
else:
LOG.info("DVS plugin will be supported")
if not len(self.plugins):
msg = _("No active plugins were found")
raise nsx_exc.NsxPluginException(err_msg=msg)
# update the default plugin for new projects
self.default_plugin = cfg.CONF.nsx_tvd.default_plugin
if self.default_plugin not in self.plugins:
msg = (_("The default plugin %s failed to start") %
self.default_plugin)
raise nsx_exc.NsxPluginException(err_msg=msg)
LOG.info("NSX-TVD plugin will use %s as the default plugin",
self.default_plugin)
def get_plugin_by_type(self, plugin_type):
return self.plugins.get(plugin_type)
def init_extensions(self):
# Support all the extensions supported by any of the plugins
extensions = []
for plugin in self.plugins:
extensions.extend(self.plugins[plugin].supported_extension_aliases)
self.supported_extension_aliases.extend(list(set(extensions)))
# mark extensions which are supported by only one of the plugins
self._unsupported_fields = {}
for plugin in self.plugins:
# TODO(asarfaty): add other resources here
plugin_type = self.plugins[plugin].plugin_type()
self._unsupported_fields[plugin_type] = {'router': [],
'port': []}
# router size and type are supported only by the V plugin
if plugin_type in [t.NsxV3Plugin.plugin_type(),
dvs.NsxDvsV2.plugin_type()]:
self._unsupported_fields[plugin_type]['router'] = [
'router_size', 'router_type']
# port mac learning, and provider sg are not supported by
# the dvs plugin
if plugin_type in [dvs.NsxDvsV2.plugin_type()]:
self._unsupported_fields[plugin_type]['port'] = [
'mac_learning_enabled', 'provider_security_groups']
def _unsubscribe_callback_events(self):
# unsubscribe the callback that should be called on all plugins
# other that NSX-T.
registry.unsubscribe_all(
l3_db.L3_NAT_dbonly_mixin._prevent_l3_port_delete_callback)
# Instead we will subscribe our internal callback.
registry.subscribe(self._prevent_l3_port_delete_callback,
resources.PORT, events.BEFORE_DELETE)
@staticmethod
def _prevent_l3_port_delete_callback(resource, event, trigger, **kwargs):
"""Register a callback to replace the default one
This callback will prevent port deleting only if the port plugin
is not NSX-T (in NSX-T plugin it was already handled)
"""
context = kwargs['context']
port_id = kwargs['port_id']
port_check = kwargs['port_check']
l3plugin = directory.get_plugin(plugin_constants.L3)
if l3plugin and port_check:
# if not nsx-t - call super code
core_plugin = directory.get_plugin()
db_port = core_plugin._get_port(context, port_id)
p = core_plugin._get_plugin_from_net_id(
context, db_port['network_id'])
if p.plugin_type() != projectpluginmap.NsxPlugins.NSX_T:
l3plugin.prevent_l3_port_deletion(context, port_id)
def _validate_obj_extensions(self, data, plugin_type, obj_type):
"""prevent configuration of unsupported extensions"""
for field in self._unsupported_fields[plugin_type][obj_type]:
if validators.is_attr_set(data.get(field)):
err_msg = (_('Can not support %(field)s extension for '
'%(obj_type)s %(p)s plugin') % {
'field': field,
'obj_type': obj_type,
'p': plugin_type})
raise n_exc.InvalidInput(error_message=err_msg)
def _cleanup_obj_fields(self, data, plugin_type, obj_type):
"""Remove data of unsupported extensions"""
for field in self._unsupported_fields[plugin_type][obj_type]:
if field in data:
del data[field]
def _list_availability_zones(self, context, filters=None):
p = self._get_plugin_from_project(context, context.project_id)
return p._list_availability_zones(context, filters=filters)
def validate_availability_zones(self, context, resource_type,
availability_zones):
p = self._get_plugin_from_project(context, context.project_id)
return p.validate_availability_zones(context, resource_type,
availability_zones)
def _get_plugin_from_net_id(self, context, net_id):
# get the network using the super plugin - here we use the
# _get_network (so as not to call the make dict method)
network = self._get_network(context, net_id)
return self._get_plugin_from_project(context, network['tenant_id'])
def get_network_availability_zones(self, net_db):
ctx = n_context.get_admin_context()
p = self._get_plugin_from_project(ctx, net_db['tenant_id'])
return p.get_network_availability_zones(net_db)
def create_network(self, context, network):
net_data = network['network']
tenant_id = net_data['tenant_id']
self._ensure_default_security_group(context, tenant_id)
p = self._get_plugin_from_project(context, tenant_id)
return p.create_network(context, network)
@db_api.retry_if_session_inactive()
def create_network_bulk(self, context, networks):
#Implement create bulk so that the plugin calculation will be done once
objects = []
items = networks['networks']
# look at the first network to find out the project & plugin
net_data = items[0]['network']
tenant_id = net_data['tenant_id']
self._ensure_default_security_group(context, tenant_id)
p = self._get_plugin_from_project(context, tenant_id)
# create all networks one by one
try:
with db_api.context_manager.writer.using(context):
for item in items:
objects.append(p.create_network(context, item))
except Exception:
with excutils.save_and_reraise_exception():
LOG.error("An exception occurred while creating "
"the networks:%(item)s",
{'item': item})
return objects
def delete_network(self, context, id):
p = self._get_plugin_from_net_id(context, id)
p.delete_network(context, id)
def get_network(self, context, id, fields=None):
p = self._get_plugin_from_net_id(context, id)
return p.get_network(context, id, fields=fields)
def get_networks(self, context, filters=None, fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
# Read project plugin to filter relevant projects according to
# plugin
req_p = self._get_plugin_from_project(context, context.project_id)
filters = filters or {}
with db_api.context_manager.reader.using(context):
networks = (
super(NsxTVDPlugin, self).get_networks(
context, filters, fields, sorts,
limit, marker, page_reverse))
for net in networks[:]:
p = self._get_plugin_from_project(context, net['tenant_id'])
if p == req_p:
p._extend_get_network_dict_provider(context, net)
else:
networks.remove(net)
return (networks if not fields else
[db_utils.resource_fields(network,
fields) for network in networks])
def update_network(self, context, id, network):
p = self._get_plugin_from_net_id(context, id)
return p.update_network(context, id, network)
def create_port(self, context, port):
net_id = port['port']['network_id']
p = self._get_plugin_from_net_id(context, net_id)
self._validate_obj_extensions(
port['port'], p.plugin_type(), 'port')
new_port = p.create_port(context, port)
self._cleanup_obj_fields(
new_port, p.plugin_type(), 'port')
return new_port
def update_port(self, context, id, port):
db_port = self._get_port(context, id)
p = self._get_plugin_from_net_id(context, db_port['network_id'])
self._validate_obj_extensions(
port['port'], p.plugin_type(), 'port')
return p.update_port(context, id, port)
def delete_port(self, context, id, **kwargs):
db_port = self._get_port(context, id)
p = self._get_plugin_from_net_id(context, db_port['network_id'])
p.delete_port(context, id, **kwargs)
def get_port(self, context, id, fields=None):
db_port = self._get_port(context, id)
p = self._get_plugin_from_net_id(context, db_port['network_id'])
port = p.get_port(context, id, fields=fields)
self._cleanup_obj_fields(
port, p.plugin_type(), 'port')
return port
def get_ports(self, context, filters=None, fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
# Read project plugin to filter relevant projects according to
# plugin
req_p = self._get_plugin_from_project(context, context.project_id)
filters = filters or {}
with db_api.context_manager.reader.using(context):
ports = (
super(NsxTVDPlugin, self).get_ports(
context, filters, fields, sorts,
limit, marker, page_reverse))
# Add port extensions
for port in ports[:]:
if 'id' in port:
port_model = self._get_port(context, port['id'])
resource_extend.apply_funcs('ports', port, port_model)
p = self._get_plugin_from_net_id(context, port['network_id'])
if p == req_p:
if hasattr(p, '_extend_get_port_dict_qos_and_binding'):
p._extend_get_port_dict_qos_and_binding(context, port)
if hasattr(p,
'_remove_provider_security_groups_from_list'):
p._remove_provider_security_groups_from_list(port)
self._cleanup_obj_fields(
port, p.plugin_type(), 'port')
else:
ports.remove(port)
return (ports if not fields else
[db_utils.resource_fields(port, fields) for port in ports])
def get_subnet(self, context, id, fields=None):
db_subnet = self._get_subnet(context, id)
p = self._get_plugin_from_net_id(context, db_subnet['network_id'])
return p.get_subnet(context, id, fields=fields)
def get_subnets(self, context, filters=None, fields=None, sorts=None,
limit=None, marker=None, page_reverse=False):
# The subnets is tricky as the metadata requests make use of the
# get subnet. So there are two use cases here:
# 1. that the metadata request returns a value
# 2. that this is a general subnet query.
# If none found then we return default plugin subnets
default_plugin_subnets = []
for plugin in self.plugins.values():
subnets = plugin.get_subnets(context, filters=filters,
fields=fields, sorts=sorts,
limit=limit, marker=marker,
page_reverse=page_reverse)
if subnets:
return subnets
if self.plugins[self.default_plugin] == plugin:
default_plugin_subnets = subnets
return default_plugin_subnets
def delete_subnet(self, context, id):
db_subnet = self._get_subnet(context, id)
p = self._get_plugin_from_net_id(context, db_subnet['network_id'])
p.delete_subnet(context, id)
def create_subnet(self, context, subnet):
id = subnet['subnet']['network_id']
p = self._get_plugin_from_net_id(context, id)
return p.create_subnet(context, subnet)
def create_subnet_bulk(self, context, subnets):
# look at the first subnet to find out the project & plugin
items = subnets['subnets']
id = items[0]['subnet']['network_id']
p = self._get_plugin_from_net_id(context, id)
return p.create_subnet_bulk(context, subnets)
def update_subnet(self, context, id, subnet):
db_subnet = self._get_subnet(context, id)
p = self._get_plugin_from_net_id(context, db_subnet['network_id'])
return p.update_subnet(context, id, subnet)
def get_router_availability_zones(self, router):
ctx = n_context.get_admin_context()
p = self._get_plugin_from_project(ctx, router['tenant_id'])
return p.get_router_availability_zones(router)
def _validate_router_gw_plugin(self, context, router_plugin,
gw_info):
if gw_info and gw_info.get('network_id'):
net_plugin = self._get_plugin_from_net_id(
context, gw_info['network_id'])
if net_plugin.plugin_type() != router_plugin.plugin_type():
err_msg = (_('Router gateway should belong to the %s plugin '
'as the router') % router_plugin.plugin_type())
raise n_exc.InvalidInput(error_message=err_msg)
def _validate_router_interface_plugin(self, context, router_plugin,
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']
net_plugin = self._get_plugin_from_net_id(context, net_id)
if net_plugin.plugin_type() != router_plugin.plugin_type():
err_msg = (_('Router interface should belong to the %s plugin '
'as the router') % router_plugin.plugin_type())
raise n_exc.InvalidInput(error_message=err_msg)
def _get_plugin_from_router_id(self, context, router_id):
# get the router using the super plugin - here we use the
# _get_router (so as not to call the make dict method)
router = self._get_router(context, router_id)
return self._get_plugin_from_project(context, router['tenant_id'])
def create_router(self, context, router):
tenant_id = router['router']['tenant_id']
self._ensure_default_security_group(context, tenant_id)
p = self._get_plugin_from_project(context, tenant_id)
self._validate_router_gw_plugin(context, p, router['router'].get(
'external_gateway_info'))
self._validate_obj_extensions(
router['router'], p.plugin_type(), 'router')
new_router = p.create_router(context, router)
self._cleanup_obj_fields(
new_router, p.plugin_type(), 'router')
return new_router
def update_router(self, context, router_id, router):
p = self._get_plugin_from_router_id(context, router_id)
self._validate_router_gw_plugin(context, p, router['router'].get(
'external_gateway_info'))
self._validate_obj_extensions(
router['router'], p.plugin_type(), 'router')
return p.update_router(context, router_id, router)
def get_router(self, context, id, fields=None):
p = self._get_plugin_from_router_id(context, id)
router = p.get_router(context, id, fields=fields)
self._cleanup_obj_fields(router, p.plugin_type(), 'router')
return router
def delete_router(self, context, id):
p = self._get_plugin_from_router_id(context, id)
p.delete_router(context, id)
def add_router_interface(self, context, router_id, interface_info):
p = self._get_plugin_from_router_id(context, router_id)
self._validate_router_interface_plugin(context, p, interface_info)
return p.add_router_interface(context, router_id, interface_info)
def remove_router_interface(self, context, router_id, interface_info):
p = self._get_plugin_from_router_id(context, router_id)
return p.remove_router_interface(context, router_id, interface_info)
def _validate_fip_router_plugin(self, context, fip_plugin, fip_data):
if 'router_id' in fip_data:
router_plugin = self._get_plugin_from_router_id(
context, fip_data['router_id'])
if router_plugin.plugin_type() != fip_plugin.plugin_type():
err_msg = (_('Floatingip router should belong to the %s '
'plugin as the floatingip') %
fip_plugin.plugin_type())
raise n_exc.InvalidInput(error_message=err_msg)
def get_routers(self, context, filters=None, fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
# Read project plugin to filter relevant projects according to
# plugin
req_p = self._get_plugin_from_project(context, context.project_id)
routers = super(NsxTVDPlugin, self).get_routers(
context, filters=filters, fields=fields, sorts=sorts,
limit=limit, marker=marker, page_reverse=page_reverse)
for router in routers[:]:
p = self._get_plugin_from_project(context, router['tenant_id'])
if p != req_p:
routers.remove(router)
return routers
def create_floatingip(self, context, floatingip):
net_id = floatingip['floatingip']['floating_network_id']
p = self._get_plugin_from_net_id(context, net_id)
self._validate_fip_router_plugin(context, p, floatingip['floatingip'])
return p.create_floatingip(context, floatingip)
def update_floatingip(self, context, id, floatingip):
fip = self._get_floatingip(context, id)
net_id = fip['floating_network_id']
p = self._get_plugin_from_net_id(context, net_id)
self._validate_fip_router_plugin(context, p, floatingip['floatingip'])
return p.update_floatingip(context, id, floatingip)
def delete_floatingip(self, context, id):
fip = self._get_floatingip(context, id)
net_id = fip['floating_network_id']
p = self._get_plugin_from_net_id(context, net_id)
return p.delete_floatingip(context, id)
def get_floatingip(self, context, id, fields=None):
fip = self._get_floatingip(context, id)
net_id = fip['floating_network_id']
p = self._get_plugin_from_net_id(context, net_id)
return p.get_floatingip(context, id, fields=fields)
def get_floatingips(self, context, filters=None, fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
# Read project plugin to filter relevant projects according to
# plugin
req_p = self._get_plugin_from_project(context, context.project_id)
fips = super(NsxTVDPlugin, self).get_floatingips(
context, filters=filters, fields=fields, sorts=sorts,
limit=limit, marker=marker, page_reverse=page_reverse)
for fip in fips[:]:
p = self._get_plugin_from_project(context,
fip['tenant_id'])
if p != req_p:
fips.remove(fip)
return fips
def disassociate_floatingips(self, context, port_id):
db_port = self._get_port(context, port_id)
p = self._get_plugin_from_net_id(context, db_port['network_id'])
return p.disassociate_floatingips(context, port_id)
def _get_plugin_from_sg_id(self, context, sg_id):
sg = self._get_security_group(context, sg_id)
return self._get_plugin_from_project(context, sg['tenant_id'])
def create_security_group(self, context, security_group,
default_sg=False):
if not default_sg:
secgroup = security_group['security_group']
tenant_id = secgroup['tenant_id']
self._ensure_default_security_group(context, tenant_id)
p = self._get_plugin_from_project(context, context.project_id)
return p.create_security_group(context, security_group,
default_sg=default_sg)
def delete_security_group(self, context, id):
p = self._get_plugin_from_sg_id(context, id)
p.delete_security_group(context, id)
def update_security_group(self, context, id, security_group):
p = self._get_plugin_from_sg_id(context, id)
return p.update_security_group(context, id, security_group)
def get_security_group(self, context, id, fields=None):
p = self._get_plugin_from_sg_id(context, id)
return p.get_security_group(context, id, fields=fields)
def get_security_groups(self, context, filters=None, fields=None,
sorts=None, limit=None,
marker=None, page_reverse=False, default_sg=False):
# Read project plugin to filter relevant projects according to
# plugin
req_p = self._get_plugin_from_project(context, context.project_id)
sgs = super(NsxTVDPlugin, self).get_security_groups(
context, filters=filters, fields=fields, sorts=sorts,
limit=limit, marker=marker, page_reverse=page_reverse,
default_sg=default_sg)
for sg in sgs[:]:
p = self._get_plugin_from_project(context, sg['tenant_id'])
if p != req_p:
sgs.remove(sg)
return sgs
def create_security_group_rule_bulk(self, context, security_group_rules):
p = self._get_plugin_from_project(context, context.project_id)
return p.create_security_group_rule_bulk(context,
security_group_rules)
def create_security_group_rule(self, context, security_group_rule):
p = self._get_plugin_from_project(context, context.project_id)
return p.create_security_group_rule(context, security_group_rule)
def delete_security_group_rule(self, context, id):
rule_db = self._get_security_group_rule(context, id)
sg_id = rule_db['security_group_id']
p = self._get_plugin_from_sg_id(context, sg_id)
p.delete_security_group_rule(context, id)
def get_security_group_rules(self, context, filters=None, fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
# Read project plugin to filter relevant projects according to
# plugin
req_p = self._get_plugin_from_project(context, context.project_id)
rules = super(NsxTVDPlugin, self).get_security_group_rules(
context, filters=filters, fields=fields, sorts=sorts,
limit=limit, marker=marker, page_reverse=page_reverse)
for rule in rules[:]:
p = self._get_plugin_from_project(context, rule['tenant_id'])
if p != req_p:
rules.remove(rule)
return rules
@staticmethod
@resource_extend.extends([net_def.COLLECTION_NAME])
def _ext_extend_network_dict(result, netdb):
ctx = n_context.get_admin_context()
# get the core plugin as this is a static method with no 'self'
plugin = directory.get_plugin()
p = plugin._get_plugin_from_project(ctx, netdb['tenant_id'])
with db_api.context_manager.writer.using(ctx):
p._extension_manager.extend_network_dict(
ctx.session, netdb, result)
@staticmethod
@resource_extend.extends([port_def.COLLECTION_NAME])
def _ext_extend_port_dict(result, portdb):
ctx = n_context.get_admin_context()
# get the core plugin as this is a static method with no 'self'
plugin = directory.get_plugin()
p = plugin._get_plugin_from_project(ctx, portdb['tenant_id'])
with db_api.context_manager.writer.using(ctx):
p._extension_manager.extend_port_dict(
ctx.session, portdb, result)
@staticmethod
@resource_extend.extends([subnet_def.COLLECTION_NAME])
def _ext_extend_subnet_dict(result, subnetdb):
ctx = n_context.get_admin_context()
# get the core plugin as this is a static method with no 'self'
plugin = directory.get_plugin()
p = plugin._get_plugin_from_project(ctx, subnetdb['tenant_id'])
with db_api.context_manager.writer.using(ctx):
p._extension_manager.extend_subnet_dict(
ctx.session, subnetdb, result)
def _get_project_plugin_dict(self, data):
return {'id': data['project'],
'project': data['project'],
'plugin': data['plugin'],
'tenant_id': data['project']}
def create_project_plugin_map(self, context, project_plugin_map):
# TODO(asarfaty): Validate project id exists
data = project_plugin_map['project_plugin_map']
if nsx_db.get_project_plugin_mapping(
context.session, data['project']):
raise projectpluginmap.ProjectPluginAlreadyExists(
project_id=data['project'])
LOG.info("Adding mapping between project %(project)s and plugin "
"%(plugin)s", {'project': data['project'],
'plugin': data['plugin']})
nsx_db.add_project_plugin_mapping(context.session,
data['project'],
data['plugin'])
return self._get_project_plugin_dict(data)
def get_project_plugin_map(self, context, id, fields=None):
data = nsx_db.get_project_plugin_mapping(context.session, id)
if data:
return self._get_project_plugin_dict(data)
else:
raise n_exc.ObjectNotFound(id=id)
def get_project_plugin_maps(self, context, filters=None, fields=None,
sorts=None, limit=None, marker=None,
page_reverse=False):
# TODO(asarfaty) filter the results
mappings = nsx_db.get_project_plugin_mappings(context.session)
return [self._get_project_plugin_dict(data) for data in mappings]
def get_plugin_type_from_project(self, context, project_id):
"""Get the correct plugin type for this project.
Look for the project in the DB.
If not there - add an entry with the default plugin
"""
plugin_type = self.default_plugin
if not project_id:
# if the project_id is empty - return the default one and do not
# add to db (used by admin context to get actions)
return plugin_type
mapping = nsx_db.get_project_plugin_mapping(
context.session, project_id)
if mapping:
plugin_type = mapping['plugin']
else:
# add a new entry with the default plugin
try:
# TODO(asarfaty) we get timeout here when called under
# _ext_extend_network_dict of the first create_network
self.create_project_plugin_map(context,
{'project_plugin_map': {'plugin': plugin_type,
'project': project_id}})
except projectpluginmap.ProjectPluginAlreadyExists:
# Maybe added by another thread
pass
if not self.plugins.get(plugin_type):
msg = (_("Cannot use unsupported plugin %(plugin)s for project "
"%(project)s") % {'plugin': plugin_type,
'project': project_id})
raise nsx_exc.NsxPluginException(err_msg=msg)
LOG.debug("Using %s plugin for project %s", plugin_type, project_id)
return plugin_type
def _get_plugin_from_project(self, context, project_id):
"""Get the correct plugin for this project.
Look for the project in the DB.
If not there - add an entry with the default plugin
"""
plugin_type = self.get_plugin_type_from_project(context, project_id)
return self.plugins[plugin_type]
def get_housekeeper(self, context, name, fields=None):
p = self._get_plugin_from_project(context, context.project_id)
if hasattr(p, 'housekeeper'):
return p.housekeeper.get(name)
msg = _("Housekeeper %s not found") % name
raise nsx_exc.NsxPluginException(err_msg=msg)
def get_housekeepers(self, context, filters=None, fields=None, sorts=None,
limit=None, marker=None, page_reverse=False):
p = self._get_plugin_from_project(context, context.project_id)
if hasattr(p, 'housekeeper'):
return p.housekeeper.list()
return []
def update_housekeeper(self, context, name, housekeeper):
p = self._get_plugin_from_project(context, context.project_id)
if hasattr(p, 'housekeeper'):
p.housekeeper.run(context, name)
return p.housekeeper.get(name)