diff --git a/quark/plugin.py b/quark/plugin.py index f08e23a..0b6a2aa 100644 --- a/quark/plugin.py +++ b/quark/plugin.py @@ -592,6 +592,27 @@ class Plugin(quantum_plugin_base_v2.QuantumPluginBaseV2): db_api.port_delete(context, port) self.net_driver.delete_port(context, backend_key) + def disassociate_port(self, context, id, ip_address_id): + """Disassociates a port from an IP address. + + : param context: quantum api request context + : param id: UUID representing the port to disassociate. + : param ip_address_id: UUID representing the IP address to + disassociate. + """ + LOG.info("disassociate_port %s for tenant %s ip_address_id %s" % + (id, context.tenant_id, ip_address_id)) + port = db_api.port_find(context, id=id, ip_address_id=[ip_address_id], + scope=db_api.ONE) + + if not port: + raise exceptions.PortNotFound(port_id=id, net_id='') + + port["ip_addresses"] = [address for address in port["ip_addresses"] + if address.id != ip_address_id] + + return self._make_port_dict(port) + def get_mac_address_ranges(self, context): LOG.info("get_mac_address_ranges for tenant %s" % context.tenant_id) ranges = db_api.mac_address_range_find(context) diff --git a/quark/tests/test_quark_plugin.py b/quark/tests/test_quark_plugin.py index 00ea90e..38df56d 100644 --- a/quark/tests/test_quark_plugin.py +++ b/quark/tests/test_quark_plugin.py @@ -23,6 +23,7 @@ from quantum.common import exceptions from quantum import context from quantum.db import api as db_api +from quark.db import api as quark_db_api from quark.db import models from quark import exceptions as quark_exceptions import quark.plugin @@ -752,6 +753,42 @@ class TestQuarkDeletePort(TestQuarkPlugin): self.plugin.delete_port(self.context, 1) +class TestQuarkDisassociatePort(TestQuarkPlugin): + @contextlib.contextmanager + def _stubs(self, port=None): + port_models = None + if port: + port_model = models.Port() + port_model.update(port) + port_models = port_model + + db_mod = "quark.db.api" + with mock.patch("%s.port_find" % db_mod) as port_find: + port_find.return_value = port_models + yield port_find + + def test_port_disassociate_port(self): + ip = dict(id=1, address=3232235876, address_readable="192.168.1.100", + subnet_id=1, network_id=2, version=4) + fixed_ips = [{"subnet_id": ip["subnet_id"], + "ip_address": ip["address_readable"]}] + port = dict(port=dict(network_id=1, tenant_id=self.context.tenant_id, + device_id=2, mac_address="AA:BB:CC:DD:EE:FF", + backend_key="foo", fixed_ips=fixed_ips)) + with self._stubs(port=port["port"]) as (port_find): + new_port = self.plugin.disassociate_port(self.context, 1, 1) + port_find.assert_called_with(self.context, + id=1, + ip_address_id=[1], + scope=quark_db_api.ONE) + self.assertEqual(new_port["fixed_ips"], []) + + def test_port_disassociate_port_not_found_fails(self): + with self._stubs(port=None): + with self.assertRaises(exceptions.PortNotFound): + self.plugin.disassociate_port(self.context, 1, 1) + + class TestQuarkGetMacAddressRanges(TestQuarkPlugin): @contextlib.contextmanager def _stubs(self, mac_range):