From: Fawad Khaliq Date: Sat, 28 Feb 2015 19:30:04 +0000 (-0800) Subject: PLUMgrid plugin decomposition X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=a48a13954881b771eaaaa1c1446e149313eb9803;p=openstack-build%2Fneutron-build.git PLUMgrid plugin decomposition As part of the plugin decomposition work, this change removes PLUMgrid plugin code from Neutron and moves it to networking-plumgrid repo [1]. Plugin code, config, drivers and unit test cases are all moved to networking-plumgrid. Updated vendor decomposition progress chart [1] https://github.com/stackforge/networking-plumgrid Partially-implements: blueprint core-vendor-decomposition Closes-bug: #1426752 Change-Id: I34c952d1c259f44ed8028ded0b58a5db908dd245 --- diff --git a/doc/source/devref/contribute.rst b/doc/source/devref/contribute.rst index c5d9f5536..5bc068c0c 100644 --- a/doc/source/devref/contribute.rst +++ b/doc/source/devref/contribute.rst @@ -415,7 +415,7 @@ The following chart captures the following aspects: +-------------------------------+-----------------------+-----------+------------------+---------+--------------+ | networking-ovs-dpdk_ | | | | | | +-------------------------------+-----------------------+-----------+------------------+---------+--------------+ -| networking-plumgrid_ | | | | | | +| networking-plumgrid_ | core | yes | yes | [C] | Kilo | +-------------------------------+-----------------------+-----------+------------------+---------+--------------+ | networking-vsphere_ | | | | | | +-------------------------------+-----------------------+-----------+------------------+---------+--------------+ @@ -460,6 +460,13 @@ OpenDayLight .. _networking-plumgrid: +PLUMgrid +--------- + +* Git: https://github.com/stackforge/networking-plumgrid +* Launchpad: https://launchpad.net/networking-plumgrid +* PyPI: https://pypi.python.org/pypi/networking-plumgrid + .. _networking-vsphere: .. _pluribus: diff --git a/neutron/plugins/plumgrid/common/__init__.py b/neutron/plugins/plumgrid/common/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/neutron/plugins/plumgrid/common/exceptions.py b/neutron/plugins/plumgrid/common/exceptions.py deleted file mode 100644 index b2a243791..000000000 --- a/neutron/plugins/plumgrid/common/exceptions.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2013 PLUMgrid, Inc. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -"""Neutron PLUMgrid Plugin exceptions""" - -from neutron.common import exceptions as base_exec - - -class PLUMgridException(base_exec.NeutronException): - message = _("PLUMgrid Plugin Error: %(err_msg)s") - - -class PLUMgridConnectionFailed(PLUMgridException): - message = _("Connection failed with PLUMgrid Director: %(err_msg)s") diff --git a/neutron/plugins/plumgrid/drivers/__init__.py b/neutron/plugins/plumgrid/drivers/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/neutron/plugins/plumgrid/drivers/fake_plumlib.py b/neutron/plugins/plumgrid/drivers/fake_plumlib.py deleted file mode 100644 index a0f81fd53..000000000 --- a/neutron/plugins/plumgrid/drivers/fake_plumlib.py +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright 2013 PLUMgrid, Inc. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from neutron.extensions import providernet as provider -from neutron.i18n import _LI -from neutron.openstack.common import log as logging - -LOG = logging.getLogger(__name__) - - -class Plumlib(object): - """ - Class PLUMgrid Fake Library. This library is a by-pass implementation - for the PLUMgrid Library. This class is being used by the unit test - integration in Neutron. - """ - - def __init__(self): - LOG.info(_LI('Python PLUMgrid Fake Library Started ')) - - def director_conn(self, director_plumgrid, director_port, timeout, - director_admin, director_password): - LOG.info(_LI('Fake Director: %s'), - director_plumgrid + ':' + director_port) - - def create_network(self, tenant_id, net_db, network): - net_db["network"] = {} - for key in (provider.NETWORK_TYPE, - provider.PHYSICAL_NETWORK, - provider.SEGMENTATION_ID): - net_db["network"][key] = network["network"][key] - return net_db - - def update_network(self, tenant_id, net_id): - pass - - def delete_network(self, net_db, net_id): - pass - - def create_subnet(self, sub_db, net_db, ipnet): - pass - - def update_subnet(self, orig_sub_db, new_sub_db, ipnet): - pass - - def delete_subnet(self, tenant_id, net_db, net_id): - pass - - def create_port(self, port_db, router_db): - pass - - def update_port(self, port_db, router_db): - pass - - def delete_port(self, port_db, router_db): - pass - - def create_router(self, tenant_id, router_db): - pass - - def update_router(self, router_db, router_id): - pass - - def delete_router(self, tenant_id, router_id): - pass - - def add_router_interface(self, tenant_id, router_id, port_db, ipnet): - pass - - def remove_router_interface(self, tenant_id, net_id, router_id): - pass - - def create_floatingip(self, floating_ip): - pass - - def update_floatingip(self, floating_ip_orig, floating_ip, id): - pass - - def delete_floatingip(self, floating_ip_orig, id): - pass - - def disassociate_floatingips(self, fip, port_id): - return dict((key, fip[key]) for key in ("id", "floating_network_id", - "floating_ip_address")) - - def create_security_group(self, sg_db): - pass - - def update_security_group(self, sg_db): - pass - - def delete_security_group(self, sg_db): - pass - - def create_security_group_rule(self, sg_rule_db): - pass - - def create_security_group_rule_bulk(self, sg_rule_db): - pass - - def delete_security_group_rule(self, sg_rule_db): - pass diff --git a/neutron/plugins/plumgrid/drivers/plumlib.py b/neutron/plugins/plumgrid/drivers/plumlib.py deleted file mode 100644 index 6056100c8..000000000 --- a/neutron/plugins/plumgrid/drivers/plumlib.py +++ /dev/null @@ -1,116 +0,0 @@ -# Copyright 2013 PLUMgrid, Inc. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -Neutron Plug-in for PLUMgrid Virtual Networking Infrastructure (VNI) -This plugin will forward authenticated REST API calls -to the PLUMgrid Network Management System called Director -""" - -from plumgridlib import plumlib - -from neutron.i18n import _LI -from neutron.openstack.common import log as logging - -LOG = logging.getLogger(__name__) - - -class Plumlib(object): - """ - Class PLUMgrid Python Library. This library is a third-party tool - needed by PLUMgrid plugin to implement all core API in Neutron. - """ - - def __init__(self): - LOG.info(_LI('Python PLUMgrid Library Started ')) - - def director_conn(self, director_plumgrid, director_port, timeout, - director_admin, director_password): - self.plumlib = plumlib.Plumlib(director_plumgrid, - director_port, - timeout, - director_admin, - director_password) - - def create_network(self, tenant_id, net_db, network): - self.plumlib.create_network(tenant_id, net_db, network) - - def update_network(self, tenant_id, net_id): - self.plumlib.update_network(tenant_id, net_id) - - def delete_network(self, net_db, net_id): - self.plumlib.delete_network(net_db, net_id) - - def create_subnet(self, sub_db, net_db, ipnet): - self.plumlib.create_subnet(sub_db, net_db, ipnet) - - def update_subnet(self, orig_sub_db, new_sub_db, ipnet): - self.plumlib.update_subnet(orig_sub_db, new_sub_db, ipnet) - - def delete_subnet(self, tenant_id, net_db, net_id): - self.plumlib.delete_subnet(tenant_id, net_db, net_id) - - def create_port(self, port_db, router_db): - self.plumlib.create_port(port_db, router_db) - - def update_port(self, port_db, router_db): - self.plumlib.update_port(port_db, router_db) - - def delete_port(self, port_db, router_db): - self.plumlib.delete_port(port_db, router_db) - - def create_router(self, tenant_id, router_db): - self.plumlib.create_router(tenant_id, router_db) - - def update_router(self, router_db, router_id): - self.plumlib.update_router(router_db, router_id) - - def delete_router(self, tenant_id, router_id): - self.plumlib.delete_router(tenant_id, router_id) - - def add_router_interface(self, tenant_id, router_id, port_db, ipnet): - self.plumlib.add_router_interface(tenant_id, router_id, port_db, ipnet) - - def remove_router_interface(self, tenant_id, net_id, router_id): - self.plumlib.remove_router_interface(tenant_id, net_id, router_id) - - def create_floatingip(self, floating_ip): - self.plumlib.create_floatingip(floating_ip) - - def update_floatingip(self, floating_ip_orig, floating_ip, id): - self.plumlib.update_floatingip(floating_ip_orig, floating_ip, id) - - def delete_floatingip(self, floating_ip_orig, id): - self.plumlib.delete_floatingip(floating_ip_orig, id) - - def disassociate_floatingips(self, floating_ip, port_id): - self.plumlib.disassociate_floatingips(floating_ip, port_id) - - def create_security_group(self, sg_db): - self.plumlib.create_security_group(sg_db) - - def update_security_group(self, sg_db): - self.plumlib.update_security_group(sg_db) - - def delete_security_group(self, sg_db): - self.plumlib.delete_security_group(sg_db) - - def create_security_group_rule(self, sg_rule_db): - self.plumlib.create_security_group_rule(sg_rule_db) - - def create_security_group_rule_bulk(self, sg_rule_db): - self.plumlib.create_security_group_rule_bulk(sg_rule_db) - - def delete_security_group_rule(self, sg_rule_db): - self.plumlib.delete_security_group_rule(sg_rule_db) diff --git a/neutron/plugins/plumgrid/plumgrid_plugin/plugin_ver.py b/neutron/plugins/plumgrid/plumgrid_plugin/plugin_ver.py deleted file mode 100644 index c050009d6..000000000 --- a/neutron/plugins/plumgrid/plumgrid_plugin/plugin_ver.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright 2013 PLUMgrid, Inc. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -VERSION = "0.2" diff --git a/neutron/plugins/plumgrid/plumgrid_plugin/plumgrid_plugin.py b/neutron/plugins/plumgrid/plumgrid_plugin/plumgrid_plugin.py index c625bad5c..ee95f2ae3 100644 --- a/neutron/plugins/plumgrid/plumgrid_plugin/plumgrid_plugin.py +++ b/neutron/plugins/plumgrid/plumgrid_plugin/plumgrid_plugin.py @@ -12,794 +12,13 @@ # License for the specific language governing permissions and limitations # under the License. -""" -Neutron Plug-in for PLUMgrid Virtual Networking Infrastructure (VNI) -This plugin will forward authenticated REST API calls -to the PLUMgrid Network Management System called Director -""" +from networking_plumgrid.neutron.plugins import plugin -import netaddr -from oslo_config import cfg -from oslo_utils import importutils -from sqlalchemy.orm import exc as sa_exc -from neutron.api.v2 import attributes -from neutron.common import constants -from neutron.db import db_base_plugin_v2 -from neutron.db import external_net_db -from neutron.db import l3_db -from neutron.db import portbindings_db -from neutron.db import quota_db # noqa -from neutron.db import securitygroups_db -from neutron.extensions import portbindings -from neutron.extensions import securitygroup as sec_grp -from neutron.i18n import _LI, _LW -from neutron.openstack.common import log as logging -from neutron.plugins.plumgrid.common import exceptions as plum_excep -from neutron.plugins.plumgrid.plumgrid_plugin import plugin_ver - -LOG = logging.getLogger(__name__) - -director_server_opts = [ - cfg.StrOpt('director_server', default='localhost', - help=_("PLUMgrid Director server to connect to")), - cfg.StrOpt('director_server_port', default='8080', - help=_("PLUMgrid Director server port to connect to")), - cfg.StrOpt('username', default='username', - help=_("PLUMgrid Director admin username")), - cfg.StrOpt('password', default='password', secret=True, - help=_("PLUMgrid Director admin password")), - cfg.IntOpt('servertimeout', default=5, - help=_("PLUMgrid Director server timeout")), - cfg.StrOpt('driver', - default="neutron.plugins.plumgrid.drivers.plumlib.Plumlib", - help=_("PLUMgrid Driver")), ] - -cfg.CONF.register_opts(director_server_opts, "plumgriddirector") - - -class NeutronPluginPLUMgridV2(db_base_plugin_v2.NeutronDbPluginV2, - external_net_db.External_net_db_mixin, - l3_db.L3_NAT_db_mixin, - portbindings_db.PortBindingMixin, - securitygroups_db.SecurityGroupDbMixin): +class NeutronPluginPLUMgridV2(plugin.NeutronPluginPLUMgridV2): supported_extension_aliases = ["binding", "external-net", "provider", "quotas", "router", "security-group"] - binding_view = "extension:port_binding:view" - binding_set = "extension:port_binding:set" - def __init__(self): - LOG.info(_LI('Neutron PLUMgrid Director: Starting Plugin')) - super(NeutronPluginPLUMgridV2, self).__init__() - self.plumgrid_init() - - LOG.debug('Neutron PLUMgrid Director: Neutron server with ' - 'PLUMgrid Plugin has started') - - def plumgrid_init(self): - """PLUMgrid initialization.""" - director_plumgrid = cfg.CONF.plumgriddirector.director_server - director_port = cfg.CONF.plumgriddirector.director_server_port - director_admin = cfg.CONF.plumgriddirector.username - director_password = cfg.CONF.plumgriddirector.password - timeout = cfg.CONF.plumgriddirector.servertimeout - plum_driver = cfg.CONF.plumgriddirector.driver - - # PLUMgrid Director info validation - LOG.info(_LI('Neutron PLUMgrid Director: %s'), director_plumgrid) - self._plumlib = importutils.import_object(plum_driver) - self._plumlib.director_conn(director_plumgrid, director_port, timeout, - director_admin, director_password) - - def create_network(self, context, network): - """Create Neutron network. - - Creates a PLUMgrid-based bridge. - """ - - LOG.debug('Neutron PLUMgrid Director: create_network() called') - - # Plugin DB - Network Create and validation - tenant_id = self._get_tenant_id_for_create(context, - network["network"]) - self._network_admin_state(network) - - with context.session.begin(subtransactions=True): - net_db = super(NeutronPluginPLUMgridV2, - self).create_network(context, network) - # Propagate all L3 data into DB - self._process_l3_create(context, net_db, network['network']) - self._ensure_default_security_group(context, tenant_id) - - try: - LOG.debug('PLUMgrid Library: create_network() called') - self._plumlib.create_network(tenant_id, net_db, network) - - except Exception as err_message: - raise plum_excep.PLUMgridException(err_msg=err_message) - - # Return created network - return net_db - - def update_network(self, context, net_id, network): - """Update Neutron network. - - Updates a PLUMgrid-based bridge. - """ - - LOG.debug("Neutron PLUMgrid Director: update_network() called") - self._network_admin_state(network) - tenant_id = self._get_tenant_id_for_create(context, network["network"]) - - with context.session.begin(subtransactions=True): - # Plugin DB - Network Update - net_db = super( - NeutronPluginPLUMgridV2, self).update_network(context, - net_id, network) - self._process_l3_update(context, net_db, network['network']) - - try: - LOG.debug("PLUMgrid Library: update_network() called") - self._plumlib.update_network(tenant_id, net_id) - - except Exception as err_message: - raise plum_excep.PLUMgridException(err_msg=err_message) - - # Return updated network - return net_db - - def delete_network(self, context, net_id): - """Delete Neutron network. - - Deletes a PLUMgrid-based bridge. - """ - - LOG.debug("Neutron PLUMgrid Director: delete_network() called") - net_db = super(NeutronPluginPLUMgridV2, - self).get_network(context, net_id) - - with context.session.begin(subtransactions=True): - self._process_l3_delete(context, net_id) - # Plugin DB - Network Delete - super(NeutronPluginPLUMgridV2, self).delete_network(context, - net_id) - - try: - LOG.debug("PLUMgrid Library: update_network() called") - self._plumlib.delete_network(net_db, net_id) - - except Exception as err_message: - raise plum_excep.PLUMgridException(err_msg=err_message) - - def create_port(self, context, port): - """Create Neutron port. - - Creates a PLUMgrid-based port on the specific Virtual Network - Function (VNF). - """ - LOG.debug("Neutron PLUMgrid Director: create_port() called") - - # Port operations on PLUMgrid Director is an automatic operation - # from the VIF driver operations in Nova. - # It requires admin_state_up to be True - - port["port"]["admin_state_up"] = True - port_data = port["port"] - - with context.session.begin(subtransactions=True): - # Plugin DB - Port Create and Return port - port_db = super(NeutronPluginPLUMgridV2, self).create_port(context, - port) - # Update port security - port_data.update(port_db) - - self._ensure_default_security_group_on_port(context, port) - - port_data[sec_grp.SECURITYGROUPS] = ( - self._get_security_groups_on_port(context, port)) - - self._process_port_create_security_group( - context, port_db, port_data[sec_grp.SECURITYGROUPS]) - - self._process_portbindings_create_and_update(context, - port_data, port_db) - - device_id = port_db["device_id"] - if port_db["device_owner"] == constants.DEVICE_OWNER_ROUTER_GW: - router_db = self._get_router(context, device_id) - else: - router_db = None - - try: - LOG.debug("PLUMgrid Library: create_port() called") - self._plumlib.create_port(port_db, router_db) - - except Exception as err_message: - raise plum_excep.PLUMgridException(err_msg=err_message) - - # Plugin DB - Port Create and Return port - return self._port_viftype_binding(context, port_db) - - def update_port(self, context, port_id, port): - """Update Neutron port. - - Updates a PLUMgrid-based port on the specific Virtual Network - Function (VNF). - """ - LOG.debug("Neutron PLUMgrid Director: update_port() called") - - with context.session.begin(subtransactions=True): - # Plugin DB - Port Create and Return port - port_db = super(NeutronPluginPLUMgridV2, self).update_port( - context, port_id, port) - device_id = port_db["device_id"] - if port_db["device_owner"] == constants.DEVICE_OWNER_ROUTER_GW: - router_db = self._get_router(context, device_id) - else: - router_db = None - - if (self._check_update_deletes_security_groups(port) or - self._check_update_has_security_groups(port)): - self._delete_port_security_group_bindings(context, - port_db["id"]) - sg_ids = self._get_security_groups_on_port(context, port) - self._process_port_create_security_group(context, - port_db, - sg_ids) - - self._process_portbindings_create_and_update(context, - port['port'], - port_db) - - try: - LOG.debug("PLUMgrid Library: create_port() called") - self._plumlib.update_port(port_db, router_db) - - except Exception as err_message: - raise plum_excep.PLUMgridException(err_msg=err_message) - - # Plugin DB - Port Update - return self._port_viftype_binding(context, port_db) - - def delete_port(self, context, port_id, l3_port_check=True): - """Delete Neutron port. - - Deletes a PLUMgrid-based port on the specific Virtual Network - Function (VNF). - """ - - LOG.debug("Neutron PLUMgrid Director: delete_port() called") - - with context.session.begin(subtransactions=True): - # Plugin DB - Port Create and Return port - port_db = super(NeutronPluginPLUMgridV2, - self).get_port(context, port_id) - router_ids = self.disassociate_floatingips( - context, port_id, do_notify=False) - super(NeutronPluginPLUMgridV2, self).delete_port(context, port_id) - - if port_db["device_owner"] == constants.DEVICE_OWNER_ROUTER_GW: - device_id = port_db["device_id"] - router_db = self._get_router(context, device_id) - else: - router_db = None - try: - LOG.debug("PLUMgrid Library: delete_port() called") - self._plumlib.delete_port(port_db, router_db) - - except Exception as err_message: - raise plum_excep.PLUMgridException(err_msg=err_message) - - # now that we've left db transaction, we are safe to notify - self.notify_routers_updated(context, router_ids) - - def get_port(self, context, id, fields=None): - with context.session.begin(subtransactions=True): - port_db = super(NeutronPluginPLUMgridV2, - self).get_port(context, id, fields) - - self._port_viftype_binding(context, port_db) - return self._fields(port_db, fields) - - def get_ports(self, context, filters=None, fields=None): - with context.session.begin(subtransactions=True): - ports_db = super(NeutronPluginPLUMgridV2, - self).get_ports(context, filters, fields) - for port_db in ports_db: - self._port_viftype_binding(context, port_db) - return [self._fields(port, fields) for port in ports_db] - - def create_subnet(self, context, subnet): - """Create Neutron subnet. - - Creates a PLUMgrid-based DHCP and NAT Virtual Network - Functions (VNFs). - """ - - LOG.debug("Neutron PLUMgrid Director: create_subnet() called") - - with context.session.begin(subtransactions=True): - # Plugin DB - Subnet Create - net_db = super(NeutronPluginPLUMgridV2, self).get_network( - context, subnet['subnet']['network_id'], fields=None) - s = subnet['subnet'] - ipnet = netaddr.IPNetwork(s['cidr']) - - # PLUMgrid Director reserves the last IP address for GW - # when is not defined - if s['gateway_ip'] is attributes.ATTR_NOT_SPECIFIED: - gw_ip = str(netaddr.IPAddress(ipnet.last - 1)) - subnet['subnet']['gateway_ip'] = gw_ip - - # PLUMgrid reserves the first IP - if s['allocation_pools'] == attributes.ATTR_NOT_SPECIFIED: - allocation_pool = self._allocate_pools_for_subnet(context, s) - subnet['subnet']['allocation_pools'] = allocation_pool - - sub_db = super(NeutronPluginPLUMgridV2, self).create_subnet( - context, subnet) - - try: - LOG.debug("PLUMgrid Library: create_subnet() called") - self._plumlib.create_subnet(sub_db, net_db, ipnet) - except Exception as err_message: - raise plum_excep.PLUMgridException(err_msg=err_message) - - return sub_db - - def delete_subnet(self, context, subnet_id): - """Delete subnet core Neutron API.""" - - LOG.debug("Neutron PLUMgrid Director: delete_subnet() called") - # Collecting subnet info - sub_db = self._get_subnet(context, subnet_id) - net_id = sub_db["network_id"] - net_db = self.get_network(context, net_id) - tenant_id = net_db["tenant_id"] - - with context.session.begin(subtransactions=True): - # Plugin DB - Subnet Delete - super(NeutronPluginPLUMgridV2, self).delete_subnet( - context, subnet_id) - try: - LOG.debug("PLUMgrid Library: delete_subnet() called") - self._plumlib.delete_subnet(tenant_id, net_db, net_id) - except Exception as err_message: - raise plum_excep.PLUMgridException(err_msg=err_message) - - def update_subnet(self, context, subnet_id, subnet): - """Update subnet core Neutron API.""" - - LOG.debug("update_subnet() called") - # Collecting subnet info - orig_sub_db = self._get_subnet(context, subnet_id) - - with context.session.begin(subtransactions=True): - # Plugin DB - Subnet Update - new_sub_db = super(NeutronPluginPLUMgridV2, - self).update_subnet(context, subnet_id, subnet) - ipnet = netaddr.IPNetwork(new_sub_db['cidr']) - - try: - # PLUMgrid Server does not support updating resources yet - LOG.debug("PLUMgrid Library: update_network() called") - self._plumlib.update_subnet(orig_sub_db, new_sub_db, ipnet) - - except Exception as err_message: - raise plum_excep.PLUMgridException(err_msg=err_message) - - return new_sub_db - - def create_router(self, context, router): - """ - Create router extension Neutron API - """ - LOG.debug("Neutron PLUMgrid Director: create_router() called") - - tenant_id = self._get_tenant_id_for_create(context, router["router"]) - - with context.session.begin(subtransactions=True): - - # Create router in DB - router_db = super(NeutronPluginPLUMgridV2, - self).create_router(context, router) - # Create router on the network controller - try: - # Add Router to VND - LOG.debug("PLUMgrid Library: create_router() called") - self._plumlib.create_router(tenant_id, router_db) - except Exception as err_message: - raise plum_excep.PLUMgridException(err_msg=err_message) - - # Return created router - return router_db - - def update_router(self, context, router_id, router): - - LOG.debug("Neutron PLUMgrid Director: update_router() called") - - with context.session.begin(subtransactions=True): - router_db = super(NeutronPluginPLUMgridV2, - self).update_router(context, router_id, router) - try: - LOG.debug("PLUMgrid Library: update_router() called") - self._plumlib.update_router(router_db, router_id) - except Exception as err_message: - raise plum_excep.PLUMgridException(err_msg=err_message) - - # Return updated router - return router_db - - def delete_router(self, context, router_id): - LOG.debug("Neutron PLUMgrid Director: delete_router() called") - - with context.session.begin(subtransactions=True): - orig_router = self._get_router(context, router_id) - tenant_id = orig_router["tenant_id"] - - super(NeutronPluginPLUMgridV2, self).delete_router(context, - router_id) - - try: - LOG.debug("PLUMgrid Library: delete_router() called") - self._plumlib.delete_router(tenant_id, router_id) - - except Exception as err_message: - raise plum_excep.PLUMgridException(err_msg=err_message) - - def add_router_interface(self, context, router_id, interface_info): - - LOG.debug("Neutron PLUMgrid Director: " - "add_router_interface() called") - with context.session.begin(subtransactions=True): - # Validate args - router_db = self._get_router(context, router_id) - tenant_id = router_db['tenant_id'] - - # Create interface in DB - int_router = super(NeutronPluginPLUMgridV2, - self).add_router_interface(context, - router_id, - interface_info) - port_db = self._get_port(context, int_router['port_id']) - subnet_id = port_db["fixed_ips"][0]["subnet_id"] - subnet_db = super(NeutronPluginPLUMgridV2, - self)._get_subnet(context, subnet_id) - ipnet = netaddr.IPNetwork(subnet_db['cidr']) - - # Create interface on the network controller - try: - LOG.debug("PLUMgrid Library: add_router_interface() called") - self._plumlib.add_router_interface(tenant_id, router_id, - port_db, ipnet) - - except Exception as err_message: - raise plum_excep.PLUMgridException(err_msg=err_message) - - return int_router - - def remove_router_interface(self, context, router_id, int_info): - - LOG.debug("Neutron PLUMgrid Director: remove_router_interface()" - " called") - with context.session.begin(subtransactions=True): - # Validate args - router_db = self._get_router(context, router_id) - tenant_id = router_db['tenant_id'] - if 'port_id' in int_info: - port = self._get_port(context, int_info['port_id']) - net_id = port['network_id'] - - elif 'subnet_id' in int_info: - subnet_id = int_info['subnet_id'] - subnet = self._get_subnet(context, subnet_id) - net_id = subnet['network_id'] - - # Remove router in DB - del_int_router = super(NeutronPluginPLUMgridV2, - self).remove_router_interface(context, - router_id, - int_info) - - try: - LOG.debug("PLUMgrid Library: " - "remove_router_interface() called") - self._plumlib.remove_router_interface(tenant_id, - net_id, router_id) - - except Exception as err_message: - raise plum_excep.PLUMgridException(err_msg=err_message) - - return del_int_router - - def create_floatingip(self, context, floatingip): - LOG.debug("Neutron PLUMgrid Director: create_floatingip() called") - - with context.session.begin(subtransactions=True): - - floating_ip = super(NeutronPluginPLUMgridV2, - self).create_floatingip(context, floatingip) - try: - LOG.debug("PLUMgrid Library: create_floatingip() called") - self._plumlib.create_floatingip(floating_ip) - - except Exception as err_message: - raise plum_excep.PLUMgridException(err_msg=err_message) - - return floating_ip - - def update_floatingip(self, context, id, floatingip): - LOG.debug("Neutron PLUMgrid Director: update_floatingip() called") - - with context.session.begin(subtransactions=True): - floating_ip_orig = super(NeutronPluginPLUMgridV2, - self).get_floatingip(context, id) - floating_ip = super(NeutronPluginPLUMgridV2, - self).update_floatingip(context, id, - floatingip) - try: - LOG.debug("PLUMgrid Library: update_floatingip() called") - self._plumlib.update_floatingip(floating_ip_orig, floating_ip, - id) - - except Exception as err_message: - raise plum_excep.PLUMgridException(err_msg=err_message) - - return floating_ip - - def delete_floatingip(self, context, id): - LOG.debug("Neutron PLUMgrid Director: delete_floatingip() called") - - with context.session.begin(subtransactions=True): - - floating_ip_orig = super(NeutronPluginPLUMgridV2, - self).get_floatingip(context, id) - - super(NeutronPluginPLUMgridV2, self).delete_floatingip(context, id) - - try: - LOG.debug("PLUMgrid Library: delete_floatingip() called") - self._plumlib.delete_floatingip(floating_ip_orig, id) - - except Exception as err_message: - raise plum_excep.PLUMgridException(err_msg=err_message) - - def disassociate_floatingips(self, context, port_id, do_notify=True): - LOG.debug("Neutron PLUMgrid Director: disassociate_floatingips() " - "called") - - try: - fip_qry = context.session.query(l3_db.FloatingIP) - floating_ip = fip_qry.filter_by(fixed_port_id=port_id).one() - - LOG.debug("PLUMgrid Library: disassociate_floatingips()" - " called") - self._plumlib.disassociate_floatingips(floating_ip, port_id) - - except sa_exc.NoResultFound: - pass - - except Exception as err_message: - raise plum_excep.PLUMgridException(err_msg=err_message) - - return super(NeutronPluginPLUMgridV2, - self).disassociate_floatingips( - context, port_id, do_notify=do_notify) - - def create_security_group(self, context, security_group, default_sg=False): - """Create a security group - - Create a new security group, including the default security group - """ - LOG.debug("Neutron PLUMgrid Director: create_security_group()" - " called") - - with context.session.begin(subtransactions=True): - - sg = security_group.get('security_group') - - tenant_id = self._get_tenant_id_for_create(context, sg) - if not default_sg: - self._ensure_default_security_group(context, tenant_id) - - sg_db = super(NeutronPluginPLUMgridV2, - self).create_security_group(context, security_group, - default_sg) - try: - LOG.debug("PLUMgrid Library: create_security_group()" - " called") - self._plumlib.create_security_group(sg_db) - - except Exception as err_message: - raise plum_excep.PLUMgridException(err_msg=err_message) - - return sg_db - - def update_security_group(self, context, sg_id, security_group): - """Update a security group - - Update security group name/description in Neutron and PLUMgrid - platform - """ - with context.session.begin(subtransactions=True): - sg_db = (super(NeutronPluginPLUMgridV2, - self).update_security_group(context, - sg_id, - security_group)) - if ('name' in security_group['security_group'] and - sg_db['name'] != 'default'): - try: - LOG.debug("PLUMgrid Library: update_security_group()" - " called") - self._plumlib.update_security_group(sg_db) - - except Exception as err_message: - raise plum_excep.PLUMgridException(err_msg=err_message) - return sg_db - - def delete_security_group(self, context, sg_id): - """Delete a security group - - Delete security group from Neutron and PLUMgrid Platform - - :param sg_id: security group ID of the rule to be removed - """ - with context.session.begin(subtransactions=True): - - sg = super(NeutronPluginPLUMgridV2, self).get_security_group( - context, sg_id) - if not sg: - raise sec_grp.SecurityGroupNotFound(id=sg_id) - - if sg['name'] == 'default' and not context.is_admin: - raise sec_grp.SecurityGroupCannotRemoveDefault() - - sec_grp_ip = sg['id'] - filters = {'security_group_id': [sec_grp_ip]} - if super(NeutronPluginPLUMgridV2, - self)._get_port_security_group_bindings(context, - filters): - raise sec_grp.SecurityGroupInUse(id=sec_grp_ip) - - sec_db = super(NeutronPluginPLUMgridV2, - self).delete_security_group(context, sg_id) - try: - LOG.debug("PLUMgrid Library: delete_security_group()" - " called") - self._plumlib.delete_security_group(sg) - - except Exception as err_message: - raise plum_excep.PLUMgridException(err_msg=err_message) - - return sec_db - - def create_security_group_rule(self, context, security_group_rule): - """Create a security group rule - - Create a security group rule in Neutron and PLUMgrid Platform - """ - LOG.debug("Neutron PLUMgrid Director: create_security_group_rule()" - " called") - bulk_rule = {'security_group_rules': [security_group_rule]} - return self.create_security_group_rule_bulk(context, bulk_rule)[0] - - def create_security_group_rule_bulk(self, context, security_group_rule): - """Create security group rules - - Create security group rules in Neutron and PLUMgrid Platform - - :param security_group_rule: list of rules to create - """ - sg_rules = security_group_rule.get('security_group_rules') - - with context.session.begin(subtransactions=True): - sg_id = super(NeutronPluginPLUMgridV2, - self)._validate_security_group_rules( - context, security_group_rule) - - # Check to make sure security group exists - security_group = super(NeutronPluginPLUMgridV2, - self).get_security_group(context, - sg_id) - - if not security_group: - raise sec_grp.SecurityGroupNotFound(id=sg_id) - - # Check for duplicate rules - self._check_for_duplicate_rules(context, sg_rules) - - sec_db = (super(NeutronPluginPLUMgridV2, - self).create_security_group_rule_bulk_native( - context, security_group_rule)) - try: - LOG.debug("PLUMgrid Library: create_security_" - "group_rule_bulk() called") - self._plumlib.create_security_group_rule_bulk(sec_db) - - except Exception as err_message: - raise plum_excep.PLUMgridException(err_msg=err_message) - - return sec_db - - def delete_security_group_rule(self, context, sgr_id): - """Delete a security group rule - - Delete a security group rule in Neutron and PLUMgrid Platform - """ - - LOG.debug("Neutron PLUMgrid Director: delete_security_group_rule()" - " called") - - sgr = (super(NeutronPluginPLUMgridV2, - self).get_security_group_rule(context, sgr_id)) - - if not sgr: - raise sec_grp.SecurityGroupRuleNotFound(id=sgr_id) - - super(NeutronPluginPLUMgridV2, - self).delete_security_group_rule(context, sgr_id) - try: - LOG.debug("PLUMgrid Library: delete_security_" - "group_rule() called") - self._plumlib.delete_security_group_rule(sgr) - - except Exception as err_message: - raise plum_excep.PLUMgridException(err_msg=err_message) - - # - # Internal PLUMgrid Functions - # - - def _get_plugin_version(self): - return plugin_ver.VERSION - - def _port_viftype_binding(self, context, port): - port[portbindings.VIF_TYPE] = portbindings.VIF_TYPE_IOVISOR - port[portbindings.VIF_DETAILS] = { - # TODO(rkukura): Replace with new VIF security details - portbindings.CAP_PORT_FILTER: - 'security-group' in self.supported_extension_aliases} - return port - - def _network_admin_state(self, network): - if network["network"].get("admin_state_up") is False: - LOG.warning(_LW("Networks with admin_state_up=False are not " - "supported by PLUMgrid plugin yet.")) - return network - - def _allocate_pools_for_subnet(self, context, subnet): - """Create IP allocation pools for a given subnet - - Pools are defined by the 'allocation_pools' attribute, - a list of dict objects with 'start' and 'end' keys for - defining the pool range. - Modified from Neutron DB based class - - """ - - pools = [] - # Auto allocate the pool around gateway_ip - net = netaddr.IPNetwork(subnet['cidr']) - boundary = int(netaddr.IPAddress(subnet['gateway_ip'] or net.last)) - potential_dhcp_ip = int(net.first + 1) - if boundary == potential_dhcp_ip: - first_ip = net.first + 3 - boundary = net.first + 2 - else: - first_ip = net.first + 2 - last_ip = net.last - 1 - # Use the gw_ip to find a point for splitting allocation pools - # for this subnet - split_ip = min(max(boundary, net.first), net.last) - if split_ip > first_ip: - pools.append({'start': str(netaddr.IPAddress(first_ip)), - 'end': str(netaddr.IPAddress(split_ip - 1))}) - if split_ip < last_ip: - pools.append({'start': str(netaddr.IPAddress(split_ip + 1)), - 'end': str(netaddr.IPAddress(last_ip))}) - # return auto-generated pools - # no need to check for their validity - return pools diff --git a/neutron/tests/unit/plumgrid/__init__.py b/neutron/tests/unit/plumgrid/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/neutron/tests/unit/plumgrid/extensions/__init__.py b/neutron/tests/unit/plumgrid/extensions/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/neutron/tests/unit/plumgrid/extensions/test_securitygroups.py b/neutron/tests/unit/plumgrid/extensions/test_securitygroups.py deleted file mode 100644 index ff5497266..000000000 --- a/neutron/tests/unit/plumgrid/extensions/test_securitygroups.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright 2014 PLUMgrid, Inc. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# - -""" -PLUMgrid plugin security group extension unit tests -""" - -import mock -from oslo_utils import importutils - -from neutron.plugins.plumgrid.plumgrid_plugin import plumgrid_plugin -from neutron.tests.unit import test_extension_security_group as ext_sg - - -PLUM_DRIVER = ('neutron.plugins.plumgrid.drivers.fake_plumlib.Plumlib') -FAKE_DIRECTOR = '1.1.1.1' -FAKE_PORT = '1234' -FAKE_USERNAME = 'fake_admin' -FAKE_PASSWORD = 'fake_password' -FAKE_TIMEOUT = '0' - - -class SecurityGroupsTestCase(ext_sg.SecurityGroupDBTestCase): - _plugin_name = ('neutron.plugins.plumgrid.plumgrid_plugin.' - 'plumgrid_plugin.NeutronPluginPLUMgridV2') - - def setUp(self): - def mocked_plumlib_init(self): - director_plumgrid = FAKE_DIRECTOR - director_port = FAKE_PORT - director_username = FAKE_USERNAME - director_password = FAKE_PASSWORD - timeout = FAKE_TIMEOUT - self._plumlib = importutils.import_object(PLUM_DRIVER) - self._plumlib.director_conn(director_plumgrid, - director_port, timeout, - director_username, - director_password) - - with mock.patch.object(plumgrid_plugin.NeutronPluginPLUMgridV2, - 'plumgrid_init', new=mocked_plumlib_init): - super(SecurityGroupsTestCase, self).setUp(self._plugin_name) - - def tearDown(self): - super(SecurityGroupsTestCase, self).tearDown() - - -class TestSecurityGroups(ext_sg.TestSecurityGroups, SecurityGroupsTestCase): - - pass diff --git a/neutron/tests/unit/plumgrid/test_plumgrid_plugin.py b/neutron/tests/unit/plumgrid/test_plumgrid_plugin.py deleted file mode 100644 index 3e7abb002..000000000 --- a/neutron/tests/unit/plumgrid/test_plumgrid_plugin.py +++ /dev/null @@ -1,221 +0,0 @@ -# Copyright 2013 PLUMgrid, Inc. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -Test cases for Neutron PLUMgrid Plug-in -""" - -import mock -from oslo_utils import importutils - -from neutron import context -from neutron.extensions import portbindings -from neutron.extensions import providernet as provider -from neutron import manager -from neutron.plugins.plumgrid.plumgrid_plugin import plumgrid_plugin -from neutron.tests.unit import _test_extension_portbindings as test_bindings -from neutron.tests.unit import test_db_plugin as test_plugin - - -PLUM_DRIVER = ('neutron.plugins.plumgrid.drivers.fake_plumlib.Plumlib') -FAKE_DIRECTOR = '1.1.1.1' -FAKE_PORT = '1234' -FAKE_USERNAME = 'fake_admin' -FAKE_PASSWORD = 'fake_password' -FAKE_TIMEOUT = '0' - - -class PLUMgridPluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase): - _plugin_name = ('neutron.plugins.plumgrid.plumgrid_plugin.' - 'plumgrid_plugin.NeutronPluginPLUMgridV2') - - def setUp(self): - def mocked_plumlib_init(self): - director_plumgrid = FAKE_DIRECTOR - director_port = FAKE_PORT - director_username = FAKE_USERNAME - director_password = FAKE_PASSWORD - timeout = FAKE_TIMEOUT - self._plumlib = importutils.import_object(PLUM_DRIVER) - self._plumlib.director_conn(director_plumgrid, - director_port, timeout, - director_username, - director_password) - - with mock.patch.object(plumgrid_plugin.NeutronPluginPLUMgridV2, - 'plumgrid_init', new=mocked_plumlib_init): - super(PLUMgridPluginV2TestCase, self).setUp(self._plugin_name) - - def tearDown(self): - super(PLUMgridPluginV2TestCase, self).tearDown() - - -class TestPlumgridPluginNetworksV2(test_plugin.TestNetworksV2, - PLUMgridPluginV2TestCase): - pass - - -class TestPlumgridV2HTTPResponse(test_plugin.TestV2HTTPResponse, - PLUMgridPluginV2TestCase): - pass - - -class TestPlumgridPluginPortsV2(test_plugin.TestPortsV2, - PLUMgridPluginV2TestCase): - def test_range_allocation(self): - self.skipTest("Plugin does not support Neutron allocation process") - - -class TestPlumgridPluginSubnetsV2(test_plugin.TestSubnetsV2, - PLUMgridPluginV2TestCase): - _unsupported = ( - 'test_create_subnet_default_gw_conflict_allocation_pool_returns_409', - 'test_create_subnet_defaults', 'test_create_subnet_gw_values', - 'test_create_subnet_ipv6_gw_values', - 'test_update_subnet_gateway_in_allocation_pool_returns_409', - 'test_update_subnet_allocation_pools', - 'test_update_subnet_allocation_pools_invalid_pool_for_cidr') - - def setUp(self): - if self._testMethodName in self._unsupported: - self.skipTest("Plugin does not support Neutron allocation process") - super(TestPlumgridPluginSubnetsV2, self).setUp() - - def test_subnet_admin_delete(self): - plugin = manager.NeutronManager.get_plugin() - admin_context = context.get_admin_context() - tenant_context = context.Context('', 'not_admin') - - network1 = self._fake_network('network1') - network1_ret = plugin.create_network(tenant_context, network1) - - subnet1 = self._fake_subnet(network1_ret['id']) - plugin.create_subnet(tenant_context, subnet1) - net_db = plugin.get_network(admin_context, network1_ret['id']) - - self.assertEqual(network1_ret['tenant_id'], net_db["tenant_id"]) - - def _fake_network(self, name): - data = {'network': {'name': name, - 'admin_state_up': False, - 'shared': False, - 'router:external': [], - 'provider:network_type': None, - 'provider:segmentation_id': None, - 'provider:physical_network': None}} - return data - - def _fake_subnet(self, net_id): - allocation_pools = [{'start': '10.0.0.2', - 'end': '10.0.0.254'}] - return {'subnet': {'name': net_id, - 'network_id': net_id, - 'gateway_ip': '10.0.0.1', - 'dns_nameservers': ['10.0.0.2'], - 'host_routes': [], - 'cidr': '10.0.0.0/24', - 'allocation_pools': allocation_pools, - 'enable_dhcp': True, - 'ip_version': 4}} - - -class TestPlumgridPluginPortBinding(PLUMgridPluginV2TestCase, - test_bindings.PortBindingsTestCase): - VIF_TYPE = portbindings.VIF_TYPE_IOVISOR - HAS_PORT_FILTER = True - - def setUp(self): - super(TestPlumgridPluginPortBinding, self).setUp() - - -class TestPlumgridNetworkAdminState(PLUMgridPluginV2TestCase): - def test_network_admin_state(self): - name = 'network_test' - admin_status_up = False - tenant_id = 'tenant_test' - network = {'network': {'name': name, - 'admin_state_up': admin_status_up, - 'tenant_id': tenant_id}} - plugin = manager.NeutronManager.get_plugin() - self.assertEqual(plugin._network_admin_state(network), network) - - -class TestPlumgridAllocationPool(PLUMgridPluginV2TestCase): - def test_allocate_pools_for_subnet(self): - cidr = '10.0.0.0/24' - gateway_ip = '10.0.0.254' - subnet = {'gateway_ip': gateway_ip, - 'cidr': cidr, - 'ip_version': 4} - allocation_pool = [{"start": '10.0.0.2', - "end": '10.0.0.253'}] - context = None - plugin = manager.NeutronManager.get_plugin() - pool = plugin._allocate_pools_for_subnet(context, subnet) - self.assertEqual(allocation_pool, pool) - - def test_conflict_dhcp_gw_ip(self): - cidr = '10.0.0.0/24' - gateway_ip = '10.0.0.1' - subnet = {'gateway_ip': gateway_ip, - 'cidr': cidr, - 'ip_version': 4} - allocation_pool = [{"start": '10.0.0.3', - "end": '10.0.0.254'}] - context = None - plugin = manager.NeutronManager.get_plugin() - pool = plugin._allocate_pools_for_subnet(context, subnet) - self.assertEqual(allocation_pool, pool) - - -class TestPlumgridProvidernet(PLUMgridPluginV2TestCase): - - def test_create_provider_network(self): - tenant_id = 'admin' - data = {'network': {'name': 'net1', - 'admin_state_up': True, - 'tenant_id': tenant_id, - provider.NETWORK_TYPE: 'vlan', - provider.SEGMENTATION_ID: 3333, - provider.PHYSICAL_NETWORK: 'phy3333'}} - - network_req = self.new_create_request('networks', data, self.fmt) - net = self.deserialize(self.fmt, network_req.get_response(self.api)) - plumlib = importutils.import_object(PLUM_DRIVER) - plumlib.create_network(tenant_id, net, data) - self.assertEqual(net['network'][provider.NETWORK_TYPE], 'vlan') - self.assertEqual(net['network'][provider.SEGMENTATION_ID], 3333) - self.assertEqual(net['network'][provider.PHYSICAL_NETWORK], 'phy3333') - - -class TestDisassociateFloatingIP(PLUMgridPluginV2TestCase): - - def test_disassociate_floating_ip(self): - port_id = "abcdefgh" - tenant_id = "94eb42de4e331" - fip_net_id = "b843d18245678" - fip_addr = "10.0.3.44" - fip_id = "e623679734051" - fip = {"router_id": "94eb42de4e331", - "tenant_id": tenant_id, - "floating_network_id": fip_net_id, - "fixed_ip_address": "192.168.8.2", - "floating_ip_address": fip_addr, - "port_id": port_id, - "id": fip_id} - plumlib = importutils.import_object(PLUM_DRIVER) - fip_res = plumlib.disassociate_floatingips(fip, port_id) - self.assertEqual(fip_res["id"], fip_id) - self.assertEqual(fip_res["floating_ip_address"], fip_addr) - self.assertEqual(fip_res["floating_network_id"], fip_net_id)