aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos
diff options
context:
space:
mode:
authorAshlee Young <ashlee@onosfw.com>2015-10-30 09:20:45 -0700
committerAshlee Young <ashlee@onosfw.com>2015-10-30 09:20:45 -0700
commit89a574196783f93e32d81244f37f726be11bbf30 (patch)
tree408c721579d29d49eebf50c78b7f4a8da7a6489e /framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos
parent62bb467ca10e4fd0ca23499953bc7f7f413dee16 (diff)
New ML2/L3 plugin to support SFC
Change-Id: Ie778a2b2e09a29972e28d70c8eedee407b1d8eb6 Signed-off-by: Ashlee Young <ashlee@onosfw.com>
Diffstat (limited to 'framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos')
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/__init__.py19
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/common/__init__.py0
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/common/config.py31
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/common/utils.py44
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/__init__.py0
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/README29
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/__init__.py0
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/driver.py126
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/floating_ip.py40
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/router.py74
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/ml2/README33
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/ml2/__init__.py0
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/ml2/driver.py140
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/__init__.py0
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/__init__.py0
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/__init__.py0
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/l3/__init__.py0
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/l3/test_driver.py230
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/ml2/__init__.py0
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/ml2/test_driver.py237
20 files changed, 1003 insertions, 0 deletions
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/__init__.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/__init__.py
new file mode 100644
index 00000000..d0b36107
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/__init__.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+
+# 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 pbr.version
+
+
+__version__ = pbr.version.VersionInfo(
+ 'networking-onos').version_string()
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/common/__init__.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/common/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/common/__init__.py
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/common/config.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/common/config.py
new file mode 100644
index 00000000..8dc72286
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/common/config.py
@@ -0,0 +1,31 @@
+# Copyright (c) 2015 Huawei Technologies India Pvt Ltd
+# 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 oslo_config import cfg
+
+ONOS_DRIVER_OPTS = [
+ cfg.StrOpt('url_path',
+ default='',
+ help=_('ONOS ReST interface URL')),
+ cfg.StrOpt('username',
+ default='',
+ help=_('Username for authentication.')),
+ cfg.StrOpt('password',
+ default='',
+ secret=True, # do not expose value in the logs
+ help=_('Password for authentication.'))
+]
+
+cfg.CONF.register_opts(ONOS_DRIVER_OPTS, "onos")
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/common/utils.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/common/utils.py
new file mode 100644
index 00000000..49477149
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/common/utils.py
@@ -0,0 +1,44 @@
+# Copyright (c) 2015 Huawei Technologies India Pvt Ltd
+# 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 oslo_log import log as logging
+from oslo_serialization import jsonutils
+import requests
+
+
+LOG = logging.getLogger(__name__)
+
+
+def send_msg(onos_path, onos_auth, msg_type, entity_path, entity=None):
+ """Send message to the ONOS controller."""
+
+ path = '/'.join([onos_path, entity_path])
+ hdr = {'Content-Type': 'application/json'}
+ body = jsonutils.dumps(entity, indent=2) if entity else None
+ LOG.debug("Sending MSG_TYPE (%(msg)s) URL (%(path)s) "
+ "OBJECT (%(entity)s) BODY (%(body)s)",
+ {'msg': msg_type, 'path': path,
+ 'entity': entity, 'body': body})
+ req = requests.request(method=msg_type, url=path,
+ headers=hdr, data=body,
+ auth=onos_auth)
+ # Let's raise voice for an error
+ req.raise_for_status()
+
+
+def safe_delete_from_dict(dict, keys):
+ """Ignore key errors when deleting from a dictionary."""
+ for key in keys:
+ dict.pop(key, None)
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/__init__.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/__init__.py
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/README b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/README
new file mode 100644
index 00000000..04ca224b
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/README
@@ -0,0 +1,29 @@
+Open Networking Operating System (ONOS) L3 Plugin
+=================================================
+ONOS is a carrier grade SDN open operating system designed for
+High Availability, scale-out and better performance.
+
+ http://www.onosproject.org/
+
+Mode of Working:
+================
+networking-onos.plugins.l3 define onos plug-in for supporting neutron's router
+functionality. This shim layer makes the communication between ONOS and
+Openstack neutron possible via ReST call.
+The driver code can be downloaded from:
+
+ https://git.openstack.org/cgit/openstack/networking-onos
+
+Using ONOS L3 Plugin
+====================
+To use ONOS L3 Plugin one should
+1. Make sure networking-onos code is downloaded and installed. If doing
+ mannually then download the code, go inside networking_onos folder
+ and finally run "sudo python setup.py install" otherwise download the
+ required package version from "https://pypi.python.org/pypi/networking-onos/"
+ and install using pip.
+
+2. Configure ONOS credentials in networking_onos/etc/conf_onos.ini.
+
+3. Start neutron server mentioning networking_onos/etc/conf_onos.ini as
+ one of the config-file with ONOS L3 Plugin support.
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/__init__.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/__init__.py
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/driver.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/driver.py
new file mode 100644
index 00000000..2db3ad35
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/driver.py
@@ -0,0 +1,126 @@
+# Copyright (C) 2015 Huawei Technologies India Pvt Ltd.
+# 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 oslo_config import cfg
+
+from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api
+from neutron.api.rpc.handlers import l3_rpc
+from neutron.common import constants as q_const
+from neutron.common import rpc as n_rpc
+from neutron.common import topics
+from neutron.db import db_base_plugin_v2
+from neutron.db import extraroute_db
+from neutron.db import l3_agentschedulers_db
+from neutron.db import l3_gwmode_db
+from neutron.plugins.common import constants
+
+from networking_onos.common import config # noqa
+from networking_onos.plugins.l3 import floating_ip as onos_fip
+from networking_onos.plugins.l3 import router as onos_router
+
+
+class ONOSL3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
+ extraroute_db.ExtraRoute_db_mixin,
+ l3_gwmode_db.L3_NAT_db_mixin,
+ l3_agentschedulers_db.L3AgentSchedulerDbMixin,
+ onos_router.ONOSRouter,
+ onos_fip.ONOSFloatingIP):
+
+ """Implementation of the ONOS L3 Router Service Plugin.
+
+ This class implements a L3 service plugin that provides
+ router and floatingip resources and manages associated
+ request/response.
+ """
+ supported_extension_aliases = ["router", "ext-gw-mode", "extraroute"]
+
+ def __init__(self):
+ self.setup_rpc()
+ self.onos_path = cfg.CONF.onos.url_path
+ self.onos_auth = (cfg.CONF.onos.username, cfg.CONF.onos.password)
+
+ def setup_rpc(self):
+ self.topic = topics.L3PLUGIN
+ self.conn = n_rpc.create_connection(new=True)
+ self.agent_notifiers.update(
+ {q_const.AGENT_TYPE_L3: l3_rpc_agent_api.L3AgentNotifyAPI()})
+ self.endpoints = [l3_rpc.L3RpcCallback()]
+ self.conn.create_consumer(self.topic, self.endpoints, fanout=False)
+ self.conn.consume_in_threads()
+
+ def get_plugin_type(self):
+ return constants.L3_ROUTER_NAT
+
+ def get_plugin_description(self):
+ """returns plug-in description"""
+ return ("L3 Router Service Plug-in for basic L3 forwarding using ONOS")
+
+ def create_router(self, context, router):
+ router_dict = super(ONOSL3Plugin, self).create_router(context, router)
+ self.handle_create_router(router_dict)
+ return router_dict
+
+ def update_router(self, context, id, router):
+ router_dict = super(ONOSL3Plugin, self).update_router(context, id,
+ router)
+ self.handle_update_router(router_dict, id)
+ return router_dict
+
+ def delete_router(self, context, id):
+ super(ONOSL3Plugin, self).delete_router(context, id)
+ self.handle_delete_router(id)
+
+ def create_floatingip(self, context, floatingip,
+ initial_status=q_const.FLOATINGIP_STATUS_ACTIVE):
+ fip_dict = super(ONOSL3Plugin, self).create_floatingip(context,
+ floatingip,
+ initial_status)
+ self.handle_create_floatingip(fip_dict)
+ return fip_dict
+
+ def update_floatingip(self, context, id, floatingip):
+ fip_dict = super(ONOSL3Plugin, self).update_floatingip(context, id,
+ floatingip)
+ self.handle_update_floatingip(id, fip_dict)
+ return fip_dict
+
+ def delete_floatingip(self, context, id):
+ super(ONOSL3Plugin, self).delete_floatingip(context, id)
+ self.handle_delete_floatingip(id)
+
+ def add_router_interface(self, context, router_id, interface_info):
+ router = super(ONOSL3Plugin, self).add_router_interface(context,
+ router_id,
+ interface_info)
+ intf_add_type = self._get_intf_add_type(router, interface_info)
+ self.handle_add_router_interface(router, router_id,
+ interface_info, intf_add_type)
+ return router
+
+ def remove_router_interface(self, context, router_id, interface_info):
+ router = super(ONOSL3Plugin, self).remove_router_interface(
+ context, router_id, interface_info)
+ intf_add_type = self._get_intf_add_type(router, interface_info)
+ self.handle_remove_router_interface(router, router_id,
+ interface_info, intf_add_type)
+ return router
+
+ def _get_intf_add_type(self, router_info, intf_info):
+ add_by_port, add_by_sub = self._validate_interface_info(intf_info)
+ if add_by_sub:
+ return onos_router.ADD_INTF_BY_SUBNET
+
+ return onos_router.ADD_INTF_BY_PORT
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/floating_ip.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/floating_ip.py
new file mode 100644
index 00000000..0748724e
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/floating_ip.py
@@ -0,0 +1,40 @@
+# Copyright (C) 2015 Huawei Technologies India Pvt Ltd.
+#
+# 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 networking_onos.common import utils as onos_utils
+
+
+class ONOSFloatingIP(object):
+
+ """Implementation of ONOS L3 Floating IP Service.
+
+ This class sends Neutron's L3 Floating IP messages to ONOS.
+ """
+ def send_floatingip_msg(self, msg_type, entity_path, entity):
+ onos_utils.send_msg(self.onos_path, self.onos_auth,
+ msg_type, entity_path, entity)
+
+ def handle_create_floatingip(self, fip_dict):
+ self.send_floatingip_msg('post', 'floatingips',
+ {'floatingip': fip_dict})
+
+ def handle_update_floatingip(self, id, fip_dict):
+ url_path = 'floatingips' + '/' + id
+ self.send_floatingip_msg('put', url_path,
+ {'floatingip': fip_dict})
+
+ def handle_delete_floatingip(self, id):
+ url_path = 'floatingips' + '/' + id
+ self.send_floatingip_msg('delete', url_path, None)
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/router.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/router.py
new file mode 100644
index 00000000..495dacd6
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/router.py
@@ -0,0 +1,74 @@
+# Copyright (C) 2015 Huawei Technologies India Pvt Ltd.
+#
+# 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 networking_onos.common import utils as onos_utils
+
+ADD_INTF_BY_PORT = 1
+ADD_INTF_BY_SUBNET = 2
+
+
+class ONOSRouter(object):
+
+ """Implementation of ONOS L3 Router Service.
+
+ This class sends Neutron's L3 router messages to ONOS.
+ """
+ def send_router_msg(self, msg_type, entity_path, entity):
+ onos_utils.send_msg(self.onos_path, self.onos_auth,
+ msg_type, entity_path, entity)
+
+ def handle_create_router(self, router_dict):
+ self.send_router_msg('post', 'routers',
+ {'router': router_dict})
+
+ def handle_update_router(self, router_dict, id):
+ url_path = 'routers' + '/' + id
+ resource = router_dict.copy()
+ onos_utils.safe_delete_from_dict(resource,
+ ['id', 'tenant_id', 'status'])
+ self.send_router_msg('put', url_path, {'router': resource})
+
+ def handle_delete_router(self, id):
+ url_path = 'routers' + '/' + id
+ self.send_router_msg('delete', url_path, None)
+
+ def handle_add_router_interface(self, new_router, router_id,
+ interface_info, intf_add_type):
+ url_path = 'routers' + '/' + router_id + '/add_router_interface'
+ router_dict = self._prepare_router_dict(router_id, interface_info,
+ new_router, intf_add_type)
+ self.send_router_msg('put', url_path, router_dict)
+
+ def handle_remove_router_interface(self, new_router, router_id,
+ interface_info, intf_add_type):
+ url_path = 'routers' + '/' + router_id + '/remove_router_interface'
+ router_dict = self._prepare_router_dict(router_id, interface_info,
+ new_router, intf_add_type)
+ self.send_router_msg('put', url_path, router_dict)
+
+ def _prepare_router_dict(self, router_id, interface_info,
+ new_router, add_type):
+ if add_type == ADD_INTF_BY_SUBNET:
+ _port_id = new_router['port_id']
+ _subnet_id = interface_info['subnet_id']
+ else:
+ _port_id = interface_info['port_id']
+ _subnet_id = new_router['subnet_id']
+
+ router_dict = {'subnet_id': _subnet_id,
+ 'port_id': _port_id,
+ 'id': router_id,
+ 'tenant_id': new_router['tenant_id']}
+ return router_dict
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/ml2/README b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/ml2/README
new file mode 100644
index 00000000..c3c722c8
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/ml2/README
@@ -0,0 +1,33 @@
+Open Networking Operating System (ONOS) ML2 MechanismDriver
+==========================================================
+ONOS is a carrier grade SDN open operating system designed for
+High Availability, scale-out and better performance.
+
+ http://www.onosproject.org/
+
+Mode of Working:
+================
+The networking-onos project provides a thin layer which makes the
+communication between ONOS and OpenStack neutron possible via ReST
+call. The driver code can be downloaded from:
+
+ https://git.openstack.org/cgit/openstack/networking-onos
+
+Using ONOS ML2 MechanismDriver
+==============================
+To use ONOS ML2 MechanismDriver one should
+1. Make sure networking-onos code is downloaded and installed. If doing
+ mannually then download the code, go inside networking_onos folder
+ and finally run "sudo python setup.py install" otherwise download the
+ required package version from "https://pypi.python.org/pypi/networking-onos/"
+ and install using pip.
+
+2. Configure ONOS as the required ML2 "mechanism_drivers" in
+ neutron/plugins/ml2/ml2_conf.ini:
+
+ mechanism_drivers=onos_ml2
+
+3. Configure ONOS credentials in networking_onos/etc/conf_onos.ini.
+
+4. Start neutron server mentioning networking_onos/etc/conf_onos.ini as
+ one of the config-file.
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/ml2/__init__.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/ml2/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/ml2/__init__.py
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/ml2/driver.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/ml2/driver.py
new file mode 100644
index 00000000..b78775f4
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/ml2/driver.py
@@ -0,0 +1,140 @@
+# Copyright (c) 2015 Huawei Technologies India Pvt Ltd
+# 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 oslo_config import cfg
+from oslo_log import helpers as log_helpers
+from oslo_log import log as logging
+
+from neutron.common import constants as n_const
+from neutron.extensions import portbindings
+from neutron.plugins.common import constants
+from neutron.plugins.ml2 import driver_api as api
+
+from networking_onos.common import config # noqa
+from networking_onos.common import utils as onos_utils
+
+LOG = logging.getLogger(__name__)
+
+
+class ONOSMechanismDriver(api.MechanismDriver):
+
+ """Open Networking Operating System ML2 Driver for Neutron.
+
+ Code which makes communication between ONOS and OpenStack Neutron
+ possible.
+ """
+ def __init__(self):
+ self.onos_path = cfg.CONF.onos.url_path
+ self.onos_auth = (cfg.CONF.onos.username, cfg.CONF.onos.password)
+ self.vif_type = portbindings.VIF_TYPE_OVS
+ self.vif_details = {portbindings.CAP_PORT_FILTER: True}
+
+ def initialize(self):
+ # No action required as of now. Can be extended in
+ # the future if required.
+ pass
+
+ @log_helpers.log_method_call
+ def create_network_postcommit(self, context):
+ entity_path = 'networks'
+ resource = context.current.copy()
+ onos_utils.send_msg(self.onos_path, self.onos_auth, 'post',
+ entity_path, {'network': resource})
+
+ @log_helpers.log_method_call
+ def update_network_postcommit(self, context):
+ entity_path = 'networks/' + context.current['id']
+ resource = context.current.copy()
+ onos_utils.send_msg(self.onos_path, self.onos_auth, 'put',
+ entity_path, {'network': resource})
+
+ @log_helpers.log_method_call
+ def delete_network_postcommit(self, context):
+ entity_path = 'networks/' + context.current['id']
+ onos_utils.send_msg(self.onos_path, self.onos_auth, 'delete',
+ entity_path)
+
+ @log_helpers.log_method_call
+ def create_subnet_postcommit(self, context):
+ entity_path = 'subnets'
+ resource = context.current.copy()
+ onos_utils.send_msg(self.onos_path, self.onos_auth, 'post',
+ entity_path, {'subnet': resource})
+
+ @log_helpers.log_method_call
+ def update_subnet_postcommit(self, context):
+ entity_path = 'subnets/' + context.current['id']
+ resource = context.current.copy()
+ onos_utils.send_msg(self.onos_path, self.onos_auth, 'put',
+ entity_path, {'subnet': resource})
+
+ @log_helpers.log_method_call
+ def delete_subnet_postcommit(self, context):
+ entity_path = 'subnets/' + context.current['id']
+ onos_utils.send_msg(self.onos_path, self.onos_auth, 'delete',
+ entity_path)
+
+ @log_helpers.log_method_call
+ def create_port_postcommit(self, context):
+ entity_path = 'ports'
+ resource = context.current.copy()
+ onos_utils.send_msg(self.onos_path, self.onos_auth, 'post',
+ entity_path, {'port': resource})
+
+ @log_helpers.log_method_call
+ def update_port_postcommit(self, context):
+ entity_path = 'ports/' + context.current['id']
+ resource = context.current.copy()
+ onos_utils.send_msg(self.onos_path, self.onos_auth, 'put',
+ entity_path, {'port': resource})
+
+ @log_helpers.log_method_call
+ def delete_port_postcommit(self, context):
+ entity_path = 'ports/' + context.current['id']
+ onos_utils.send_msg(self.onos_path, self.onos_auth, 'delete',
+ entity_path)
+
+ @log_helpers.log_method_call
+ def bind_port(self, context):
+ """Set port binding data for use with nova."""
+ LOG.debug("Attempting to bind port %(port)s on network %(network)s",
+ {'port': context.current['id'],
+ 'network': context.network.current['id']})
+ # Prepared porting binding data
+ for segment in context.segments_to_bind:
+ if self.check_segment(segment):
+ context.set_binding(segment[api.ID],
+ self.vif_type,
+ self.vif_details,
+ status=n_const.PORT_STATUS_ACTIVE)
+ LOG.debug("Port bound successful for segment: %s", segment)
+ return
+ else:
+ LOG.debug("Port bound un-successfult 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]})
+
+ @log_helpers.log_method_call
+ def check_segment(self, segment):
+ """Check whether segment is valid for the ONOS MechanismDriver."""
+
+ return segment[api.NETWORK_TYPE] in [constants.TYPE_LOCAL,
+ constants.TYPE_GRE,
+ constants.TYPE_VXLAN,
+ constants.TYPE_VLAN]
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/__init__.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/__init__.py
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/__init__.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/__init__.py
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/__init__.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/__init__.py
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/l3/__init__.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/l3/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/l3/__init__.py
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/l3/test_driver.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/l3/test_driver.py
new file mode 100644
index 00000000..c0bba85a
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/l3/test_driver.py
@@ -0,0 +1,230 @@
+# Copyright (C) 2015 Huawei Technologies India Pvt Ltd.
+# 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.
+#
+
+import copy
+import mock
+
+from oslotest import base
+
+from neutron.extensions import l3
+from neutron.tests.unit.api.v2 import test_base
+from neutron.tests.unit.extensions import base as test_neutron_extensions
+from webob import exc
+
+import networking_onos.plugins.l3.driver as onos_driver
+
+fake_tenant_id = '048aa98a3ec345dc8b14427c81e276cf'
+
+fake_router_uuid = '292f7967-c5e7-47d8-8265-dc2160678b75'
+fake_router_object = {'router': {'name': 'router_abc',
+ 'external_gateway_info': None,
+ 'admin_state_up': True,
+ 'tenant_id': fake_tenant_id}}
+
+fake_network_id = '7464aaf0-27ea-448a-97df-51732f9e0e27'
+fake_router_external_info = {'external_gateway_info':
+ {'network_id': fake_network_id,
+ 'enable_snat': False}}
+
+fake_floating_ip_id = '7464aaf0-27ea-448a-97df-51732f9e0e25'
+fake_floating_ip = {'floatingip':
+ {'fixed_ip_address': '10.1.1.1',
+ 'id': fake_floating_ip_id,
+ 'router_id': fake_router_uuid,
+ 'port_id': None,
+ 'status': None,
+ 'tenant_id': fake_tenant_id}}
+
+fake_port_id = '7db560e9-76d4-4bf9-9c28-43efa7afa45d'
+fake_subnet_id = 'dc2b8071-c24c-4a8e-b471-dbf3fbe55830'
+fake_port = {'id': fake_port_id,
+ 'network_id': fake_network_id,
+ 'fixed_ips': [{'ip_address': '21.41.4.5',
+ 'prefixlen': 28,
+ 'subnet_id': fake_subnet_id}],
+ 'subnets': [{'id': fake_subnet_id,
+ 'cidr': '21.41.4.0/28',
+ 'gateway_ip': '21.41.4.1'}]}
+
+fake_floating_ip_update_info = {'floating_network_id': fake_network_id,
+ 'tenant_id': fake_tenant_id,
+ 'fixed_ip_address': '20.1.1.11',
+ 'subnet_id': fake_port['subnets'][0]['id'],
+ 'port_id': fake_port_id,
+ 'floating_ip_address': '198.1.2.3'}
+
+fake_interface_add = {'subnet_id': fake_subnet_id}
+
+fake_interface_remove = {'subnet_id': fake_subnet_id,
+ 'port_id': fake_port_id}
+
+
+class ONOSL3PluginTestCase(base.BaseTestCase,
+ test_neutron_extensions.ExtensionTestCase,
+ onos_driver.ONOSL3Plugin):
+
+ def setUp(self):
+ super(ONOSL3PluginTestCase, self).setUp()
+ self._setUpExtension(
+ 'neutron.extensions.l3.RouterPluginBase', None,
+ l3.RESOURCE_ATTRIBUTE_MAP, l3.L3, None,
+ allow_pagination=True, allow_sorting=True,
+ supported_extension_aliases=['router'],
+ use_quota=True)
+ self.instance = self.plugin.return_value
+
+ def _mock_req_res(self, status_code):
+ response = mock.Mock(status_code=status_code)
+ response.raise_for_status = mock.Mock()
+ return response
+
+ def _test_send_msg(self, dict_info, oper_type, url):
+ if oper_type == 'post':
+ resp = self.api.post(url, self.serialize(dict_info))
+ elif oper_type == 'put':
+ resp = self.api.put(url, self.serialize(dict_info))
+ else:
+ resp = self.api.delete(url)
+ return resp
+
+ def test_create_router(self):
+ router_info = copy.deepcopy(fake_router_object['router'])
+ router_info.update({'status': 'ACTIVE', 'id': fake_router_uuid})
+ self.instance.create_router.return_value = router_info
+ self.instance.get_routers_count.return_value = 0
+ url = test_base._get_path('routers', fmt=self.fmt)
+ resp = self._test_send_msg(fake_router_object, 'post', url)
+ self.instance.create_router.\
+ assert_called_once_with(mock.ANY, router=fake_router_object)
+ self._verify_resp(resp, exc.HTTPCreated.code,
+ 'router', fake_router_uuid)
+
+ def test_update_router(self):
+ router_info = copy.deepcopy(fake_router_object['router'])
+ router_info.update(fake_router_external_info)
+ router_info.update({'status': 'ACTIVE', 'id': fake_router_uuid})
+ self.instance.update_router.return_value = router_info
+ router_request = {'router': fake_router_external_info}
+ url = test_base._get_path('routers', id=fake_router_uuid, fmt=self.fmt)
+ resp = self._test_send_msg(router_request, 'put', url)
+ self.instance.update_router.\
+ assert_called_once_with(mock.ANY, fake_router_uuid,
+ router=router_request)
+ self._verify_resp(resp, exc.HTTPOk.code, 'router', fake_router_uuid)
+
+ def test_delete_router(self):
+ url = test_base._get_path('routers', id=fake_router_uuid, fmt=self.fmt)
+ resp = self._test_send_msg(None, 'delete', url)
+ self.instance.delete_router.assert_called_once_with(mock.ANY,
+ fake_router_uuid)
+ self.assertEqual(resp.status_int, exc.HTTPNoContent.code)
+
+ def test_create_floating_ip(self):
+ floatingip_info = copy.deepcopy(fake_floating_ip['floatingip'])
+ floatingip_info.update(fake_floating_ip_update_info)
+ floatingip_info.update({'status': 'ACTIVE', 'fixed_ip_address': None})
+
+ self.instance.create_floatingip.return_value = floatingip_info
+ self.instance.get_floatingips_count.return_value = 0
+ self.instance.get_port = mock.Mock(return_value=fake_port)
+
+ floating_ip_request = {'floatingip': fake_floating_ip_update_info}
+ url = test_base._get_path('floatingips', fmt=self.fmt)
+ resp = self._test_send_msg(floating_ip_request, 'post', url)
+ self.instance.create_floatingip.\
+ assert_called_once_with(mock.ANY,
+ floatingip=floating_ip_request)
+ self._verify_resp(resp, exc.HTTPCreated.code,
+ 'floatingip', fake_floating_ip_id)
+
+ def test_update_floating_ip(self):
+ fake_floating_ip_update_info = {'port_id': None}
+ floatingip_info = copy.deepcopy(fake_floating_ip['floatingip'])
+ floatingip_info.update(fake_floating_ip_update_info)
+ floatingip_info.update({'status': 'ACTIVE',
+ 'tenant_id': fake_tenant_id,
+ 'floating_network_id': fake_network_id,
+ 'fixed_ip_address': None,
+ 'floating_ip_address': '172.24.4.228'})
+
+ self.instance.update_floatingip.return_value = floatingip_info
+ self.instance.get_port = mock.Mock(return_value=fake_port)
+ floating_ip_request = {'floatingip': fake_floating_ip_update_info}
+ url = test_base._get_path('floatingips',
+ id=fake_floating_ip_id, fmt=self.fmt)
+ resp = self._test_send_msg(floating_ip_request, 'put', url)
+ self.instance.update_floatingip.\
+ assert_called_once_with(mock.ANY,
+ fake_floating_ip_id,
+ floatingip=floating_ip_request)
+ self._verify_resp(resp, exc.HTTPOk.code,
+ 'floatingip', fake_floating_ip_id)
+
+ def test_delete_floating_ip(self):
+ self.instance.get_port = mock.Mock(return_value=fake_port)
+ url = test_base._get_path('floatingips', id=fake_floating_ip_id)
+ resp = self._test_send_msg(None, 'delete', url)
+ self.instance.delete_floatingip.\
+ assert_called_once_with(mock.ANY, fake_floating_ip_id)
+ self.assertEqual(resp.status_int, exc.HTTPNoContent.code)
+
+ def test_add_router_interface(self):
+ interface_info = {'tenant_id': fake_tenant_id,
+ 'port_id': fake_port_id,
+ 'id': fake_router_uuid}
+ interface_info.update(fake_interface_add)
+ self.instance.add_router_interface.return_value = interface_info
+ url = test_base._get_path('routers', id=fake_router_uuid,
+ action='add_router_interface',
+ fmt=self.fmt)
+ resp = self._test_send_msg(fake_interface_add, 'put', url)
+ self.instance.add_router_interface.\
+ assert_called_once_with(mock.ANY, fake_router_uuid,
+ fake_interface_add)
+ self._verify_resp(resp, exc.HTTPOk.code, None, fake_router_uuid)
+
+ def test_remove_router_interface(self):
+ interface_info = {'tenant_id': fake_tenant_id,
+ 'id': fake_router_uuid}
+ interface_info.update(fake_interface_remove)
+ self.instance.remove_router_interface.return_value = interface_info
+ url = test_base._get_path('routers', id=fake_router_uuid,
+ action='remove_router_interface',
+ fmt=self.fmt)
+ resp = self._test_send_msg(fake_interface_remove, 'put', url)
+ self.instance.remove_router_interface.\
+ assert_called_once_with(mock.ANY, fake_router_uuid,
+ fake_interface_remove)
+ self._verify_resp(resp, exc.HTTPOk.code, None, fake_router_uuid)
+
+ def _verify_resp(self, resp, return_code, context, id):
+ self.assertEqual(resp.status_int, return_code)
+ resp = self.deserialize(resp)
+
+ if context is None:
+ self.assertEqual(resp['id'], id)
+ self.assertEqual(resp['subnet_id'], fake_subnet_id)
+ return
+
+ self.assertIn(context, resp)
+ resource = resp[context]
+ self.assertEqual(resource['id'], id)
+ if context == 'router':
+ self.assertEqual(resource['status'], 'ACTIVE')
+ self.assertEqual(resource['admin_state_up'], True)
+ elif context == 'floatingip':
+ self.assertEqual(resource['status'], 'ACTIVE')
+ self.assertEqual(resource['fixed_ip_address'], None)
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/ml2/__init__.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/ml2/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/ml2/__init__.py
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/ml2/test_driver.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/ml2/test_driver.py
new file mode 100644
index 00000000..89969239
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/ml2/test_driver.py
@@ -0,0 +1,237 @@
+# Copyright (c) 2015 Huawei Technologies India Pvt Ltd
+# 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.
+
+import mock
+import requests
+
+from oslo_config import cfg
+from oslo_serialization import jsonutils
+from oslotest import base
+
+from neutron.common import constants as n_const
+from neutron.plugins.common import constants
+from neutron.plugins.ml2 import driver_api as api
+from neutron.plugins.ml2 import driver_context as ctx
+
+import networking_onos.plugins.ml2.driver as onos_ml2_driver
+
+
+fake_network_uuid = 'd897e21a-dfd6-4331-a5dd-7524fa421c3e'
+fake_network_object = {'status': 'ACTIVE',
+ 'subnets': [],
+ 'name': 'net1',
+ 'provider:physical_network': None,
+ 'admin_state_up': True,
+ 'tenant_id': 'test-tenant',
+ 'provider:network_type': 'local',
+ 'router:external': False,
+ 'shared': False,
+ 'id': fake_network_uuid,
+ 'provider:segmentation_id': None}
+
+fake_subnet_uuid = 'd897e21a-dfd6-4331-a5dd-7524fa421c3e'
+fake_subnet_object = {'ipv6_ra_mode': None,
+ 'allocation_pools': [{'start': '10.0.0.2',
+ 'end': '10.0.1.254'}],
+ 'host_routes': [],
+ 'ipv6_address_mode': None,
+ 'cidr': '10.0.0.0/23',
+ 'id': fake_subnet_uuid,
+ 'name': '',
+ 'enable_dhcp': True,
+ 'network_id': fake_network_uuid,
+ 'tenant_id': 'test-tenant',
+ 'dns_nameservers': [],
+ 'gateway_ip': '10.0.0.1',
+ 'ip_version': 4,
+ 'shared': False}
+
+fake_port_uuid = '72c56c48-e9b8-4dcf-b3a7-0813bb3bd839'
+fake_port_object = {'status': 'DOWN',
+ 'binding:host_id': '',
+ 'allowed_address_pairs': [],
+ 'device_owner': 'fake_owner',
+ 'binding:profile': {},
+ 'fixed_ips': [],
+ 'id': fake_port_uuid,
+ 'security_groups':
+ ['2f9244b4-9bee-4e81-bc4a-3f3c2045b3d7'],
+ 'device_id': 'fake_device',
+ 'name': '',
+ 'admin_state_up': True,
+ 'network_id': fake_network_uuid,
+ 'tenant_id': 'test-tenant',
+ 'binding:vif_details': {},
+ 'binding:vnic_type': 'normal',
+ 'binding:vif_type': 'unbound',
+ 'mac_address': '12:34:56 :78:21:b6'}
+
+
+class ONOSMechanismDriverTestCase(base.BaseTestCase,
+ onos_ml2_driver.ONOSMechanismDriver):
+
+ def setUp(self):
+ super(ONOSMechanismDriverTestCase, self).setUp()
+ self.set_test_config()
+
+ def set_test_config(self):
+ cfg.CONF.set_override('url_path', 'http://127.0.0.1:1111', 'onos')
+ cfg.CONF.set_override('username', 'onos_user', 'onos')
+ cfg.CONF.set_override('password', 'awesome', 'onos')
+ self.onos_path = cfg.CONF.onos.url_path
+ self.onos_auth = (cfg.CONF.onos.username,
+ cfg.CONF.onos.password)
+
+ def _mock_req_resp(self, status_code):
+ response = mock.Mock(status_code=status_code)
+ response.raise_for_status = mock.Mock()
+ return response
+
+ def _test_response(self, context, oper_type, obj_type, mock_method):
+ body = None
+ if oper_type is not 'delete':
+ entity = {obj_type: context.current.copy()}
+ body = jsonutils.dumps(entity, indent=2)
+ if oper_type == 'post':
+ url = '%s/%s' % (self.onos_path, obj_type + 's')
+ else:
+ url = '%s/%s/%s' % (self.onos_path, obj_type + 's',
+ context.current['id'])
+ kwargs = {'url': url, 'data': body}
+ mock_method.assert_called_once_with(
+ method=oper_type,
+ headers={'Content-Type': 'application/json'},
+ auth=self.onos_auth, **kwargs)
+
+ def test_create_network_postcommit(self):
+ context = mock.Mock(current=fake_network_object)
+ resp = self._mock_req_resp(requests.codes.created)
+ with mock.patch('requests.request',
+ return_value=resp) as mock_method:
+ self.create_network_postcommit(context)
+ self._test_response(context, 'post', 'network', mock_method)
+
+ def test_update_network_postcommit(self):
+ context = mock.Mock(current=fake_network_object)
+ resp = self._mock_req_resp(requests.codes.created)
+ with mock.patch('requests.request',
+ return_value=resp) as mock_method:
+ self.update_network_postcommit(context)
+ self._test_response(context, 'put', 'network', mock_method)
+
+ def test_delete_network_postcommit(self):
+ context = mock.Mock(current={'id': fake_network_uuid})
+ resp = self._mock_req_resp(requests.codes.created)
+ with mock.patch('requests.request',
+ return_value=resp) as mock_method:
+ self.delete_network_postcommit(context)
+ self._test_response(context, 'delete', 'network', mock_method)
+
+ def test_create_subnet_postcommit(self):
+ context = mock.Mock(current=fake_subnet_object)
+ resp = self._mock_req_resp(requests.codes.created)
+ with mock.patch('requests.request',
+ return_value=resp) as mock_method:
+ self.create_subnet_postcommit(context)
+ self._test_response(context, 'post', 'subnet', mock_method)
+
+ def test_update_subnet_postcommit(self):
+ context = mock.Mock(current=fake_subnet_object)
+ resp = self._mock_req_resp(requests.codes.created)
+ with mock.patch('requests.request',
+ return_value=resp) as mock_method:
+ self.update_subnet_postcommit(context)
+ self._test_response(context, 'put', 'subnet', mock_method)
+
+ def test_delete_subnet_postcommit(self):
+ context = mock.Mock(current={'id': fake_subnet_uuid})
+ resp = self._mock_req_resp(requests.codes.created)
+ with mock.patch('requests.request',
+ return_value=resp) as mock_method:
+ self.delete_subnet_postcommit(context)
+ self._test_response(context, 'delete', 'subnet', mock_method)
+
+ def test_create_port_postcommit(self):
+ context = mock.Mock(current=fake_port_object)
+ resp = self._mock_req_resp(requests.codes.created)
+ with mock.patch('requests.request',
+ return_value=resp) as mock_method:
+ self.create_port_postcommit(context)
+ self._test_response(context, 'post', 'port', mock_method)
+
+ def test_update_port_postcommit(self):
+ context = mock.Mock(current=fake_port_object)
+ resp = self._mock_req_resp(requests.codes.created)
+ with mock.patch('requests.request',
+ return_value=resp) as mock_method:
+ self.update_port_postcommit(context)
+ self._test_response(context, 'put', 'port', mock_method)
+
+ def test_delete_port_postcommit(self):
+ context = mock.Mock(current={'id': fake_port_uuid})
+ resp = self._mock_req_resp(requests.codes.created)
+ with mock.patch('requests.request',
+ return_value=resp) as mock_method:
+ self.delete_port_postcommit(context)
+ self._test_response(context, 'delete', 'port', mock_method)
+
+ # given valid and invalid segments
+ valid_segment = {
+ api.ID: 'API_ID',
+ api.NETWORK_TYPE: constants.TYPE_LOCAL,
+ api.SEGMENTATION_ID: 'API_SEGMENTATION_ID',
+ api.PHYSICAL_NETWORK: 'API_PHYSICAL_NETWORK'}
+
+ invalid_segment = {
+ api.ID: 'API_ID',
+ api.NETWORK_TYPE: constants.TYPE_NONE,
+ api.SEGMENTATION_ID: 'API_SEGMENTATION_ID',
+ api.PHYSICAL_NETWORK: 'API_PHYSICAL_NETWORK'}
+
+ def test_check_segment(self):
+ """Validate the check_segment method."""
+
+ # given driver and all network types
+ all_network_types = [constants.TYPE_FLAT, constants.TYPE_GRE,
+ constants.TYPE_LOCAL, constants.TYPE_VXLAN,
+ constants.TYPE_VLAN, constants.TYPE_NONE]
+
+ # when checking segments network type
+ valid_types = {network_type
+ for network_type in all_network_types
+ if self.check_segment({api.NETWORK_TYPE: network_type})}
+
+ # then true is returned only for valid network types
+ self.assertEqual({constants.TYPE_LOCAL, constants.TYPE_GRE,
+ constants.TYPE_VXLAN, constants.TYPE_VLAN},
+ valid_types)
+
+ def test_bind_port(self):
+ self.vif_type = "MY_VIF_TYPE"
+ self.vif_details = "MY_VIF_DETAILS"
+ network = mock.MagicMock(spec=api.NetworkContext)
+ port_context = mock.MagicMock(
+ spec=ctx.PortContext, current={'id': 'CURRENT_CONTEXT_ID'},
+ segments_to_bind=[self.valid_segment, self.invalid_segment],
+ network=network)
+
+ # when port is bound
+ self.bind_port(port_context)
+
+ # then context binding is setup with returned vif_type and valid
+ # segment api ID
+ port_context.set_binding.assert_called_once_with(
+ self.valid_segment[api.ID], self.vif_type,
+ self.vif_details, status=n_const.PORT_STATUS_ACTIVE)