e71a3bc751
Since [0] was merged PORT PRECOMMIT_DELETE event callback uses payload argument instead of kwargs. [0] https://review.opendev.org/c/openstack/neutron/+/800604 Change-Id: Ieeba5c996f06294df33581f08510bc8809ec5098
227 lines
8.7 KiB
Python
227 lines
8.7 KiB
Python
# Copyright (C) 2016 Midokura SARL.
|
|
# Copyright (C) 2015 Ericsson AB
|
|
# Copyright (c) 2015 Gigamon
|
|
#
|
|
# 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.db import servicetype_db as st_db
|
|
from neutron.services import provider_configuration as pconf
|
|
from neutron.services import service_base
|
|
from neutron_lib.callbacks import events
|
|
from neutron_lib.callbacks import registry
|
|
from neutron_lib.callbacks import resources
|
|
from neutron_lib import constants
|
|
from neutron_lib import exceptions as n_exc
|
|
|
|
from neutron_taas.common import constants as taas_consts
|
|
from neutron_taas.db import taas_db
|
|
from neutron_taas.extensions import taas as taas_ex
|
|
from neutron_taas.services.taas.service_drivers import (service_driver_context
|
|
as sd_context)
|
|
|
|
from oslo_log import log as logging
|
|
from oslo_utils import excutils
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
def add_provider_configuration(type_manager, service_type):
|
|
type_manager.add_provider_configuration(
|
|
service_type,
|
|
pconf.ProviderConfiguration('neutron_taas'))
|
|
|
|
|
|
@registry.has_registry_receivers
|
|
class TaasPlugin(taas_db.Taas_db_Mixin):
|
|
|
|
supported_extension_aliases = ["taas",
|
|
"taas-vlan-filter"]
|
|
path_prefix = "/taas"
|
|
|
|
def __init__(self):
|
|
|
|
LOG.debug("TAAS PLUGIN INITIALIZED")
|
|
self.service_type_manager = st_db.ServiceTypeManager.get_instance()
|
|
add_provider_configuration(self.service_type_manager,
|
|
taas_consts.TAAS)
|
|
self._load_drivers()
|
|
self.driver = self._get_driver_for_provider(self.default_provider)
|
|
|
|
return
|
|
|
|
def _load_drivers(self):
|
|
"""Loads plugin-drivers specified in configuration."""
|
|
self.drivers, self.default_provider = service_base.load_drivers(
|
|
taas_consts.TAAS, self)
|
|
|
|
def _get_driver_for_provider(self, provider):
|
|
if provider in self.drivers:
|
|
return self.drivers[provider]
|
|
raise n_exc.Invalid("Error retrieving driver for provider %s" %
|
|
provider)
|
|
|
|
def create_tap_service(self, context, tap_service):
|
|
LOG.debug("create_tap_service() called")
|
|
|
|
t_s = tap_service['tap_service']
|
|
tenant_id = t_s['tenant_id']
|
|
port_id = t_s['port_id']
|
|
|
|
# Get port details
|
|
port = self._get_port_details(context, port_id)
|
|
|
|
# Check if the port is owned by the tenant.
|
|
if port['tenant_id'] != tenant_id:
|
|
raise taas_ex.PortDoesNotBelongToTenant()
|
|
|
|
# Extract the host where the port is located
|
|
host = port['binding:host_id']
|
|
|
|
if host is not None:
|
|
LOG.debug("Host on which the port is created = %s" % host)
|
|
else:
|
|
LOG.debug("Host could not be found, Port Binding disbaled!")
|
|
|
|
# Create tap service in the db model
|
|
with context.session.begin(subtransactions=True):
|
|
ts = super(TaasPlugin, self).create_tap_service(context,
|
|
tap_service)
|
|
driver_context = sd_context.TapServiceContext(self, context, ts)
|
|
self.driver.create_tap_service_precommit(driver_context)
|
|
|
|
try:
|
|
self.driver.create_tap_service_postcommit(driver_context)
|
|
except Exception:
|
|
with excutils.save_and_reraise_exception():
|
|
LOG.error("Failed to create tap service on driver,"
|
|
"deleting tap_service %s", ts['id'])
|
|
super(TaasPlugin, self).delete_tap_service(context, ts['id'])
|
|
|
|
return ts
|
|
|
|
def delete_tap_service(self, context, id):
|
|
LOG.debug("delete_tap_service() called")
|
|
|
|
# Get all the tap Flows that are associated with the Tap service
|
|
# and delete them as well
|
|
t_f_collection = self.get_tap_flows(
|
|
context,
|
|
filters={'tap_service_id': [id]}, fields=['id'])
|
|
|
|
for t_f in t_f_collection:
|
|
self.delete_tap_flow(context, t_f['id'])
|
|
|
|
with context.session.begin(subtransactions=True):
|
|
ts = self.get_tap_service(context, id)
|
|
driver_context = sd_context.TapServiceContext(self, context, ts)
|
|
if ts['status'] == constants.ACTIVE:
|
|
ts['status'] = constants.PENDING_DELETE
|
|
super(TaasPlugin, self).update_tap_service(
|
|
context, id, {'tap_service': ts})
|
|
method = self.driver.delete_tap_service_precommit
|
|
else:
|
|
super(TaasPlugin, self).delete_tap_service(context, id)
|
|
method = self.driver.delete_tap_service_postcommit
|
|
|
|
try:
|
|
method(driver_context)
|
|
except Exception:
|
|
with excutils.save_and_reraise_exception():
|
|
LOG.error("Failed to delete tap service on driver. "
|
|
"tap_sevice: %s", id)
|
|
|
|
def create_tap_flow(self, context, tap_flow):
|
|
LOG.debug("create_tap_flow() called")
|
|
|
|
t_f = tap_flow['tap_flow']
|
|
tenant_id = t_f['tenant_id']
|
|
|
|
# Check if the tenant id of the source port is the same as the
|
|
# tenant_id of the tap service we are attaching it to.
|
|
|
|
ts = self.get_tap_service(context, t_f['tap_service_id'])
|
|
ts_tenant_id = ts['tenant_id']
|
|
|
|
if tenant_id != ts_tenant_id:
|
|
raise taas_ex.TapServiceNotBelongToTenant()
|
|
|
|
# create tap flow in the db model
|
|
with context.session.begin(subtransactions=True):
|
|
tf = super(TaasPlugin, self).create_tap_flow(context, tap_flow)
|
|
driver_context = sd_context.TapFlowContext(self, context, tf)
|
|
self.driver.create_tap_flow_precommit(driver_context)
|
|
|
|
try:
|
|
self.driver.create_tap_flow_postcommit(driver_context)
|
|
except Exception:
|
|
with excutils.save_and_reraise_exception():
|
|
LOG.error("Failed to create tap flow on driver,"
|
|
"deleting tap_flow %s", tf['id'])
|
|
super(TaasPlugin, self).delete_tap_flow(context, tf['id'])
|
|
|
|
return tf
|
|
|
|
def delete_tap_flow(self, context, id):
|
|
LOG.debug("delete_tap_flow() called")
|
|
|
|
with context.session.begin(subtransactions=True):
|
|
tf = self.get_tap_flow(context, id)
|
|
driver_context = sd_context.TapFlowContext(self, context, tf)
|
|
if tf['status'] == constants.ACTIVE:
|
|
tf['status'] = constants.PENDING_DELETE
|
|
super(TaasPlugin, self).update_tap_flow(context, id,
|
|
{'tap_flow': tf})
|
|
method = self.driver.delete_tap_flow_precommit
|
|
else:
|
|
super(TaasPlugin, self).delete_tap_flow(context, id)
|
|
method = self.driver.delete_tap_flow_postcommit
|
|
|
|
try:
|
|
method(driver_context)
|
|
except Exception:
|
|
with excutils.save_and_reraise_exception():
|
|
LOG.error("Failed to delete tap flow on driver. "
|
|
"tap_flow: %s", id)
|
|
|
|
@registry.receives(resources.PORT, [events.PRECOMMIT_DELETE])
|
|
def handle_delete_port(self, resource, event, trigger, payload):
|
|
context = payload.context
|
|
deleted_port = payload.latest_state
|
|
if not deleted_port:
|
|
LOG.error("TaaS: Handle Delete Port: Invalid port object received")
|
|
return
|
|
|
|
deleted_port_id = deleted_port['id']
|
|
LOG.info("TaaS: Handle Delete Port: %s", deleted_port_id)
|
|
|
|
# Get list of configured tap-services
|
|
t_s_collection = self.get_tap_services(
|
|
context,
|
|
filters={'port_id': [deleted_port_id]}, fields=['id'])
|
|
|
|
for t_s in t_s_collection:
|
|
try:
|
|
self.delete_tap_service(context, t_s['id'])
|
|
except taas_ex.TapServiceNotFound:
|
|
LOG.debug("Not found tap_service: %s", t_s['id'])
|
|
|
|
t_f_collection = self.get_tap_flows(
|
|
context,
|
|
filters={'source_port': [deleted_port_id]}, fields=['id'])
|
|
|
|
for t_f in t_f_collection:
|
|
try:
|
|
self.delete_tap_flow(context, t_f['id'])
|
|
except taas_ex.TapFlowNotFound:
|
|
LOG.debug("Not found tap_flow: %s", t_f['id'])
|