neutron-lbaas/neutron/plugins/oneconvergence/plugin.py

446 lines
17 KiB
Python

# Copyright 2014 OneConvergence, 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.
#
# @author: Kedar Kulkarni, One Convergence, Inc.
"""Implementation of OneConvergence Neutron Plugin."""
from oslo.config import cfg
from neutron.agent import securitygroups_rpc as sg_rpc
from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api
from neutron.common import constants as q_const
from neutron.common import exceptions as nexception
from neutron.common import rpc as q_rpc
from neutron.common import topics
from neutron.db import agents_db
from neutron.db import agentschedulers_db
from neutron.db import db_base_plugin_v2
from neutron.db import dhcp_rpc_base
from neutron.db import external_net_db
from neutron.db import extraroute_db
from neutron.db import l3_agentschedulers_db
from neutron.db import l3_gwmode_db
from neutron.db import l3_rpc_base
from neutron.db import portbindings_base
from neutron.db import quota_db # noqa
from neutron.db import securitygroups_rpc_base as sg_db_rpc
from neutron.extensions import portbindings
from neutron.openstack.common import excutils
from neutron.openstack.common import importutils
from neutron.openstack.common import log as logging
from neutron.openstack.common import rpc
from neutron.plugins.common import constants as svc_constants
import neutron.plugins.oneconvergence.lib.config # noqa
import neutron.plugins.oneconvergence.lib.exception as nvsdexception
import neutron.plugins.oneconvergence.lib.nvsd_db as nvsd_db
from neutron.plugins.oneconvergence.lib import nvsdlib as nvsd_lib
LOG = logging.getLogger(__name__)
IPv6 = 6
class NVSDPluginRpcCallbacks(dhcp_rpc_base.DhcpRpcCallbackMixin,
l3_rpc_base.L3RpcCallbackMixin,
sg_db_rpc.SecurityGroupServerRpcCallbackMixin):
RPC_API_VERSION = '1.1'
def create_rpc_dispatcher(self):
"""Get the rpc dispatcher for this manager."""
return q_rpc.PluginRpcDispatcher([self,
agents_db.AgentExtRpcCallback()])
@staticmethod
def get_port_from_device(device):
port = nvsd_db.get_port_from_device(device)
if port:
port['device'] = device
return port
class NVSDPluginV2AgentNotifierApi(rpc.proxy.RpcProxy,
sg_rpc.SecurityGroupAgentRpcApiMixin):
BASE_RPC_API_VERSION = '1.0'
def __init__(self, topic):
super(NVSDPluginV2AgentNotifierApi, self).__init__(
topic=topic, default_version=self.BASE_RPC_API_VERSION)
self.topic_port_update = topics.get_topic_name(topic, topics.PORT,
topics.UPDATE)
def port_update(self, context, port):
self.fanout_cast(context,
self.make_msg('port_update',
port=port,
topic=self.topic_port_update))
class OneConvergencePluginV2(db_base_plugin_v2.NeutronDbPluginV2,
extraroute_db.ExtraRoute_db_mixin,
l3_agentschedulers_db.L3AgentSchedulerDbMixin,
agentschedulers_db.DhcpAgentSchedulerDbMixin,
external_net_db.External_net_db_mixin,
l3_gwmode_db.L3_NAT_db_mixin,
portbindings_base.PortBindingBaseMixin,
sg_db_rpc.SecurityGroupServerRpcMixin):
"""L2 Virtual Network Plugin.
OneConvergencePluginV2 is a Neutron plugin that provides L2 Virtual Network
functionality.
"""
__native_bulk_support = True
__native_pagination_support = True
__native_sorting_support = True
_supported_extension_aliases = ['agent',
'binding',
'dhcp_agent_scheduler',
'ext-gw-mode',
'external-net',
'extraroute',
'l3_agent_scheduler',
'quotas',
'router',
'security-group'
]
@property
def supported_extension_aliases(self):
if not hasattr(self, '_aliases'):
aliases = self._supported_extension_aliases[:]
sg_rpc.disable_security_group_extension_by_config(aliases)
self._aliases = aliases
return self._aliases
def __init__(self):
super(OneConvergencePluginV2, self).__init__()
self.oneconvergence_init()
self.base_binding_dict = {
portbindings.VIF_TYPE: portbindings.VIF_TYPE_OVS,
portbindings.VIF_DETAILS: {
portbindings.CAP_PORT_FILTER:
'security-group' in self.supported_extension_aliases}}
portbindings_base.register_port_dict_function()
self.setup_rpc()
self.network_scheduler = importutils.import_object(
cfg.CONF.network_scheduler_driver)
self.router_scheduler = importutils.import_object(
cfg.CONF.router_scheduler_driver)
def oneconvergence_init(self):
"""Initialize the connections and set the log levels for the plugin."""
self.nvsdlib = nvsd_lib.NVSDApi()
self.nvsdlib.set_connection()
def setup_rpc(self):
# RPC support
self.service_topics = {svc_constants.CORE: topics.PLUGIN,
svc_constants.L3_ROUTER_NAT: topics.L3PLUGIN}
self.conn = rpc.create_connection(new=True)
self.notifier = NVSDPluginV2AgentNotifierApi(topics.AGENT)
self.agent_notifiers[q_const.AGENT_TYPE_DHCP] = (
dhcp_rpc_agent_api.DhcpAgentNotifyAPI()
)
self.agent_notifiers[q_const.AGENT_TYPE_L3] = (
l3_rpc_agent_api.L3AgentNotify
)
self.callbacks = NVSDPluginRpcCallbacks()
self.dispatcher = self.callbacks.create_rpc_dispatcher()
for svc_topic in self.service_topics.values():
self.conn.create_consumer(svc_topic, self.dispatcher, fanout=False)
# Consume from all consumers in a thread
self.conn.consume_in_thread()
def create_network(self, context, network):
tenant_id = self._get_tenant_id_for_create(
context, network['network'])
self._ensure_default_security_group(context, tenant_id)
net = self.nvsdlib.create_network(network['network'])
network['network']['id'] = net['id']
with context.session.begin(subtransactions=True):
try:
neutron_net = super(OneConvergencePluginV2,
self).create_network(context, network)
#following call checks whether the network is external or not
#and if it is external then adds this network to
#externalnetworks table of neutron db
self._process_l3_create(context, neutron_net,
network['network'])
except nvsdexception.NVSDAPIException:
with excutils.save_and_reraise_exception():
self.nvsdlib.delete_network(net)
return neutron_net
def update_network(self, context, net_id, network):
with context.session.begin(subtransactions=True):
neutron_net = super(OneConvergencePluginV2,
self).update_network(context, net_id, network)
self.nvsdlib.update_network(neutron_net, network['network'])
# updates neutron database e.g. externalnetworks table.
self._process_l3_update(context, neutron_net, network['network'])
return neutron_net
def delete_network(self, context, net_id):
with context.session.begin(subtransactions=True):
network = self._get_network(context, net_id)
#get all the subnets under the network to delete them
subnets = self._get_subnets_by_network(context, net_id)
super(OneConvergencePluginV2, self).delete_network(context,
net_id)
self.nvsdlib.delete_network(network, subnets)
def create_subnet(self, context, subnet):
if subnet['subnet']['ip_version'] == IPv6:
raise nexception.InvalidInput(
error_message="NVSDPlugin doesn't support IPv6.")
neutron_subnet = super(OneConvergencePluginV2,
self).create_subnet(context, subnet)
try:
self.nvsdlib.create_subnet(neutron_subnet)
except nvsdexception.NVSDAPIException:
with excutils.save_and_reraise_exception():
#Log the message and delete the subnet from the neutron
super(OneConvergencePluginV2,
self).delete_subnet(context, neutron_subnet['id'])
LOG.error(_("Failed to create subnet, "
"deleting it from neutron"))
return neutron_subnet
def delete_subnet(self, context, subnet_id):
neutron_subnet = self._get_subnet(context, subnet_id)
with context.session.begin(subtransactions=True):
super(OneConvergencePluginV2, self).delete_subnet(context,
subnet_id)
self.nvsdlib.delete_subnet(neutron_subnet)
def update_subnet(self, context, subnet_id, subnet):
with context.session.begin(subtransactions=True):
neutron_subnet = super(OneConvergencePluginV2,
self).update_subnet(context, subnet_id,
subnet)
self.nvsdlib.update_subnet(neutron_subnet, subnet)
return neutron_subnet
def create_port(self, context, port):
self._ensure_default_security_group_on_port(context, port)
sgids = self._get_security_groups_on_port(context, port)
network = {}
network_id = port['port']['network_id']
with context.session.begin(subtransactions=True):
# Invoke the Neutron API for creating port
neutron_port = super(OneConvergencePluginV2,
self).create_port(context, port)
self._process_portbindings_create_and_update(context,
port['port'],
neutron_port)
self._process_port_create_security_group(context, neutron_port,
sgids)
if port['port']['device_owner'] in ('network:router_gateway',
'network:floatingip'):
# for l3 requests, tenant_id will be None/''
network = self._get_network(context, network_id)
tenant_id = network['tenant_id']
else:
tenant_id = port['port']['tenant_id']
port_id = neutron_port['id']
try:
self.nvsdlib.create_port(tenant_id, neutron_port)
except nvsdexception.NVSDAPIException:
with excutils.save_and_reraise_exception():
LOG.error(_("Deleting newly created "
"neutron port %s"), port_id)
super(OneConvergencePluginV2, self).delete_port(context,
port_id)
self.notify_security_groups_member_updated(context, neutron_port)
return neutron_port
def update_port(self, context, port_id, port):
with context.session.begin(subtransactions=True):
old_port = super(OneConvergencePluginV2, self).get_port(context,
port_id)
neutron_port = super(OneConvergencePluginV2,
self).update_port(context, port_id, port)
if neutron_port['tenant_id'] == '':
network = self._get_network(context,
neutron_port['network_id'])
tenant_id = network['tenant_id']
else:
tenant_id = neutron_port['tenant_id']
self.nvsdlib.update_port(tenant_id, neutron_port, port['port'])
self._process_portbindings_create_and_update(context,
port['port'],
neutron_port)
need_port_update_notify = self.update_security_group_on_port(
context, port_id, port, old_port, neutron_port)
if need_port_update_notify:
self.notifier.port_update(context, neutron_port)
return neutron_port
def delete_port(self, context, port_id, l3_port_check=True):
if l3_port_check:
self.prevent_l3_port_deletion(context, port_id)
with context.session.begin(subtransactions=True):
neutron_port = super(OneConvergencePluginV2,
self).get_port(context, port_id)
self._delete_port_security_group_bindings(context, port_id)
self.disassociate_floatingips(context, port_id)
super(OneConvergencePluginV2, self).delete_port(context, port_id)
network = self._get_network(context, neutron_port['network_id'])
neutron_port['tenant_id'] = network['tenant_id']
self.nvsdlib.delete_port(port_id, neutron_port)
self.notify_security_groups_member_updated(context, neutron_port)
def create_floatingip(self, context, floatingip):
neutron_floatingip = super(OneConvergencePluginV2,
self).create_floatingip(context,
floatingip)
try:
self.nvsdlib.create_floatingip(neutron_floatingip)
except nvsdexception.NVSDAPIException:
with excutils.save_and_reraise_exception():
LOG.error(_("Failed to create floatingip"))
super(OneConvergencePluginV2,
self).delete_floatingip(context,
neutron_floatingip['id'])
return neutron_floatingip
def update_floatingip(self, context, fip_id, floatingip):
with context.session.begin(subtransactions=True):
neutron_floatingip = super(OneConvergencePluginV2,
self).update_floatingip(context,
fip_id,
floatingip)
self.nvsdlib.update_floatingip(neutron_floatingip, floatingip)
return neutron_floatingip
def delete_floatingip(self, context, floating_ip_id):
with context.session.begin(subtransactions=True):
floating_ip = self._get_floatingip(context, floating_ip_id)
super(OneConvergencePluginV2,
self).delete_floatingip(context, floating_ip_id)
self.nvsdlib.delete_floatingip(floating_ip)
def create_router(self, context, router):
neutron_router = super(OneConvergencePluginV2,
self).create_router(context, router)
try:
self.nvsdlib.create_router(neutron_router)
except nvsdexception.NVSDAPIException:
with excutils.save_and_reraise_exception():
LOG.error(_("Failed to create router"))
super(OneConvergencePluginV2,
self).delete_router(context, neutron_router['id'])
return neutron_router
def update_router(self, context, router_id, router):
with context.session.begin(subtransactions=True):
neutron_router = super(OneConvergencePluginV2,
self).update_router(context, router_id,
router)
self.nvsdlib.update_router(neutron_router)
return neutron_router
def delete_router(self, context, router_id):
tenant_id = self._get_router(context, router_id)['tenant_id']
with context.session.begin(subtransactions=True):
super(OneConvergencePluginV2, self).delete_router(context,
router_id)
self.nvsdlib.delete_router(tenant_id, router_id)