summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/source/command-objects/port.rst29
-rw-r--r--openstackclient/network/v2/port.py59
-rw-r--r--openstackclient/tests/network/v2/test_port.py78
-rw-r--r--releasenotes/notes/add-port-unset-command-8bdaf1fa9c593374.yaml6
-rw-r--r--setup.cfg1
5 files changed, 173 insertions, 0 deletions
diff --git a/doc/source/command-objects/port.rst b/doc/source/command-objects/port.rst
index 9d93ee62..4d7b95b4 100644
--- a/doc/source/command-objects/port.rst
+++ b/doc/source/command-objects/port.rst
@@ -215,3 +215,32 @@ Display port details
.. describe:: <port>
Port to display (name or ID)
+
+port unset
+----------
+
+Unset port properties
+
+.. program:: port unset
+.. code:: bash
+
+ os port unset
+ [--fixed-ip subnet=<subnet>,ip-address=<ip-address> [...]]
+ [--binding-profile <binding-profile-key> [...]]
+ <port>
+
+.. option:: --fixed-ip subnet=<subnet>,ip-address=<ip-address>
+
+ Desired IP and/or subnet (name or ID) which should be removed
+ from this port: subnet=<subnet>,ip-address=<ip-address>
+ (repeat option to unset multiple fixed IP addresses)
+
+.. option:: --binding-profile <binding-profile-key>
+
+ Desired key which should be removed from binding-profile
+ (repeat option to unset multiple binding:profile data)
+
+.. _port_unset-port:
+.. describe:: <port>
+
+ Port to modify (name or ID)
diff --git a/openstackclient/network/v2/port.py b/openstackclient/network/v2/port.py
index 2a069f09..05c5a012 100644
--- a/openstackclient/network/v2/port.py
+++ b/openstackclient/network/v2/port.py
@@ -14,6 +14,7 @@
"""Port action implementations"""
import argparse
+import copy
import json
import logging
@@ -485,3 +486,61 @@ class ShowPort(command.ShowOne):
columns = _get_columns(obj)
data = utils.get_item_properties(obj, columns, formatters=_formatters)
return (columns, data)
+
+
+class UnsetPort(command.Command):
+ """Unset port properties"""
+
+ def get_parser(self, prog_name):
+ parser = super(UnsetPort, self).get_parser(prog_name)
+ parser.add_argument(
+ '--fixed-ip',
+ metavar='subnet=<subnet>,ip-address=<ip-address>',
+ action=parseractions.MultiKeyValueAction,
+ optional_keys=['subnet', 'ip-address'],
+ help=_("Desired IP and/or subnet (name or ID) which should be "
+ "removed from this port: subnet=<subnet>,"
+ "ip-address=<ip-address> (repeat option to unset multiple "
+ "fixed IP addresses)"))
+
+ parser.add_argument(
+ '--binding-profile',
+ metavar='<binding-profile-key>',
+ action='append',
+ help=_("Desired key which should be removed from binding:profile"
+ "(repeat option to unset multiple binding:profile data)"))
+ parser.add_argument(
+ 'port',
+ metavar="<port>",
+ help=_("Port to modify (name or ID)")
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ client = self.app.client_manager.network
+ obj = client.find_port(parsed_args.port, ignore_missing=False)
+ # SDK ignores update() if it recieves a modified obj and attrs
+ # To handle the same tmp_obj is created in all take_action of
+ # Unset* classes
+ tmp_fixed_ips = copy.deepcopy(obj.fixed_ips)
+ tmp_binding_profile = copy.deepcopy(obj.binding_profile)
+ _prepare_fixed_ips(self.app.client_manager, parsed_args)
+ attrs = {}
+ if parsed_args.fixed_ip:
+ try:
+ for ip in parsed_args.fixed_ip:
+ tmp_fixed_ips.remove(ip)
+ except ValueError:
+ msg = _("Port does not contain fixed-ip %s") % ip
+ raise exceptions.CommandError(msg)
+ attrs['fixed_ips'] = tmp_fixed_ips
+ if parsed_args.binding_profile:
+ try:
+ for key in parsed_args.binding_profile:
+ del tmp_binding_profile[key]
+ except KeyError:
+ msg = _("Port does not contain binding-profile %s") % key
+ raise exceptions.CommandError(msg)
+ attrs['binding:profile'] = tmp_binding_profile
+ if attrs:
+ client.update_port(obj, **attrs)
diff --git a/openstackclient/tests/network/v2/test_port.py b/openstackclient/tests/network/v2/test_port.py
index 871fe872..a1cecec8 100644
--- a/openstackclient/tests/network/v2/test_port.py
+++ b/openstackclient/tests/network/v2/test_port.py
@@ -616,3 +616,81 @@ class TestShowPort(TestPort):
ref_columns, ref_data = self._get_common_cols_data(self._port)
self.assertEqual(ref_columns, columns)
self.assertEqual(ref_data, data)
+
+
+class TestUnsetPort(TestPort):
+
+ def setUp(self):
+ super(TestUnsetPort, self).setUp()
+ self._testport = network_fakes.FakePort.create_one_port(
+ {'fixed_ips': [{'subnet_id': '042eb10a-3a18-4658-ab-cf47c8d03152',
+ 'ip_address': '0.0.0.1'},
+ {'subnet_id': '042eb10a-3a18-4658-ab-cf47c8d03152',
+ 'ip_address': '1.0.0.0'}],
+ 'binding:profile': {'batman': 'Joker', 'Superman': 'LexLuthor'}})
+ self.fake_subnet = network_fakes.FakeSubnet.create_one_subnet(
+ {'id': '042eb10a-3a18-4658-ab-cf47c8d03152'})
+ self.network.find_subnet = mock.Mock(return_value=self.fake_subnet)
+ self.network.find_port = mock.Mock(return_value=self._testport)
+ self.network.update_port = mock.Mock(return_value=None)
+ # Get the command object to test
+ self.cmd = port.UnsetPort(self.app, self.namespace)
+
+ def test_unset_port_parameters(self):
+ arglist = [
+ '--fixed-ip',
+ 'subnet=042eb10a-3a18-4658-ab-cf47c8d03152,ip-address=1.0.0.0',
+ '--binding-profile', 'Superman',
+ self._testport.name,
+ ]
+ verifylist = [
+ ('fixed_ip', [{
+ 'subnet': '042eb10a-3a18-4658-ab-cf47c8d03152',
+ 'ip-address': '1.0.0.0'}]),
+ ('binding_profile', ['Superman']),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'fixed_ips': [{
+ 'subnet_id': '042eb10a-3a18-4658-ab-cf47c8d03152',
+ 'ip_address': '0.0.0.1'}],
+ 'binding:profile': {'batman': 'Joker'}
+ }
+ self.network.update_port.assert_called_once_with(
+ self._testport, **attrs)
+ self.assertIsNone(result)
+
+ def test_unset_port_fixed_ip_not_existent(self):
+ arglist = [
+ '--fixed-ip', 'ip-address=1.0.0.1',
+ '--binding-profile', 'Superman',
+ self._testport.name,
+ ]
+ verifylist = [
+ ('fixed_ip', [{'ip-address': '1.0.0.1'}]),
+ ('binding_profile', ['Superman']),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
+
+ def test_unset_port_binding_profile_not_existent(self):
+ arglist = [
+ '--fixed-ip', 'ip-address=1.0.0.0',
+ '--binding-profile', 'Neo',
+ self._testport.name,
+ ]
+ verifylist = [
+ ('fixed_ip', [{'ip-address': '1.0.0.0'}]),
+ ('binding_profile', ['Neo']),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
diff --git a/releasenotes/notes/add-port-unset-command-8bdaf1fa9c593374.yaml b/releasenotes/notes/add-port-unset-command-8bdaf1fa9c593374.yaml
new file mode 100644
index 00000000..f4e547b9
--- /dev/null
+++ b/releasenotes/notes/add-port-unset-command-8bdaf1fa9c593374.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - |
+ Add a new command ``port unset`` to clear the information
+ of fixed-ip and binding-profile from the port.
+ [ Blueprint `network-property-unset <https://blueprints.launchpad.net/python-openstackclient/+spec/network-property-unset>`_]
diff --git a/setup.cfg b/setup.cfg
index d41cdc01..a129436e 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -355,6 +355,7 @@ openstack.network.v2 =
port_list = openstackclient.network.v2.port:ListPort
port_set = openstackclient.network.v2.port:SetPort
port_show = openstackclient.network.v2.port:ShowPort
+ port_unset = openstackclient.network.v2.port:UnsetPort
router_add_port = openstackclient.network.v2.router:AddPortToRouter
router_add_subnet = openstackclient.network.v2.router:AddSubnetToRouter