Decompose the NCS ML2 Mechanism Driver

The last of the Cisco drivers to decompose.

Closes-bug: #1416713
Co-Authored-By: Nikolay Fedotov <nfedotov@cisco.com>

Change-Id: Icd2b358fb0db3d859ee287225ab8eeb10d7da871
This commit is contained in:
Henry Gessau 2015-06-01 14:36:17 -04:00
parent fca57ab604
commit 9cac5c3a9f
7 changed files with 18 additions and 251 deletions

View File

@ -402,14 +402,3 @@ will be removed. The following aspects are captured:
+===============================+=======================+===========+==================+=========+==============+
| freescale-nscs | ml2,fw | no | no | [D] | |
+-------------------------------+-----------------------+-----------+------------------+---------+--------------+
| networking-cisco_ | core,ml2,l3,fw,vpn | yes | yes | [B] | |
+-------------------------------+-----------------------+-----------+------------------+---------+--------------+
.. _networking-cisco:
Cisco
-----
* Git: https://git.openstack.org/stackforge/networking-cisco
* Launchpad: https://launchpad.net/networking-cisco
* PyPI: https://pypi.python.org/pypi/networking-cisco

View File

@ -92,6 +92,8 @@ capabilities of Neutron, the Neutron API, or a combination of both.
+-------------------------------+-----------------------+
| networking-brocade_ | ml2,l3 |
+-------------------------------+-----------------------+
| networking-cisco_ | core,ml2,l3,fw,vpn |
+-------------------------------+-----------------------+
| networking-edge-vpn_ | vpn |
+-------------------------------+-----------------------+
| networking-hyperv_ | ml2 |
@ -185,6 +187,17 @@ Brocade
* Launchpad: https://launchpad.net/networking-brocade
* PyPI: https://pypi.python.org/pypi/networking-brocade
.. _networking-cisco:
Cisco
-----
* Git: https://github.com/stackforge/networking-cisco
* Launchpad: https://launchpad.net/networking-cisco
* PyPI: https://pypi.python.org/pypi/networking-cisco
.. _dragonflow:
DragonFlow
----------

View File

@ -1,28 +0,0 @@
# Defines configuration options specific to the Tail-f NCS Mechanism Driver
[ml2_ncs]
# (StrOpt) Tail-f NCS HTTP endpoint for REST access to the OpenStack
# subtree.
# If this is not set then no HTTP requests will be made.
#
# url =
# Example: url = http://ncs/api/running/services/openstack
# (StrOpt) Username for HTTP basic authentication to NCS.
# This is an optional parameter. If unspecified then no authentication is used.
#
# username =
# Example: username = admin
# (StrOpt) Password for HTTP basic authentication to NCS.
# This is an optional parameter. If unspecified then no authentication is used.
#
# password =
# Example: password = admin
# (IntOpt) Timeout in seconds to wait for NCS HTTP request completion.
# This is an optional parameter, default value is 10 seconds.
#
# timeout =
# Example: timeout = 15

View File

@ -13,171 +13,10 @@
# License for the specific language governing permissions and limitations
# under the License.
import re
"""
ML2 Mechanism Driver for Cisco NCS.
"""
from oslo_config import cfg
from oslo_log import log
from oslo_serialization import jsonutils
import requests
import six
from networking_cisco.plugins.ml2.drivers.cisco.ncs import driver as cisco
from neutron.plugins.ml2 import driver_api as api
LOG = log.getLogger(__name__)
ncs_opts = [
cfg.StrOpt('url',
help=_("HTTP URL of Tail-f NCS REST interface.")),
cfg.StrOpt('username',
help=_("HTTP username for authentication")),
cfg.StrOpt('password', secret=True,
help=_("HTTP password for authentication")),
cfg.IntOpt('timeout', default=10,
help=_("HTTP timeout in seconds."))
]
cfg.CONF.register_opts(ncs_opts, "ml2_ncs")
class NCSMechanismDriver(api.MechanismDriver):
"""Mechanism Driver for Tail-f Network Control System (NCS).
This driver makes portions of the Neutron database available for
service provisioning in NCS. For example, NCS can use this
information to provision physical switches and routers in response
to OpenStack configuration changes.
The database is replicated from Neutron to NCS using HTTP and JSON.
The driver has two states: out-of-sync (initially) and in-sync.
In the out-of-sync state each driver event triggers an attempt
to synchronize the complete database. On success the driver
transitions to the in-sync state.
In the in-sync state each driver event triggers synchronization
of one network or port. On success the driver stays in-sync and
on failure it transitions to the out-of-sync state.
"""
out_of_sync = True
def initialize(self):
self.url = cfg.CONF.ml2_ncs.url
self.timeout = cfg.CONF.ml2_ncs.timeout
self.username = cfg.CONF.ml2_ncs.username
self.password = cfg.CONF.ml2_ncs.password
# Postcommit hooks are used to trigger synchronization.
def create_network_postcommit(self, context):
self.synchronize('create', 'network', context)
def update_network_postcommit(self, context):
self.synchronize('update', 'network', context)
def delete_network_postcommit(self, context):
self.synchronize('delete', 'network', context)
def create_subnet_postcommit(self, context):
self.synchronize('create', 'subnet', context)
def update_subnet_postcommit(self, context):
self.synchronize('update', 'subnet', context)
def delete_subnet_postcommit(self, context):
self.synchronize('delete', 'subnet', context)
def create_port_postcommit(self, context):
self.synchronize('create', 'port', context)
def update_port_postcommit(self, context):
self.synchronize('update', 'port', context)
def delete_port_postcommit(self, context):
self.synchronize('delete', 'port', context)
def synchronize(self, operation, object_type, context):
"""Synchronize NCS with Neutron following a configuration change."""
if self.out_of_sync:
self.sync_full(context)
else:
self.sync_object(operation, object_type, context)
def sync_full(self, context):
"""Resync the entire database to NCS.
Transition to the in-sync state on success.
"""
dbcontext = context._plugin_context
networks = context._plugin.get_networks(dbcontext)
subnets = context._plugin.get_subnets(dbcontext)
ports = context._plugin.get_ports(dbcontext)
for port in ports:
self.add_security_groups(context, dbcontext, port)
json = {'openstack': {'network': networks,
'subnet': subnets,
'port': ports}}
self.sendjson('put', '', json)
self.out_of_sync = False
def sync_object(self, operation, object_type, context):
"""Synchronize the single modified record to NCS.
Transition to the out-of-sync state on failure.
"""
self.out_of_sync = True
dbcontext = context._plugin_context
id = context.current['id']
urlpath = object_type + '/' + id
if operation == 'delete':
self.sendjson('delete', urlpath, None)
else:
assert operation == 'create' or operation == 'update'
if object_type == 'network':
network = context._plugin.get_network(dbcontext, id)
self.sendjson('put', urlpath, {'network': network})
elif object_type == 'subnet':
subnet = context._plugin.get_subnet(dbcontext, id)
self.sendjson('put', urlpath, {'subnet': subnet})
else:
assert object_type == 'port'
port = context._plugin.get_port(dbcontext, id)
self.add_security_groups(context, dbcontext, port)
self.sendjson('put', urlpath, {'port': port})
self.out_of_sync = False
def add_security_groups(self, context, dbcontext, port):
"""Populate the 'security_groups' field with entire records."""
groups = [context._plugin.get_security_group(dbcontext, sg)
for sg in port['security_groups']]
port['security_groups'] = groups
def sendjson(self, method, urlpath, obj):
obj = self.escape_keys(obj)
headers = {'Content-Type': 'application/vnd.yang.data+json'}
if obj is None:
data = None
else:
data = jsonutils.dumps(obj, indent=2)
auth = None
if self.username and self.password:
auth = (self.username, self.password)
if self.url:
url = '/'.join([self.url, urlpath])
r = requests.request(method, url=url,
headers=headers, data=data,
auth=auth, timeout=self.timeout)
r.raise_for_status()
def escape_keys(self, obj):
"""Escape JSON keys to be NCS compatible.
NCS does not allow period (.) or colon (:) characters.
"""
if isinstance(obj, dict):
obj = dict((self.escape(k), self.escape_keys(v))
for k, v in six.iteritems(obj))
if isinstance(obj, list):
obj = [self.escape_keys(x) for x in obj]
return obj
def escape(self, string):
return re.sub('[:._]', '-', string)
NCSMechanismDriver = cisco.NCSMechanismDriver

View File

@ -1,45 +0,0 @@
# Copyright (c) 2013 OpenStack Foundation
# 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.plugins.ml2.drivers.cisco.ncs import driver
from neutron.tests.unit.plugins.ml2 import test_plugin
class NCSTestCase(test_plugin.Ml2PluginV2TestCase):
_mechanism_drivers = ['logger', 'ncs']
def setUp(self):
# Enable the test mechanism driver to ensure that
# we can successfully call through to all mechanism
# driver apis.
super(NCSTestCase, self).setUp()
self.port_create_status = 'DOWN'
driver.NCSMechanismDriver.sendjson = self.check_sendjson
def check_sendjson(self, method, urlpath, obj):
# Confirm fix for bug #1224981
self.assertFalse(urlpath.startswith("http://"))
class NCSMechanismTestBasicGet(test_plugin.TestMl2BasicGet, NCSTestCase):
pass
class NCSMechanismTestNetworksV2(test_plugin.TestMl2NetworksV2, NCSTestCase):
pass
class NCSMechanismTestPortsV2(test_plugin.TestMl2PortsV2, NCSTestCase):
pass

View File

@ -68,7 +68,6 @@ data_files =
etc/neutron/plugins/ml2/ml2_conf_brocade.ini
etc/neutron/plugins/ml2/ml2_conf_brocade_fi_ni.ini
etc/neutron/plugins/ml2/ml2_conf_cisco.ini
etc/neutron/plugins/ml2/ml2_conf_ncs.ini
etc/neutron/plugins/ml2/ml2_conf_ofa.ini
etc/neutron/plugins/ml2/ml2_conf_fslsdn.ini
etc/neutron/plugins/ml2/ml2_conf_sriov.ini