Remove unused drivers and related code
Change-Id: I5306ceec11aa77f582eeb4a8e9666001667864f4
(cherry picked from commit 3087262c56
)
This commit is contained in:
parent
441bb72fcd
commit
47158fe945
|
@ -1,47 +0,0 @@
|
|||
# Copyright 2014 Alcatel-Lucent USA Inc.
|
||||
#
|
||||
# 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.plugins.ml2 import driver_api as api
|
||||
|
||||
from gbpservice.neutron.services.grouppolicy.drivers.nuage import driver
|
||||
|
||||
|
||||
NOVA_PORT_OWNER_PREF = 'compute:'
|
||||
|
||||
|
||||
class NuageMechanismGBPDriver(api.MechanismDriver):
|
||||
|
||||
def initialize(self):
|
||||
self._nuage_gbp = None
|
||||
|
||||
@property
|
||||
def nuage_gbp(self):
|
||||
if not self._nuage_gbp:
|
||||
self._nuage_gbp = (driver.NuageGBPDriver.
|
||||
get_initialized_instance())
|
||||
return self._nuage_gbp
|
||||
|
||||
def update_port_postcommit(self, context):
|
||||
port = context.current
|
||||
port_prefix = NOVA_PORT_OWNER_PREF
|
||||
# Check two things prior to proceeding with
|
||||
# talking to backend.
|
||||
# 1) binding has happened successfully.
|
||||
# 2) Its a VM port.
|
||||
if ((not context.original_bound_segment and
|
||||
context.bound_segment) and
|
||||
port['device_owner'].startswith(port_prefix)):
|
||||
self.nuage_gbp.create_nuage_policy_target(
|
||||
context._plugin_context, context.current)
|
|
@ -1,76 +0,0 @@
|
|||
# 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.common import constants as n_constants
|
||||
from neutron.extensions import portbindings
|
||||
from neutron.plugins.common import constants
|
||||
from neutron.plugins.ml2 import driver_api as api
|
||||
from oslo_log import log as log
|
||||
|
||||
from gbpservice.neutron.services.grouppolicy.drivers.odl import odl_mapping
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class OdlMechanismGBPDriver(api.MechanismDriver):
|
||||
|
||||
def initialize(self):
|
||||
self._odl_gbp = None
|
||||
self.vif_type = portbindings.VIF_TYPE_OVS
|
||||
self.vif_details = {portbindings.CAP_PORT_FILTER: True}
|
||||
|
||||
@property
|
||||
def odl_gbp(self):
|
||||
if not self._odl_gbp:
|
||||
self._odl_gbp = (odl_mapping.OdlMappingDriver.
|
||||
get_initialized_instance())
|
||||
return self._odl_gbp
|
||||
|
||||
def create_port_postcommit(self, context):
|
||||
# DHCP Ports are created implicitly by Neutron, need to inform GBP
|
||||
if (context.current.get('device_owner') ==
|
||||
n_constants.DEVICE_OWNER_DHCP):
|
||||
self.odl_gbp.create_dhcp_policy_target_if_needed(
|
||||
context._plugin_context, context.current
|
||||
)
|
||||
|
||||
def bind_port(self, context):
|
||||
LOG.debug("Attempting to bind port %(port)s on "
|
||||
"network %(network)s",
|
||||
{'port': context.current['id'],
|
||||
'network': context.network.current['id']})
|
||||
for segment in context.network.network_segments:
|
||||
if self._check_segment(segment):
|
||||
context.set_binding(segment[api.ID],
|
||||
self.vif_type,
|
||||
self.vif_details,
|
||||
status=n_constants.PORT_STATUS_ACTIVE)
|
||||
LOG.debug("Bound using segment: %s", segment)
|
||||
return
|
||||
else:
|
||||
LOG.debug("Refusing to bind port for segment ID %(id)s, "
|
||||
"segment %(seg)s, phys net %(physnet)s, and "
|
||||
"network type %(nettype)s",
|
||||
{'id': segment[api.ID],
|
||||
'seg': segment[api.SEGMENTATION_ID],
|
||||
'physnet': segment[api.PHYSICAL_NETWORK],
|
||||
'nettype': segment[api.NETWORK_TYPE]})
|
||||
|
||||
def _check_segment(self, segment):
|
||||
"""Verify a segment is valid for the OpenDaylight MechanismDriver.
|
||||
|
||||
Verify the requested segment is supported by ODL and return True or
|
||||
False to indicate this to callers.
|
||||
"""
|
||||
network_type = segment[api.NETWORK_TYPE]
|
||||
return network_type in [constants.TYPE_VXLAN, ]
|
|
@ -1,32 +0,0 @@
|
|||
# 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
|
||||
|
||||
|
||||
od_driver_opts = [
|
||||
cfg.StrOpt('odl_username',
|
||||
default='admin',
|
||||
help=_("OpenDaylight Controller Username")),
|
||||
cfg.StrOpt('odl_password',
|
||||
default='admin',
|
||||
help=_("OpenDaylight Controller Password")),
|
||||
cfg.StrOpt('odl_host',
|
||||
default='127.0.0.1',
|
||||
help=_("OpenDaylight Controller host ip address")),
|
||||
cfg.StrOpt('odl_port',
|
||||
default='8080',
|
||||
help=_("OpenDaylight Controller Rest API port number")),
|
||||
]
|
||||
|
||||
|
||||
cfg.CONF.register_opts(od_driver_opts, "odl_driver")
|
|
@ -1,288 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import requests
|
||||
from requests import auth
|
||||
|
||||
from neutron._i18n import _LI
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
cfg.CONF.import_opt(
|
||||
'odl_username',
|
||||
'gbpservice.neutron.services.grouppolicy.drivers.odl.config',
|
||||
group='odl_driver'
|
||||
)
|
||||
cfg.CONF.import_opt(
|
||||
'odl_password',
|
||||
'gbpservice.neutron.services.grouppolicy.drivers.odl.config',
|
||||
group='odl_driver'
|
||||
)
|
||||
cfg.CONF.import_opt(
|
||||
'odl_host',
|
||||
'gbpservice.neutron.services.grouppolicy.drivers.odl.config',
|
||||
group='odl_driver'
|
||||
)
|
||||
cfg.CONF.import_opt(
|
||||
'odl_port',
|
||||
'gbpservice.neutron.services.grouppolicy.drivers.odl.config',
|
||||
group='odl_driver'
|
||||
)
|
||||
|
||||
|
||||
class OdlManager(object):
|
||||
"""Class to manage ODL translations and workflow.
|
||||
|
||||
This class manages translation from Neutron objects to APIC
|
||||
managed objects and contains workflows to implement these
|
||||
translations.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
|
||||
LOG.info(_LI("Configured ODL username: %s"),
|
||||
cfg.CONF.odl_driver.odl_username)
|
||||
LOG.info(_LI("Configured ODL password: %s"),
|
||||
cfg.CONF.odl_driver.odl_password)
|
||||
LOG.info(_LI("Configured ODL host: %s"),
|
||||
cfg.CONF.odl_driver.odl_host)
|
||||
LOG.info(_LI("Configured ODL port: %s"),
|
||||
cfg.CONF.odl_driver.odl_port)
|
||||
|
||||
self._username = cfg.CONF.odl_driver.odl_username
|
||||
self._password = cfg.CONF.odl_driver.odl_password
|
||||
self._host = cfg.CONF.odl_driver.odl_host
|
||||
self._port = cfg.CONF.odl_driver.odl_port
|
||||
self._headers = {
|
||||
'Content-type': 'application/yang.data+json',
|
||||
'Accept': 'application/yang.data+json',
|
||||
}
|
||||
|
||||
self._base_url = (
|
||||
"http://%(host)s:%(port)s/restconf" %
|
||||
{'host': self._host, 'port': self._port}
|
||||
)
|
||||
self._reg_ep_url = (
|
||||
self._base_url +
|
||||
'/operations/endpoint:register-endpoint'
|
||||
)
|
||||
self._unreg_ep_url = (
|
||||
self._base_url +
|
||||
'/operations/endpoint:unregister-endpoint'
|
||||
)
|
||||
self._policy_url = (
|
||||
self._base_url +
|
||||
'/config/policy:tenants/policy:tenant/%(tenant_id)s'
|
||||
)
|
||||
self._action_url = (
|
||||
self._policy_url +
|
||||
'/subject-feature-instances/action-instance/%(action)s'
|
||||
)
|
||||
self._classifier_url = (
|
||||
self._policy_url +
|
||||
'/subject-feature-instances/classifier-instance/%(classifier)s'
|
||||
)
|
||||
self._l3ctx_url = (
|
||||
self._policy_url +
|
||||
'/l3-context/%(l3ctx)s'
|
||||
)
|
||||
self._l2bd_url = (
|
||||
self._policy_url +
|
||||
'/l2-bridge-domain/%(l2bd)s'
|
||||
)
|
||||
self._l2fd_url = (
|
||||
self._policy_url +
|
||||
'/l2-flood-domain/%(l2fd)s'
|
||||
)
|
||||
self._epg_url = (
|
||||
self._policy_url +
|
||||
'/policy:endpoint-group/%(epg)s'
|
||||
)
|
||||
self._subnet_url = (
|
||||
self._policy_url +
|
||||
'/subnet/%(subnet)s'
|
||||
)
|
||||
self._contract_url = (
|
||||
self._policy_url +
|
||||
'/policy:contract/%(contract)s'
|
||||
)
|
||||
|
||||
def _convert2ascii(self, obj):
|
||||
if isinstance(obj, dict):
|
||||
return {self._convert2ascii(key): self._convert2ascii(value) for
|
||||
key, value in obj.iteritems()}
|
||||
elif isinstance(obj, list):
|
||||
return [self._convert2ascii(element) for element in obj]
|
||||
elif isinstance(obj, unicode):
|
||||
return obj.encode('ascii', 'ignore')
|
||||
else:
|
||||
return obj
|
||||
|
||||
def _sendjson(self, method, url, headers, obj=None):
|
||||
"""Send json to the ODL controller."""
|
||||
|
||||
medium = self._convert2ascii(obj) if obj else None
|
||||
url = self._convert2ascii(url)
|
||||
data = (
|
||||
jsonutils.dumps(medium, indent=4, sort_keys=True) if medium
|
||||
else None
|
||||
)
|
||||
LOG.debug("=========================================================")
|
||||
LOG.debug("Sending METHOD (%(method)s) URL (%(url)s)",
|
||||
{'method': method, 'url': url})
|
||||
LOG.debug("(%(data)s)", {'data': data})
|
||||
LOG.debug("=========================================================")
|
||||
r = requests.request(
|
||||
method,
|
||||
url=url,
|
||||
headers=headers,
|
||||
data=data,
|
||||
auth=auth.HTTPBasicAuth(self._username,
|
||||
self._password)
|
||||
)
|
||||
r.raise_for_status()
|
||||
|
||||
def _is_tenant_created(self, tenant_id):
|
||||
url = self._convert2ascii(self._policy_url % {'tenant_id': tenant_id})
|
||||
r = requests.request(
|
||||
'get',
|
||||
url=url,
|
||||
headers=self._headers,
|
||||
auth=auth.HTTPBasicAuth(self._username,
|
||||
self._password)
|
||||
)
|
||||
if r.status_code == 200:
|
||||
return True
|
||||
elif r.status_code == 404:
|
||||
return False
|
||||
else:
|
||||
r.raise_for_status()
|
||||
|
||||
def register_endpoints(self, endpoints):
|
||||
for ep in endpoints:
|
||||
data = {"input": ep}
|
||||
self._sendjson('post', self._reg_ep_url, self._headers, data)
|
||||
|
||||
def unregister_endpoints(self, endpoints):
|
||||
for ep in endpoints:
|
||||
data = {"input": ep}
|
||||
self._sendjson('post', self._unreg_ep_url, self._headers, data)
|
||||
|
||||
def create_update_tenant(self, tenant_id, tenant):
|
||||
url = (self._policy_url % {'tenant_id': tenant_id})
|
||||
data = {"tenant": tenant}
|
||||
self._sendjson('put', url, self._headers, data)
|
||||
|
||||
def create_action(self, tenant_id, action):
|
||||
"""Create policy action"""
|
||||
self._touch_tenant(tenant_id)
|
||||
url = (self._action_url %
|
||||
{'tenant_id': tenant_id, 'action': action['name']})
|
||||
data = {"action-instance": action}
|
||||
self._sendjson('put', url, self._headers, data)
|
||||
|
||||
def delete_action(self, tenant_id, action):
|
||||
"""Delete policy action"""
|
||||
url = (self._action_url %
|
||||
{'tenant_id': tenant_id, 'action': action['name']})
|
||||
self._sendjson('delete', url, self._headers)
|
||||
|
||||
def create_classifier(self, tenant_id, classifier):
|
||||
"""Create policy classifier"""
|
||||
self._touch_tenant(tenant_id)
|
||||
url = (self._classifier_url %
|
||||
{'tenant_id': tenant_id, 'classifier': classifier['name']})
|
||||
data = {"classifier-instance": classifier}
|
||||
self._sendjson('put', url, self._headers, data)
|
||||
|
||||
def delete_classifier(self, tenant_id, classifier):
|
||||
"""Delete policy classifier"""
|
||||
url = (self._classifier_url %
|
||||
{'tenant_id': tenant_id, 'classifier': classifier['name']})
|
||||
self._sendjson('delete', url, self._headers)
|
||||
|
||||
def create_update_l3_context(self, tenant_id, l3ctx):
|
||||
self._touch_tenant(tenant_id)
|
||||
url = (self._l3ctx_url %
|
||||
{'tenant_id': tenant_id, 'l3ctx': l3ctx['id']})
|
||||
data = {"l3-context": l3ctx}
|
||||
self._sendjson('put', url, self._headers, data)
|
||||
|
||||
def delete_l3_context(self, tenant_id, l3ctx):
|
||||
url = (self._l3ctx_url %
|
||||
{'tenant_id': tenant_id, 'l3ctx': l3ctx['id']})
|
||||
self._sendjson('delete', url, self._headers)
|
||||
|
||||
def create_update_l2_bridge_domain(self, tenant_id, l2bd):
|
||||
self._touch_tenant(tenant_id)
|
||||
url = (self._l2bd_url %
|
||||
{'tenant_id': tenant_id, 'l2bd': l2bd['id']})
|
||||
data = {"l2-bridge-domain": l2bd}
|
||||
self._sendjson('put', url, self._headers, data)
|
||||
|
||||
def delete_l2_bridge_domain(self, tenant_id, l2bd):
|
||||
url = (self._l2bd_url %
|
||||
{'tenant_id': tenant_id, 'l2bd': l2bd['id']})
|
||||
self._sendjson('delete', url, self._headers)
|
||||
|
||||
def create_update_l2_flood_domain(self, tenant_id, l2fd):
|
||||
self._touch_tenant(tenant_id)
|
||||
url = (self._l2fd_url %
|
||||
{'tenant_id': tenant_id, 'l2fd': l2fd['id']})
|
||||
data = {"l2-flood-domain": l2fd}
|
||||
self._sendjson('put', url, self._headers, data)
|
||||
|
||||
def delete_l2_flood_domain(self, tenant_id, l2fd):
|
||||
url = (self._l2fd_url %
|
||||
{'tenant_id': tenant_id, 'l2fd': l2fd['id']})
|
||||
self._sendjson('delete', url, self._headers)
|
||||
|
||||
def create_update_endpoint_group(self, tenant_id, epg):
|
||||
self._touch_tenant(tenant_id)
|
||||
url = (self._epg_url %
|
||||
{'tenant_id': tenant_id, 'epg': epg['id']})
|
||||
data = {"endpoint-group": epg}
|
||||
self._sendjson('put', url, self._headers, data)
|
||||
|
||||
def delete_endpoint_group(self, tenant_id, epg):
|
||||
url = (self._epg_url %
|
||||
{'tenant_id': tenant_id, 'epg': epg['id']})
|
||||
self._sendjson('delete', url, self._headers)
|
||||
|
||||
def create_update_subnet(self, tenant_id, subnet):
|
||||
self._touch_tenant(tenant_id)
|
||||
url = (self._subnet_url %
|
||||
{'tenant_id': tenant_id, 'subnet': subnet['id']})
|
||||
data = {"subnet": subnet}
|
||||
self._sendjson('put', url, self._headers, data)
|
||||
|
||||
def delete_subnet(self, tenant_id, subnet):
|
||||
url = (self._subnet_url %
|
||||
{'tenant_id': tenant_id, 'subnet': subnet['id']})
|
||||
self._sendjson('delete', url, self._headers)
|
||||
|
||||
def create_update_contract(self, tenant_id, contract):
|
||||
url = (self._contract_url %
|
||||
{'tenant_id': tenant_id, 'contract': contract['id']})
|
||||
data = {"contract": contract}
|
||||
self._sendjson('put', url, self._headers, data)
|
||||
|
||||
def _touch_tenant(self, tenant_id):
|
||||
tenant = {
|
||||
"id": tenant_id
|
||||
}
|
||||
if not self._is_tenant_created(tenant_id):
|
||||
self.create_update_tenant(tenant_id, tenant)
|
|
@ -1,636 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import uuid
|
||||
|
||||
from neutron.common import constants
|
||||
from neutron import manager
|
||||
from oslo_concurrency import lockutils # noqa
|
||||
from oslo_log import log as logging
|
||||
|
||||
from gbpservice.neutron.db.grouppolicy import group_policy_mapping_db as gpdb
|
||||
from gbpservice.neutron.services.grouppolicy.common import constants as g_const
|
||||
from gbpservice.neutron.services.grouppolicy.common import exceptions as gpexc
|
||||
from gbpservice.neutron.services.grouppolicy.drivers import (
|
||||
resource_mapping as api)
|
||||
from gbpservice.neutron.services.grouppolicy.drivers.odl import odl_manager
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ExternalSegmentNotSupportedOnOdlDriver(gpexc.GroupPolicyBadRequest):
|
||||
message = _("External Segment currently not supported on ODL GBP "
|
||||
"driver.")
|
||||
|
||||
|
||||
class UpdateL3PolicyNotSupportedOnOdlDriver(gpexc.GroupPolicyBadRequest):
|
||||
message = _("Update L3 Policy currently not supported on ODL GBP "
|
||||
"driver.")
|
||||
|
||||
|
||||
class UpdateL2PolicyNotSupportedOnOdlDriver(gpexc.GroupPolicyBadRequest):
|
||||
message = _("Update L2 Policy currently not supported on ODL GBP "
|
||||
"driver.")
|
||||
|
||||
|
||||
class UpdatePTNotSupportedOnOdlDriver(gpexc.GroupPolicyBadRequest):
|
||||
message = _("Update Policy Target currently not supported on ODL GBP "
|
||||
"driver.")
|
||||
|
||||
|
||||
class UpdatePTGNotSupportedOnOdlDriver(gpexc.GroupPolicyBadRequest):
|
||||
message = _("Update Policy Target Group currently not supported on ODL "
|
||||
"GBP driver.")
|
||||
|
||||
|
||||
class L2PolicyMultiplePolicyTargetGroupNotSupportedOnOdlDriver(
|
||||
gpexc.GroupPolicyBadRequest):
|
||||
message = _("An L2 policy can't have multiple policy target groups on "
|
||||
"ODL GBP driver.")
|
||||
|
||||
|
||||
class UpdatePolicyActionNotSupportedOnOdlDriver(gpexc.GroupPolicyBadRequest):
|
||||
message = _("Update Policy Action currently not supported on ODL GBP "
|
||||
"driver.")
|
||||
|
||||
|
||||
class RedirectActionNotSupportedOnOdlDriver(gpexc.GroupPolicyBadRequest):
|
||||
message = _("Redirect action is currently not supported for ODL GBP "
|
||||
"driver.")
|
||||
|
||||
|
||||
class OnlyAllowActionSupportedOnOdlDriver(gpexc.GroupPolicyBadRequest):
|
||||
message = _("Currently only allow action is supported for ODL GBP "
|
||||
"driver.")
|
||||
|
||||
|
||||
class UpdateClassifierNotSupportedOnOdlDriver(gpexc.GroupPolicyBadRequest):
|
||||
message = _("Update Policy Classifier currently not supported on ODL GBP "
|
||||
"driver.")
|
||||
|
||||
|
||||
class PolicyRuleUpdateNotSupportedOnOdlDriver(gpexc.GroupPolicyBadRequest):
|
||||
message = _("Policy rule update is not supported on for ODL GBP "
|
||||
"driver.")
|
||||
|
||||
|
||||
class PolicyRuleSetUpdateNotSupportedOnOdlDriver(gpexc.GroupPolicyBadRequest):
|
||||
message = _("Policy rule set update is not supported on for ODL GBP "
|
||||
"driver.")
|
||||
|
||||
|
||||
class ExactlyOneActionPerRuleIsSupportedOnOdlDriver(
|
||||
gpexc.GroupPolicyBadRequest):
|
||||
message = _("Exactly one action per rule is supported on ODL GBP driver.")
|
||||
|
||||
|
||||
class ClassifierTcpUdpPortRangeNotSupportedOnOdlDriver(
|
||||
gpexc.GroupPolicyBadRequest):
|
||||
message = _("Tcp or Udp port range is not supported on ODL GBP driver.")
|
||||
|
||||
|
||||
class ClassifierUnknownIPProtocolNotSupportedOnOdlDriver(
|
||||
gpexc.GroupPolicyBadRequest):
|
||||
message = _("Unknown IP Protocol is not supported on ODL GBP driver.")
|
||||
|
||||
|
||||
class OdlMappingDriver(api.ResourceMappingDriver):
|
||||
"""ODL Mapping driver for Group Policy plugin.
|
||||
|
||||
This driver implements group policy semantics by mapping group
|
||||
policy resources to various other neutron resources, and leverages
|
||||
ODL backend for enforcing the policies.
|
||||
"""
|
||||
|
||||
me = None
|
||||
manager = None
|
||||
|
||||
@staticmethod
|
||||
def get_odl_manager():
|
||||
if not OdlMappingDriver.manager:
|
||||
OdlMappingDriver.manager = odl_manager.OdlManager()
|
||||
return OdlMappingDriver.manager
|
||||
|
||||
def initialize(self):
|
||||
super(OdlMappingDriver, self).initialize()
|
||||
self.odl_manager = OdlMappingDriver.get_odl_manager()
|
||||
self._gbp_plugin = None
|
||||
OdlMappingDriver.me = self
|
||||
|
||||
@property
|
||||
def gbp_plugin(self):
|
||||
if not self._gbp_plugin:
|
||||
self._gbp_plugin = (manager.NeutronManager.get_service_plugins()
|
||||
.get("GROUP_POLICY"))
|
||||
return self._gbp_plugin
|
||||
|
||||
@staticmethod
|
||||
def get_initialized_instance():
|
||||
return OdlMappingDriver.me
|
||||
|
||||
def create_dhcp_policy_target_if_needed(self, plugin_context, port):
|
||||
session = plugin_context.session
|
||||
if (self._port_is_owned(session, port['id'])):
|
||||
# Nothing to do
|
||||
return
|
||||
|
||||
# Retrieve PTG
|
||||
# TODO(ywu): optimize later
|
||||
subnets = self._core_plugin._get_subnets_by_network(
|
||||
plugin_context, port['network_id']
|
||||
)
|
||||
ptg = (plugin_context.session.query(gpdb.PolicyTargetGroupMapping).
|
||||
join(gpdb.PolicyTargetGroupMapping.subnets).
|
||||
filter(gpdb.PTGToSubnetAssociation.subnet_id ==
|
||||
subnets[0]['id']).
|
||||
first())
|
||||
|
||||
# Create PolicyTarget
|
||||
attrs = {'policy_target':
|
||||
{'tenant_id': port['tenant_id'],
|
||||
'name': 'dhcp-%s' % ptg['id'],
|
||||
'description': ("Implicitly created DHCP policy "
|
||||
"target"),
|
||||
'policy_target_group_id': ptg['id'],
|
||||
'port_id': port['id']}}
|
||||
self.gbp_plugin.create_policy_target(plugin_context, attrs)
|
||||
# TODO(ODL): security group is not required
|
||||
# sg_id = self._ensure_default_security_group(plugin_context,
|
||||
# port['tenant_id'])
|
||||
# data = {'port': {'security_groups': [sg_id]}}
|
||||
# self._core_plugin.update_port(plugin_context, port['id'], data)
|
||||
|
||||
def create_external_segment_precommit(self, context):
|
||||
raise ExternalSegmentNotSupportedOnOdlDriver()
|
||||
|
||||
def update_external_segment_precommit(self, context):
|
||||
raise ExternalSegmentNotSupportedOnOdlDriver()
|
||||
|
||||
def delete_external_segment_precommit(self, context):
|
||||
raise ExternalSegmentNotSupportedOnOdlDriver()
|
||||
|
||||
def create_external_policy_precommit(self, context):
|
||||
raise ExternalSegmentNotSupportedOnOdlDriver()
|
||||
|
||||
def update_external_policy_precommit(self, context):
|
||||
raise ExternalSegmentNotSupportedOnOdlDriver()
|
||||
|
||||
def delete_external_policy_precommit(self, context):
|
||||
raise ExternalSegmentNotSupportedOnOdlDriver()
|
||||
|
||||
def create_nat_pool_precommit(self, context):
|
||||
raise ExternalSegmentNotSupportedOnOdlDriver()
|
||||
|
||||
def update_nat_pool_precommit(self, context):
|
||||
raise ExternalSegmentNotSupportedOnOdlDriver()
|
||||
|
||||
def delete_nat_pool_precommit(self, context):
|
||||
raise ExternalSegmentNotSupportedOnOdlDriver()
|
||||
|
||||
def create_policy_target_postcommit(self, context):
|
||||
super(OdlMappingDriver, self).create_policy_target_postcommit(context)
|
||||
pt = self._get_pt_detail(context)
|
||||
ep = {
|
||||
"endpoint-group": pt['ptg_id'],
|
||||
"l2-context": pt['l2ctx_id'],
|
||||
"l3-address": pt['l3_list'],
|
||||
"mac-address": pt['mac_address'],
|
||||
"port-name": pt['neutron_port_id'],
|
||||
"tenant": pt['tenant_id']
|
||||
}
|
||||
self.odl_manager.register_endpoints([ep])
|
||||
|
||||
def update_policy_target_precommit(self, context):
|
||||
raise UpdatePTNotSupportedOnOdlDriver()
|
||||
|
||||
def delete_policy_target_postcommit(self, context):
|
||||
pt = self._get_pt_detail(context)
|
||||
ep = {
|
||||
"l2": pt['l2_list'],
|
||||
"l3": pt['l3_list']
|
||||
}
|
||||
self.odl_manager.unregister_endpoints([ep])
|
||||
# Delete Neutron's port
|
||||
super(OdlMappingDriver, self).delete_policy_target_postcommit(context)
|
||||
|
||||
def create_l3_policy_postcommit(self, context):
|
||||
tenant_id = uuid.UUID(context.current['tenant_id']).urn[9:]
|
||||
l3ctx = {
|
||||
"id": context.current['id'],
|
||||
"name": context.current['name'],
|
||||
"description": context.current['description']
|
||||
}
|
||||
self.odl_manager.create_update_l3_context(tenant_id, l3ctx)
|
||||
|
||||
def update_l3_policy_precommit(self, context):
|
||||
raise UpdateL3PolicyNotSupportedOnOdlDriver()
|
||||
|
||||
def delete_l3_policy_postcommit(self, context):
|
||||
tenant_id = uuid.UUID(context.current['tenant_id']).urn[9:]
|
||||
l3ctx = {
|
||||
"id": context.current['id']
|
||||
}
|
||||
self.odl_manager.delete_l3_context(tenant_id, l3ctx)
|
||||
|
||||
def create_l2_policy_postcommit(self, context):
|
||||
super(OdlMappingDriver, self).create_l2_policy_postcommit(context)
|
||||
tenant_id = uuid.UUID(context.current['tenant_id']).urn[9:]
|
||||
|
||||
# l2_policy mapped to l2_bridge_domain in ODL
|
||||
l2bd = {
|
||||
"id": context.current['id'],
|
||||
"name": context.current['name'],
|
||||
"description": context.current['description'],
|
||||
"parent": context.current['l3_policy_id']
|
||||
}
|
||||
self.odl_manager.create_update_l2_bridge_domain(tenant_id, l2bd)
|
||||
|
||||
# Implicit network within l2 policy mapped to l2 FD in ODL
|
||||
net_id = context.current['network_id']
|
||||
network = self._core_plugin.get_network(context._plugin_context,
|
||||
net_id)
|
||||
l2fd = {
|
||||
"id": net_id,
|
||||
"name": network['name'],
|
||||
"parent": context.current['id']
|
||||
}
|
||||
self.odl_manager.create_update_l2_flood_domain(tenant_id, l2fd)
|
||||
|
||||
def update_l2_policy_precommit(self, context):
|
||||
raise UpdateL2PolicyNotSupportedOnOdlDriver()
|
||||
|
||||
def delete_l2_policy_postcommit(self, context):
|
||||
super(OdlMappingDriver, self).delete_l2_policy_postcommit(context)
|
||||
tenant_id = uuid.UUID(context.current['tenant_id']).urn[9:]
|
||||
|
||||
# l2_policy mapped to l2_bridge_domain in ODL
|
||||
l2bd = {
|
||||
"id": context.current['id']
|
||||
}
|
||||
self.odl_manager.delete_l2_bridge_domain(tenant_id, l2bd)
|
||||
|
||||
# Implicit network within l2 policy mapped to l2 FD in ODL
|
||||
net_id = context.current['network_id']
|
||||
l2fd = {
|
||||
"id": net_id,
|
||||
}
|
||||
self.odl_manager.delete_l2_flood_domain(tenant_id, l2fd)
|
||||
|
||||
def create_policy_target_group_postcommit(self, context):
|
||||
super(OdlMappingDriver, self).create_policy_target_group_postcommit(
|
||||
context)
|
||||
|
||||
# consumed_policy_rule_sets mapped to consumer_named_selectors
|
||||
consumer_named_selectors = []
|
||||
for prs_id in context.current['consumed_policy_rule_sets']:
|
||||
prs = context._plugin.get_policy_rule_set(
|
||||
context._plugin_context, prs_id
|
||||
)
|
||||
consumer_named_selectors.append(
|
||||
{
|
||||
"name": prs['name'],
|
||||
"contract": prs_id
|
||||
}
|
||||
)
|
||||
|
||||
# provided_policy_rule_sets mapped to provider_named_selectors
|
||||
provider_named_selectors = []
|
||||
for prs_id in context.current['provided_policy_rule_sets']:
|
||||
prs = context._plugin.get_policy_rule_set(
|
||||
context._plugin_context, prs_id
|
||||
)
|
||||
provider_named_selectors.append(
|
||||
{
|
||||
"name": prs['name'],
|
||||
"contract": prs_id
|
||||
}
|
||||
)
|
||||
|
||||
# PTG mapped to EPG in ODL
|
||||
subnets = context.current['subnets']
|
||||
epg = {
|
||||
"id": context.current['id'],
|
||||
"name": context.current['name'],
|
||||
"description": context.current['description'],
|
||||
"network-domain": subnets[0],
|
||||
"consumer-named-selector": consumer_named_selectors,
|
||||
"provider-named-selector": provider_named_selectors
|
||||
}
|
||||
tenant_id = uuid.UUID(context.current['tenant_id']).urn[9:]
|
||||
self.odl_manager.create_update_endpoint_group(tenant_id, epg)
|
||||
|
||||
# Implicit subnet within policy target group mapped to subnet in ODL
|
||||
for subnet_id in subnets:
|
||||
neutron_subnet = self._core_plugin.get_subnet(
|
||||
context._plugin_context, subnet_id
|
||||
)
|
||||
odl_subnet = {
|
||||
"id": subnet_id,
|
||||
"ip-prefix": neutron_subnet['cidr'],
|
||||
"parent": neutron_subnet['network_id'],
|
||||
"virtual-router-ip": neutron_subnet['gateway_ip']
|
||||
}
|
||||
self.odl_manager.create_update_subnet(tenant_id, odl_subnet)
|
||||
|
||||
def update_policy_target_group_precommit(self, context):
|
||||
raise UpdatePTGNotSupportedOnOdlDriver()
|
||||
|
||||
def delete_policy_target_group_postcommit(self, context):
|
||||
tenant_id = uuid.UUID(context.current['tenant_id']).urn[9:]
|
||||
subnets = context.current['subnets']
|
||||
|
||||
# delete mapped subnets in ODL, and clean them up from neutron
|
||||
for subnet_id in subnets:
|
||||
self._cleanup_subnet(context._plugin_context, subnet_id, None)
|
||||
odl_subnet = {
|
||||
"id": subnet_id
|
||||
}
|
||||
self.odl_manager.delete_subnet(tenant_id, odl_subnet)
|
||||
|
||||
# delete mapped EPG in ODL
|
||||
epg = {
|
||||
"id": context.current['id'],
|
||||
}
|
||||
self.odl_manager.delete_endpoint_group(tenant_id, epg)
|
||||
|
||||
def create_policy_action_precommit(self, context):
|
||||
# TODO(odl): allow redirect for service chaining
|
||||
if context.current['action_type'] == g_const.GP_ACTION_REDIRECT:
|
||||
raise RedirectActionNotSupportedOnOdlDriver()
|
||||
|
||||
def create_policy_action_postcommit(self, context):
|
||||
super(OdlMappingDriver, self).create_policy_action_postcommit(context)
|
||||
# TODO(ODL): remove comment out after PoC
|
||||
# tenant_id = uuid.UUID(context.current['tenant_id']).urn[9:]
|
||||
|
||||
# fill in action instance data
|
||||
if context.current['action_type'] == g_const.GP_ACTION_ALLOW:
|
||||
# TODO(ODL): remove the return and comment out after POC
|
||||
return
|
||||
# action_definition_id = "f942e8fd-e957-42b7-bd18-f73d11266d17"
|
||||
# action_instance = {
|
||||
# "action-definition-id": action_definition_id,
|
||||
# "name": context.current['name'],
|
||||
# "parameter-value": [
|
||||
# {
|
||||
# "name": context.current['name'],
|
||||
# "string-value": context.current['action_type'],
|
||||
# }
|
||||
# ]
|
||||
# }
|
||||
# self.odl_manager.create_action(tenant_id, action_instance)
|
||||
else:
|
||||
raise OnlyAllowActionSupportedOnOdlDriver()
|
||||
|
||||
def update_policy_action_precommit(self, context):
|
||||
raise UpdatePolicyActionNotSupportedOnOdlDriver()
|
||||
|
||||
def delete_policy_action_postcommit(self, context):
|
||||
super(OdlMappingDriver, self).delete_policy_action_postcommit(context)
|
||||
# TODO(ODL): remove comment out after PoC
|
||||
# tenant_id = uuid.UUID(context.current['tenant_id']).urn[9:]
|
||||
#
|
||||
# # fill in action instance data
|
||||
# action_instance = {
|
||||
# "name": context.current['name']
|
||||
# }
|
||||
# self.odl_manager.delete_action(tenant_id, action_instance)
|
||||
|
||||
def create_policy_classifier_postcommit(self, context):
|
||||
tenant_id = uuid.UUID(context.current['tenant_id']).urn[9:]
|
||||
classifiers = self._make_odl_classifiers(context.current)
|
||||
|
||||
for classifier in classifiers:
|
||||
classifier_instance = {
|
||||
"classifier-definition-id":
|
||||
classifier['classifier-definition-id'],
|
||||
"name": classifier['name'],
|
||||
"parameter-value": classifier['parameter-value']
|
||||
}
|
||||
self.odl_manager.create_classifier(tenant_id, classifier_instance)
|
||||
|
||||
def _make_odl_classifiers(self, stack_classifier):
|
||||
classifiers = []
|
||||
if stack_classifier['protocol'] == constants.PROTO_NAME_ICMP:
|
||||
direction = stack_classifier['direction']
|
||||
if direction == 'bi':
|
||||
direction = "bidirectional"
|
||||
classifier = {
|
||||
# Use hard coded value based on current ODL implementation
|
||||
"classifier-definition-id":
|
||||
'79c6fdb2-1e1a-4832-af57-c65baf5c2335',
|
||||
"name": stack_classifier['name'],
|
||||
"parameter-value": [
|
||||
{
|
||||
"name": "proto",
|
||||
# TODO(yapeng): change the hard code value
|
||||
"int-value": 1,
|
||||
}
|
||||
],
|
||||
"direction": direction
|
||||
}
|
||||
classifiers.append(classifier)
|
||||
else:
|
||||
# For TCP and UDP protoocol create two classifier (in and out)
|
||||
for port in ['sourceport', 'destport']:
|
||||
if stack_classifier['direction'] == 'in':
|
||||
if port == 'destport':
|
||||
direction = 'in'
|
||||
else:
|
||||
direction = 'out'
|
||||
elif stack_classifier['direction'] == 'out':
|
||||
if port == 'destport':
|
||||
direction = 'out'
|
||||
else:
|
||||
direction = 'in'
|
||||
else:
|
||||
direction = 'bidirectional'
|
||||
|
||||
classifier = {
|
||||
# Use hard coded value based on current ODL implementation
|
||||
"classifier-definition-id":
|
||||
'4250ab32-e8b8-445a-aebb-e1bd2cdd291f',
|
||||
"direction": direction,
|
||||
"name": stack_classifier['name'] + '-' + port,
|
||||
"parameter-value": [
|
||||
{
|
||||
"name": "type",
|
||||
"string-value": stack_classifier['protocol'],
|
||||
},
|
||||
{
|
||||
"name": port,
|
||||
"int-value": stack_classifier['port_range'],
|
||||
}
|
||||
]
|
||||
}
|
||||
classifiers.append(classifier)
|
||||
return classifiers
|
||||
|
||||
def update_policy_classifier_precommit(self, context):
|
||||
raise UpdateClassifierNotSupportedOnOdlDriver()
|
||||
|
||||
def delete_policy_classifier_postcommit(self, context):
|
||||
tenant_id = uuid.UUID(context.current['tenant_id']).urn[9:]
|
||||
|
||||
if context.current['protocol'] == constants.PROTO_NAME_ICMP:
|
||||
# fill in classifier instance data
|
||||
classifier_instance = {
|
||||
"name": context.current['name']
|
||||
}
|
||||
self.odl_manager.delete_classifier(tenant_id, classifier_instance)
|
||||
return
|
||||
|
||||
# fill in classifier instance data
|
||||
for port in ['sourceport', 'destport']:
|
||||
classifier_instance = {
|
||||
"name": context.current['name'] + '-' + port,
|
||||
}
|
||||
self.odl_manager.delete_classifier(tenant_id, classifier_instance)
|
||||
|
||||
def create_policy_rule_precommit(self, context):
|
||||
if ('policy_actions' in context.current and
|
||||
len(context.current['policy_actions']) != 1):
|
||||
# TODO(odl): to be fixed when redirect is supported
|
||||
raise ExactlyOneActionPerRuleIsSupportedOnOdlDriver()
|
||||
|
||||
def update_policy_rule_precommit(self, context):
|
||||
# TODO(ivar): add support for action update on policy rules
|
||||
raise PolicyRuleUpdateNotSupportedOnOdlDriver()
|
||||
|
||||
def create_policy_rule_set_postcommit(self, context):
|
||||
"""Each Policy Rule Set is mapped to a contract, with a single clause
|
||||
|
||||
Each included Policy Rule will be mapped to one subject, which includes
|
||||
one rule.
|
||||
|
||||
The clause has no matcher, but refers to all the subjects
|
||||
"""
|
||||
subjects = []
|
||||
subject_names = []
|
||||
for rule_id in context.current['policy_rules']:
|
||||
subject = self._make_odl_subject(context, rule_id)
|
||||
subjects.append(subject)
|
||||
subject_names.append(subject['name'])
|
||||
|
||||
clauses = [
|
||||
{
|
||||
"name": context.current['name'],
|
||||
"subject-refs": subject_names
|
||||
}
|
||||
]
|
||||
|
||||
contract_id = context.current['id']
|
||||
contract_desc = context.current['name']
|
||||
contract = {
|
||||
"id": contract_id,
|
||||
"description": contract_desc,
|
||||
"clause": clauses,
|
||||
"subject": subjects
|
||||
}
|
||||
|
||||
tenant_id = uuid.UUID(context.current['tenant_id']).urn[9:]
|
||||
self.odl_manager.create_update_contract(tenant_id, contract)
|
||||
|
||||
def _make_odl_subject(self, context, rule_id):
|
||||
gbp_rule = context._plugin.get_policy_rule(
|
||||
context._plugin_context, rule_id
|
||||
)
|
||||
odl_rules = []
|
||||
odl_rule = self._make_odl_rule(context, rule_id)
|
||||
odl_rules.append(odl_rule)
|
||||
return {
|
||||
"name": gbp_rule['name'],
|
||||
"rule": odl_rules
|
||||
}
|
||||
|
||||
def _make_odl_rule(self, context, rule_id):
|
||||
rule = context._plugin.get_policy_rule(
|
||||
context._plugin_context, rule_id
|
||||
)
|
||||
stack_classifier = context._plugin.get_policy_classifier(
|
||||
context._plugin_context, rule['policy_classifier_id']
|
||||
)
|
||||
|
||||
# while openstack supports only one classifier per rule, the classifier
|
||||
# may mapped to multi classifier in ODL
|
||||
classifier_refs = []
|
||||
classifiers = self._make_odl_classifiers(stack_classifier)
|
||||
for classifier in classifiers:
|
||||
classifier_ref = {
|
||||
"name": classifier['name']
|
||||
}
|
||||
if classifier['direction'] != "bidirectional":
|
||||
classifier_ref['direction'] = classifier['direction']
|
||||
classifier_refs.append(classifier_ref)
|
||||
action_refs = []
|
||||
for action_id in rule['policy_actions']:
|
||||
action = context._plugin.get_policy_action(
|
||||
context._plugin_context, action_id
|
||||
)
|
||||
action_refs.append(
|
||||
{
|
||||
"name": action['name']
|
||||
}
|
||||
)
|
||||
|
||||
# TODO(ODL): send action_refs later but not for PoC
|
||||
return {
|
||||
"name": rule['name'],
|
||||
"classifier-ref": classifier_refs,
|
||||
}
|
||||
|
||||
def update_policy_rule_set_precommit(self, context):
|
||||
# TODO(Yi): add support for action update on policy rule sets
|
||||
raise PolicyRuleSetUpdateNotSupportedOnOdlDriver()
|
||||
|
||||
def _get_pt_detail(self, context):
|
||||
port_id = context.current['port_id']
|
||||
port = self._core_plugin.get_port(context._plugin_context, port_id)
|
||||
tenant_id = uuid.UUID(context.current['tenant_id']).urn[9:]
|
||||
ptg_id = context.current['policy_target_group_id']
|
||||
ptg = self.gbp_plugin.get_policy_target_group(context._plugin_context,
|
||||
ptg_id)
|
||||
l2ctx_id = ptg['l2_policy_id']
|
||||
l2ctx = self.gbp_plugin.get_l2_policy(context._plugin_context,
|
||||
l2ctx_id)
|
||||
l3ctx_id = l2ctx['l3_policy_id']
|
||||
mac_address = port['mac_address']
|
||||
neutron_port_id = 'tap' + port_id[:11]
|
||||
|
||||
l3_list = []
|
||||
for fixed_ip in port['fixed_ips']:
|
||||
l3_list.append(
|
||||
{
|
||||
"ip-address": fixed_ip['ip_address'],
|
||||
"l3-context": l3ctx_id
|
||||
}
|
||||
)
|
||||
|
||||
l2_list = [
|
||||
{
|
||||
"l2-context": l2ctx_id,
|
||||
"mac-address": mac_address
|
||||
}
|
||||
]
|
||||
|
||||
return {
|
||||
"port_id": port_id,
|
||||
"tenant_id": tenant_id,
|
||||
"ptg_id": ptg_id,
|
||||
"l2ctx_id": l2ctx_id,
|
||||
"l3ctx_id": l3ctx_id,
|
||||
"mac_address": mac_address,
|
||||
"neutron_port_id": neutron_port_id,
|
||||
"l3_list": l3_list,
|
||||
"l2_list": l2_list,
|
||||
}
|
|
@ -1,463 +0,0 @@
|
|||
# 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.
|
||||
|
||||
import requests
|
||||
import unittest
|
||||
|
||||
import mock
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
from gbpservice.neutron.services.grouppolicy import config
|
||||
from gbpservice.neutron.services.grouppolicy.drivers.odl import odl_manager
|
||||
|
||||
|
||||
HOST = 'fake_host'
|
||||
PORT = 'fake_port'
|
||||
USERNAME = 'fake_username'
|
||||
PASSWORD = 'fake_password'
|
||||
HEADER = {
|
||||
'Content-type': 'application/yang.data+json',
|
||||
'Accept': 'application/yang.data+json',
|
||||
}
|
||||
|
||||
VALUE = 'fake_value'
|
||||
TENANT_ID = 'fake_tenant_id'
|
||||
TENANT = {
|
||||
'id': TENANT_ID,
|
||||
'value': VALUE
|
||||
}
|
||||
ENDPOINT = 'fake_endpoint'
|
||||
ACTION_NAME = 'fake_action_name'
|
||||
ACTION = {
|
||||
'name': ACTION_NAME,
|
||||
'value': VALUE
|
||||
}
|
||||
CLASSIFIER_NAME = 'fake_classifier_name'
|
||||
CLASSIFIER = {
|
||||
'name': CLASSIFIER_NAME,
|
||||
'value': VALUE
|
||||
}
|
||||
L3CTX_ID = 'fake_l3ctx_id'
|
||||
L3CTX = {
|
||||
'id': L3CTX_ID,
|
||||
'value': VALUE
|
||||
}
|
||||
L2BD_ID = 'fake_l2bd_id'
|
||||
L2BD = {
|
||||
'id': L2BD_ID,
|
||||
'value': VALUE
|
||||
}
|
||||
L2FD_ID = 'fake_l2bd_id'
|
||||
L2FD = {
|
||||
'id': L2FD_ID,
|
||||
'value': VALUE
|
||||
}
|
||||
EPG_ID = 'fake_epg_id'
|
||||
EPG = {
|
||||
'id': EPG_ID,
|
||||
'value': VALUE
|
||||
}
|
||||
SUBNET_ID = 'fake_subnet_id'
|
||||
SUBNET = {
|
||||
'id': SUBNET_ID,
|
||||
'value': VALUE
|
||||
}
|
||||
CONTRACT_ID = 'fake_contract_id'
|
||||
CONTRACT = {
|
||||
'id': CONTRACT_ID,
|
||||
'value': VALUE
|
||||
}
|
||||
|
||||
URL_BASE = ("http://%(host)s:%(port)s/restconf" %
|
||||
{'host': HOST, 'port': PORT})
|
||||
URL_REG_EP = (URL_BASE +
|
||||
'/operations/endpoint:register-endpoint')
|
||||
URL_UNREG_EP = (URL_BASE +
|
||||
'/operations/endpoint:unregister-endpoint')
|
||||
URL_TENANT = (URL_BASE +
|
||||
'/config/policy:tenants/policy:tenant/%s' %
|
||||
TENANT_ID)
|
||||
URL_ACTION = (URL_TENANT +
|
||||
'/subject-feature-instances/action-instance/%s' %
|
||||
ACTION_NAME)
|
||||
URL_CLASSIFIER = (URL_TENANT +
|
||||
'/subject-feature-instances/classifier-instance/%s' %
|
||||
CLASSIFIER_NAME)
|
||||
URL_L3CTX = (URL_TENANT + '/l3-context/%s' % L3CTX_ID)
|
||||
URL_L2BD = (URL_TENANT + '/l2-bridge-domain/%s' % L2BD_ID)
|
||||
URL_L2FD = (URL_TENANT + '/l2-flood-domain/%s' % L2FD_ID)
|
||||
URL_EPG = (URL_TENANT + '/policy:endpoint-group/%s' % EPG_ID)
|
||||
URL_SUBNET = (URL_TENANT + '/subnet/%s' % SUBNET_ID)
|
||||
URL_CONTRACT = (URL_TENANT + '/policy:contract/%s' % CONTRACT_ID)
|
||||
|
||||
|
||||
class AuthMatcher(object):
|
||||
""" A customized class to check if authentication object is matched or not
|
||||
|
||||
AS authentication is passed as an object reference, we cannot test the
|
||||
object directly, instead, we check if the correct username and password
|
||||
is used
|
||||
"""
|
||||
|
||||
def __eq__(self, obj):
|
||||
return (obj.username == USERNAME and obj.password == PASSWORD)
|
||||
|
||||
|
||||
class DataMatcher(object):
|
||||
""" A customized class to check if data is matched or not
|
||||
|
||||
As data is passed as a string for HTTP request in ODL manager, we cannot
|
||||
directly test the data object. Instead, we have to convert the data to
|
||||
the string in the same format
|
||||
"""
|
||||
|
||||
def __init__(self, obj):
|
||||
self._data = jsonutils.dumps(
|
||||
obj,
|
||||
indent=4,
|
||||
sort_keys=True
|
||||
)
|
||||
|
||||
def __eq__(self, obj):
|
||||
return (self._data == obj)
|
||||
|
||||
|
||||
class OdlManagerTestCase(unittest.TestCase):
|
||||
""" Test case for ODL manager testing
|
||||
|
||||
Set up the testing environment
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
config.cfg.CONF.set_override('odl_username',
|
||||
USERNAME,
|
||||
group='odl_driver')
|
||||
config.cfg.CONF.set_override('odl_password',
|
||||
PASSWORD,
|
||||
group='odl_driver')
|
||||
config.cfg.CONF.set_override('odl_host',
|
||||
HOST,
|
||||
group='odl_driver')
|
||||
config.cfg.CONF.set_override('odl_port',
|
||||
PORT,
|
||||
group='odl_driver')
|
||||
|
||||
self.manager = odl_manager.OdlManager()
|
||||
|
||||
# test a single HTTP request
|
||||
def _test_single_request_operation(
|
||||
self,
|
||||
http_method,
|
||||
tested_method,
|
||||
*args,
|
||||
**kwargs
|
||||
):
|
||||
with mock.patch('requests.request') as mock_request:
|
||||
tested_method(*args)
|
||||
mock_request.assert_called_once_with(
|
||||
http_method,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
# In some ODL manager operations, ODL manager needs to check if a tenant
|
||||
# is existing or not, if not, the ODL manager needs to create the tenant
|
||||
# first -- such a scenario needs to be tested with this method
|
||||
def _test_multi_request_operations(
|
||||
self,
|
||||
http_method,
|
||||
tested_method,
|
||||
*args,
|
||||
**kwargs
|
||||
):
|
||||
with mock.patch.object(odl_manager.OdlManager,
|
||||
'_is_tenant_created') as mock_is_tenant_created:
|
||||
with mock.patch('requests.request') as mock_request:
|
||||
mock_is_tenant_created.return_value = True
|
||||
tested_method(*args)
|
||||
mock_request.assert_called_once_with(
|
||||
http_method,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
mock_is_tenant_created.return_value = False
|
||||
mock_request.reset_mock()
|
||||
tested_method(*args)
|
||||
mock_request.assert_any_call(
|
||||
'put',
|
||||
url=URL_TENANT,
|
||||
headers=HEADER,
|
||||
data=DataMatcher({'tenant': {'id': TENANT_ID}}),
|
||||
auth=AuthMatcher()
|
||||
)
|
||||
mock_request.assert_any_call(
|
||||
http_method,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
@mock.patch.object(requests, 'request')
|
||||
def test_is_tenant_created(self, mock_request):
|
||||
|
||||
mock_request.return_value = mock.Mock(
|
||||
status_code=200
|
||||
)
|
||||
assert self.manager._is_tenant_created(TENANT_ID)
|
||||
mock_request.assert_called_once_with(
|
||||
'get',
|
||||
url=URL_TENANT,
|
||||
headers=HEADER,
|
||||
auth=AuthMatcher()
|
||||
)
|
||||
|
||||
mock_request.reset_mock()
|
||||
mock_request.return_value = mock.Mock(
|
||||
status_code=404
|
||||
)
|
||||
assert not self.manager._is_tenant_created(TENANT_ID)
|
||||
mock_request.assert_called_once_with(
|
||||
'get',
|
||||
url=URL_TENANT,
|
||||
headers=HEADER,
|
||||
auth=AuthMatcher()
|
||||
)
|
||||
|
||||
def test_register_endpoints(self):
|
||||
method = getattr(self.manager, 'register_endpoints')
|
||||
self._test_single_request_operation(
|
||||
'post',
|
||||
method,
|
||||
[ENDPOINT],
|
||||
url=URL_REG_EP,
|
||||
headers=HEADER,
|
||||
data=DataMatcher({'input': ENDPOINT}),
|
||||
auth=AuthMatcher()
|
||||
)
|
||||
|
||||
def test_unregister_endpoints(self):
|
||||
method = getattr(self.manager, 'unregister_endpoints')
|
||||
self._test_single_request_operation(
|
||||
'post',
|
||||
method,
|
||||
[ENDPOINT],
|
||||
url=URL_UNREG_EP,
|
||||
headers=HEADER,
|
||||
data=DataMatcher({'input': ENDPOINT}),
|
||||
auth=AuthMatcher()
|
||||
)
|
||||
|
||||
def test_create_update_tenant(self):
|
||||
method = getattr(self.manager, 'create_update_tenant')
|
||||
self._test_single_request_operation(
|
||||
'put',
|
||||
method,
|
||||
TENANT_ID,
|
||||
TENANT,
|
||||
url=URL_TENANT,
|
||||
headers=HEADER,
|
||||
data=DataMatcher({'tenant': TENANT}),
|
||||
auth=AuthMatcher()
|
||||
)
|
||||
|
||||
def test_create_action(self):
|
||||
method = getattr(self.manager, 'create_action')
|
||||
self._test_multi_request_operations(
|
||||
'put',
|
||||
method,
|
||||
TENANT_ID,
|
||||
ACTION,
|
||||
url=URL_ACTION,
|
||||
headers=HEADER,
|
||||
data=DataMatcher({'action-instance': ACTION}),
|
||||
auth=AuthMatcher()
|
||||
)
|
||||
|
||||
def test_delete_action(self):
|
||||
method = getattr(self.manager, 'delete_action')
|
||||
self._test_single_request_operation(
|
||||
'delete',
|
||||
method,
|
||||
TENANT_ID,
|
||||
ACTION,
|
||||
url=URL_ACTION,
|
||||
headers=HEADER,
|
||||
data=None,
|
||||
auth=AuthMatcher()
|
||||
)
|
||||
|
||||
def test_create_classifier(self):
|
||||
method = getattr(self.manager, 'create_classifier')
|
||||
self._test_multi_request_operations(
|
||||
'put',
|
||||
method,
|
||||
TENANT_ID,
|
||||
CLASSIFIER,
|
||||
url=URL_CLASSIFIER,
|
||||
headers=HEADER,
|
||||
data=DataMatcher({'classifier-instance': CLASSIFIER}),
|
||||
auth=AuthMatcher()
|
||||
)
|
||||
|
||||
def test_delete_classifier(self):
|
||||
method = getattr(self.manager, 'delete_classifier')
|
||||
self._test_single_request_operation(
|
||||
'delete',
|
||||
method,
|
||||
TENANT_ID,
|
||||
CLASSIFIER,
|
||||
url=URL_CLASSIFIER,
|
||||
headers=HEADER,
|
||||
data=None,
|
||||
auth=AuthMatcher()
|
||||
)
|
||||
|
||||
def test_create_update_l3_context(self):
|
||||
method = getattr(self.manager, 'create_update_l3_context')
|
||||
self._test_multi_request_operations(
|
||||
'put',
|
||||
method,
|
||||
TENANT_ID,
|
||||
L3CTX,
|
||||
url=URL_L3CTX,
|
||||
headers=HEADER,
|
||||
data=DataMatcher({'l3-context': L3CTX}),
|
||||
auth=AuthMatcher()
|
||||
)
|
||||
|
||||
def test_delete_l3_context(self):
|
||||
method = getattr(self.manager, 'delete_l3_context')
|
||||
self._test_single_request_operation(
|
||||
'delete',
|
||||
method,
|
||||
TENANT_ID,
|
||||
L3CTX,
|
||||
url=URL_L3CTX,
|
||||
headers=HEADER,
|
||||
data=None,
|
||||
auth=AuthMatcher()
|
||||
)
|
||||
|
||||
def test_create_update_l2_bridge_domain(self):
|
||||
method = getattr(self.manager, 'create_update_l2_bridge_domain')
|
||||
self._test_multi_request_operations(
|
||||
'put',
|
||||
method,
|
||||
TENANT_ID,
|
||||
L2BD,
|
||||
url=URL_L2BD,
|
||||
headers=HEADER,
|
||||
data=DataMatcher({'l2-bridge-domain': L2BD}),
|
||||
auth=AuthMatcher()
|
||||
)
|
||||
|
||||
def test_delete_l2_bridge_domain(self):
|
||||
method = getattr(self.manager, 'delete_l2_bridge_domain')
|
||||
self._test_single_request_operation(
|
||||
'delete',
|
||||
method,
|
||||
TENANT_ID,
|
||||
L2BD,
|
||||
url=URL_L2BD,
|
||||
headers=HEADER,
|
||||
data=None,
|
||||
auth=AuthMatcher()
|
||||
)
|
||||
|
||||
def test_create_update_l2_flood_domain(self):
|
||||
method = getattr(self.manager, 'create_update_l2_flood_domain')
|
||||
self._test_multi_request_operations(
|
||||
'put',
|
||||
method,
|
||||
TENANT_ID,
|
||||
L2FD,
|
||||
url=URL_L2FD,
|
||||
headers=HEADER,
|
||||
data=DataMatcher({'l2-flood-domain': L2FD}),
|
||||
auth=AuthMatcher()
|
||||
)
|
||||
|
||||
def test_delete_l2_flood_domain(self):
|
||||
method = getattr(self.manager, 'delete_l2_flood_domain')
|
||||
self._test_single_request_operation(
|
||||
'delete',
|
||||
method,
|
||||
TENANT_ID,
|
||||
L2FD,
|
||||
url=URL_L2FD,
|
||||
headers=HEADER,
|
||||
data=None,
|
||||
auth=AuthMatcher()
|
||||
)
|
||||
|
||||
def test_create_update_endpoint_group(self):
|
||||
method = getattr(self.manager, 'create_update_endpoint_group')
|
||||
self._test_multi_request_operations(
|
||||
'put',
|
||||
method,
|
||||
TENANT_ID,
|
||||
EPG,
|
||||
url=URL_EPG,
|
||||
headers=HEADER,
|
||||
data=DataMatcher({'endpoint-group': EPG}),
|
||||
auth=AuthMatcher()
|
||||
)
|
||||
|
||||
def test_delete_endpoint_group(self):
|
||||
method = getattr(self.manager, 'delete_endpoint_group')
|
||||
self._test_single_request_operation(
|
||||
'delete',
|
||||
method,
|
||||
TENANT_ID,
|
||||
EPG,
|
||||
url=URL_EPG,
|
||||
headers=HEADER,
|
||||
data=None,
|
||||
auth=AuthMatcher()
|
||||
)
|
||||
|
||||
def test_create_update_subnet(self):
|
||||
method = getattr(self.manager, 'create_update_subnet')
|
||||
self._test_multi_request_operations(
|
||||
'put',
|
||||
method,
|
||||
TENANT_ID,
|
||||
SUBNET,
|
||||
url=URL_SUBNET,
|
||||
headers=HEADER,
|
||||
data=DataMatcher({'subnet': SUBNET}),
|
||||
auth=AuthMatcher()
|
||||
)
|
||||
|
||||
def test_delete_subnet(self):
|
||||
method = getattr(self.manager, 'delete_subnet')
|
||||
self._test_single_request_operation(
|
||||
'delete',
|
||||
method,
|
||||
TENANT_ID,
|
||||
SUBNET,
|
||||
url=URL_SUBNET,
|
||||
headers=HEADER,
|
||||
data=None,
|
||||
auth=AuthMatcher()
|
||||
)
|
||||
|
||||
def test_create_update_contract(self):
|
||||
method = getattr(self.manager, 'create_update_contract')
|
||||
self._test_single_request_operation(
|
||||
'put',
|
||||
method,
|
||||
TENANT_ID,
|
||||
CONTRACT,
|
||||
url=URL_CONTRACT,
|
||||
headers=HEADER,
|
||||
data=DataMatcher({'contract': CONTRACT}),
|
||||
auth=AuthMatcher()
|
||||
)
|
File diff suppressed because it is too large
Load Diff
|
@ -68,15 +68,10 @@ gbpservice.neutron.group_policy.policy_drivers =
|
|||
chain_mapping = gbpservice.neutron.services.grouppolicy.drivers.chain_mapping:ChainMappingDriver
|
||||
aim_mapping = gbpservice.neutron.services.grouppolicy.drivers.cisco.apic.aim_mapping:AIMMappingDriver
|
||||
apic = gbpservice.neutron.services.grouppolicy.drivers.cisco.apic.apic_mapping:ApicMappingDriver
|
||||
odl = gbpservice.neutron.services.grouppolicy.drivers.odl.odl_mapping:OdlMappingDriver
|
||||
oneconvergence_gbp_driver = gbpservice.neutron.services.grouppolicy.drivers.oneconvergence.nvsd_gbp_driver:NvsdGbpDriver
|
||||
nuage_gbp_driver = gbpservice.neutron.services.grouppolicy.drivers.nuage.driver:NuageGBPDriver
|
||||
neutron.ml2.mechanism_drivers =
|
||||
logger_plus = gbpservice.neutron.tests.unit.plugins.ml2plus.drivers.mechanism_logger:LoggerPlusMechanismDriver
|
||||
apic_aim = gbpservice.neutron.plugins.ml2plus.drivers.apic_aim.mechanism_driver:ApicMechanismDriver
|
||||
apic_gbp = gbpservice.neutron.plugins.ml2.drivers.grouppolicy.apic.driver:APICMechanismGBPDriver
|
||||
nuage_gbp = gbpservice.neutron.plugins.ml2.drivers.grouppolicy.nuage.driver:NuageMechanismGBPDriver
|
||||
odl_gbp = gbpservice.neutron.plugins.ml2.drivers.grouppolicy.odl.driver:OdlMechanismGBPDriver
|
||||
stitching_gbp = gbpservice.neutron.plugins.ml2.drivers.grouppolicy.stitching.driver:TrafficStitchingMechanismGBPDriver
|
||||
neutron.ml2.extension_drivers =
|
||||
apic_aim = gbpservice.neutron.plugins.ml2plus.drivers.apic_aim.extension_driver:ApicExtensionDriver
|
||||
|
@ -85,7 +80,6 @@ neutron.ml2.extension_drivers =
|
|||
gbpservice.neutron.servicechain.servicechain_drivers =
|
||||
dummy = gbpservice.neutron.services.servicechain.plugins.msc.drivers.dummy_driver:NoopDriver
|
||||
simplechain_driver = gbpservice.neutron.services.servicechain.plugins.msc.drivers.simplechain_driver:SimpleChainDriver
|
||||
oneconvergence_servicechain_driver = gbpservice.neutron.services.servicechain.plugins.msc.drivers.oneconvergence_servicechain_driver:OneconvergenceServiceChainDriver
|
||||
gbpservice.neutron.servicechain.ncp_drivers =
|
||||
node_dummy = gbpservice.neutron.services.servicechain.plugins.ncp.node_drivers.dummy_driver:NoopNodeDriver
|
||||
heat_node_driver = gbpservice.neutron.services.servicechain.plugins.ncp.node_drivers.heat_node_driver:HeatNodeDriver
|
||||
|
|
Loading…
Reference in New Issue