Add 'allowed address pairs' option to 'port create/set/unset'

This patch adds '--allowed-addres-pair' and '--no-allowed-address-pair'
options to 'port create', 'port set' and 'port unset' commands.

Partial-Bug: #1612136
Closes-Bug: #1638265
Partially-Implements: blueprint network-commands-options
Co-Authored-By: Ha Van Tu <tuhv@vn.fujitsu.com>
Change-Id: I08d2269950467a8972a0d0110ed61f5cc7f5ca45
This commit is contained in:
Nguyen Phuong An 2016-08-17 11:25:13 +07:00 committed by Ha Van Tu
parent 3ab94614c2
commit 8bcfb824c8
4 changed files with 310 additions and 4 deletions

View File

@ -29,6 +29,7 @@ Create new port
[--mac-address <mac-address>]
[--security-group <security-group> | --no-security-group]
[--dns-name <dns-name>]
[--allowed-address ip-address=<ip-address>[,mac-address=<mac-address>]]
[--project <project> [--project-domain <project-domain>]]
[--enable-port-security | --disable-port-security]
<name>
@ -97,6 +98,12 @@ Create new port
Set DNS name to this port
(requires DNS integration extension)
.. option:: --allowed-address ip-address=<ip-address>[,mac-address=<mac-address>]
Add allowed-address pair associated with this port:
ip-address=<ip-address>[,mac-address=<mac-address>]
(repeat option to set multiple allowed-address pairs)
.. option:: --project <project>
Owner's project (name or ID)
@ -199,6 +206,8 @@ Set port properties
[--no-security-group]
[--enable-port-security | --disable-port-security]
[--dns-name <dns-name>]
[--allowed-address ip-address=<ip-address>[,mac-address=<mac-address>]]
[--no-allowed-address]
<port>
.. option:: --description <description>
@ -281,6 +290,19 @@ Set port properties
Set DNS name to this port
(requires DNS integration extension)
.. option:: --allowed-address ip-address=<ip-address>[,mac-address=<mac-address>]
Add allowed-address pair associated with this port:
ip-address=<ip-address>[,mac-address=<mac-address>]
(repeat option to set multiple allowed-address pairs)
.. option:: --no-allowed-address
Clear existing allowed-address pairs associated
with this port.
(Specify both --allowed-address and --no-allowed-address
to overwrite the current allowed-address pairs)
.. _port_set-port:
.. describe:: <port>
@ -314,6 +336,7 @@ Unset port properties
[--fixed-ip subnet=<subnet>,ip-address=<ip-address> [...]]
[--binding-profile <binding-profile-key> [...]]
[--security-group <security-group> [...]]
[--allowed-address ip-address=<ip-address>[,mac-address=<mac-address>] [...]]
<port>
.. option:: --fixed-ip subnet=<subnet>,ip-address=<ip-address>
@ -332,6 +355,12 @@ Unset port properties
Security group which should be removed from this port (name or ID)
(repeat option to unset multiple security groups)
.. option:: --allowed-address ip-address=<ip-address>[,mac-address=<mac-address>]
Desired allowed-address pair which should be removed from this port:
ip-address=<ip-address>[,mac-address=<mac-address>]
(repeat option to unset multiple allowed-address pairs)
.. _port_unset-port:
.. describe:: <port>

View File

@ -246,6 +246,17 @@ def _add_updatable_args(parser):
# TODO(abhiraut): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
def _convert_address_pairs(parsed_args):
ops = []
for opt in parsed_args.allowed_address_pairs:
addr = {}
addr['ip_address'] = opt['ip-address']
if 'mac-address' in opt:
addr['mac_address'] = opt['mac-address']
ops.append(addr)
return ops
class CreatePort(command.ShowOne):
_description = _("Create a new port")
@ -305,7 +316,7 @@ class CreatePort(command.ShowOne):
help=_("Name of this port")
)
# TODO(singhj): Add support for extended options:
# qos,dhcp, address pairs
# qos,dhcp
secgroups = parser.add_mutually_exclusive_group()
secgroups.add_argument(
'--security-group',
@ -332,7 +343,17 @@ class CreatePort(command.ShowOne):
action='store_true',
help=_("Disable port security for this port")
)
parser.add_argument(
'--allowed-address',
metavar='ip-address=<ip-address>[,mac-address=<mac-address>]',
action=parseractions.MultiKeyValueAction,
dest='allowed_address_pairs',
required_keys=['ip-address'],
optional_keys=['mac-address'],
help=_("Add allowed-address pair associated with this port: "
"ip-address=<ip-address>[,mac-address=<mac-address>] "
"(repeat option to set multiple allowed-address pairs)")
)
return parser
def take_action(self, parsed_args):
@ -349,6 +370,9 @@ class CreatePort(command.ShowOne):
for sg in parsed_args.security_groups]
if parsed_args.no_security_group:
attrs['security_groups'] = []
if parsed_args.allowed_address_pairs:
attrs['allowed_address_pairs'] = (
_convert_address_pairs(parsed_args))
obj = client.create_port(**attrs)
display_columns, columns = _get_columns(obj)
@ -569,7 +593,26 @@ class SetPort(command.Command):
action='store_true',
help=_("Disable port security for this port")
)
parser.add_argument(
'--allowed-address',
metavar='ip-address=<ip-address>[,mac-address=<mac-address>]',
action=parseractions.MultiKeyValueAction,
dest='allowed_address_pairs',
required_keys=['ip-address'],
optional_keys=['mac-address'],
help=_("Add allowed-address pair associated with this port: "
"ip-address=<ip-address>[,mac-address=<mac-address>] "
"(repeat option to set multiple allowed-address pairs)")
)
parser.add_argument(
'--no-allowed-address',
dest='no_allowed_address_pair',
action='store_true',
help=_("Clear existing allowed-address pairs associated"
"with this port."
"(Specify both --allowed-address and --no-allowed-address"
"to overwrite the current allowed-address pairs)")
)
return parser
def take_action(self, parsed_args):
@ -609,6 +652,19 @@ class SetPort(command.Command):
elif parsed_args.no_security_group:
attrs['security_groups'] = []
if (parsed_args.allowed_address_pairs and
parsed_args.no_allowed_address_pair):
attrs['allowed_address_pairs'] = (
_convert_address_pairs(parsed_args))
elif parsed_args.allowed_address_pairs:
attrs['allowed_address_pairs'] = (
[addr for addr in obj.allowed_address_pairs if addr] +
_convert_address_pairs(parsed_args))
elif parsed_args.no_allowed_address_pair:
attrs['allowed_address_pairs'] = []
client.update_port(obj, **attrs)
@ -669,6 +725,19 @@ class UnsetPort(command.Command):
metavar="<port>",
help=_("Port to modify (name or ID)")
)
parser.add_argument(
'--allowed-address',
metavar='ip-address=<ip-address>[,mac-address=<mac-address>]',
action=parseractions.MultiKeyValueAction,
dest='allowed_address_pairs',
required_keys=['ip-address'],
optional_keys=['mac-address'],
help=_("Desired allowed-address pair which should be removed "
"from this port: ip-address=<ip-address> "
"[,mac-address=<mac-address>] (repeat option to set "
"multiple allowed-address pairs)")
)
return parser
def take_action(self, parsed_args):
@ -680,6 +749,7 @@ class UnsetPort(command.Command):
tmp_fixed_ips = copy.deepcopy(obj.fixed_ips)
tmp_binding_profile = copy.deepcopy(obj.binding_profile)
tmp_secgroups = copy.deepcopy(obj.security_groups)
tmp_addr_pairs = copy.deepcopy(obj.allowed_address_pairs)
_prepare_fixed_ips(self.app.client_manager, parsed_args)
attrs = {}
if parsed_args.fixed_ip:
@ -708,6 +778,14 @@ class UnsetPort(command.Command):
msg = _("Port does not contain security group %s") % sg
raise exceptions.CommandError(msg)
attrs['security_groups'] = tmp_secgroups
if parsed_args.allowed_address_pairs:
try:
for addr in _convert_address_pairs(parsed_args):
tmp_addr_pairs.remove(addr)
except ValueError:
msg = _("Port does not contain allowed-address-pair %s") % addr
raise exceptions.CommandError(msg)
attrs['allowed_address_pairs'] = tmp_addr_pairs
if attrs:
client.update_port(obj, **attrs)

View File

@ -216,7 +216,7 @@ class TestCreatePort(TestPort):
'test-port',
]
verifylist = [
('network', self._port.network_id,),
('network', self._port.network_id),
('enable', True),
('binding_profile', {'parent_name': 'fake_parent', 'tag': 42}),
('name', 'test-port'),
@ -351,6 +351,74 @@ class TestCreatePort(TestPort):
self.assertEqual(ref_columns, columns)
self.assertEqual(ref_data, data)
def test_create_port_with_allowed_address_pair_ipaddr(self):
pairs = [{'ip_address': '192.168.1.123'},
{'ip_address': '192.168.1.45'}]
arglist = [
'--network', self._port.network_id,
'--allowed-address', 'ip-address=192.168.1.123',
'--allowed-address', 'ip-address=192.168.1.45',
'test-port',
]
verifylist = [
('network', self._port.network_id),
('enable', True),
('allowed_address_pairs', [{'ip-address': '192.168.1.123'},
{'ip-address': '192.168.1.45'}]),
('name', 'test-port'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = (self.cmd.take_action(parsed_args))
self.network.create_port.assert_called_once_with(**{
'admin_state_up': True,
'network_id': self._port.network_id,
'allowed_address_pairs': pairs,
'name': 'test-port',
})
ref_columns, ref_data = self._get_common_cols_data(self._port)
self.assertEqual(ref_columns, columns)
self.assertEqual(ref_data, data)
def test_create_port_with_allowed_address_pair(self):
pairs = [{'ip_address': '192.168.1.123',
'mac_address': 'aa:aa:aa:aa:aa:aa'},
{'ip_address': '192.168.1.45',
'mac_address': 'aa:aa:aa:aa:aa:b1'}]
arglist = [
'--network', self._port.network_id,
'--allowed-address',
'ip-address=192.168.1.123,mac-address=aa:aa:aa:aa:aa:aa',
'--allowed-address',
'ip-address=192.168.1.45,mac-address=aa:aa:aa:aa:aa:b1',
'test-port',
]
verifylist = [
('network', self._port.network_id),
('enable', True),
('allowed_address_pairs', [{'ip-address': '192.168.1.123',
'mac-address': 'aa:aa:aa:aa:aa:aa'},
{'ip-address': '192.168.1.45',
'mac-address': 'aa:aa:aa:aa:aa:b1'}]),
('name', 'test-port'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = (self.cmd.take_action(parsed_args))
self.network.create_port.assert_called_once_with(**{
'admin_state_up': True,
'network_id': self._port.network_id,
'allowed_address_pairs': pairs,
'name': 'test-port',
})
ref_columns, ref_data = self._get_common_cols_data(self._port)
self.assertEqual(ref_columns, columns)
self.assertEqual(ref_data, data)
def test_create_port_security_enabled(self):
arglist = [
'--network', self._port.network_id,
@ -996,6 +1064,91 @@ class TestSetPort(TestPort):
self.network.update_port.assert_called_once_with(_testport, **attrs)
self.assertIsNone(result)
def test_set_allowed_address_pair(self):
arglist = [
'--allowed-address', 'ip-address=192.168.1.123',
self._port.name,
]
verifylist = [
('allowed_address_pairs', [{'ip-address': '192.168.1.123'}]),
('port', self._port.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
attrs = {
'allowed_address_pairs': [{'ip_address': '192.168.1.123'}],
}
self.network.update_port.assert_called_once_with(self._port, **attrs)
self.assertIsNone(result)
def test_append_allowed_address_pair(self):
_testport = network_fakes.FakePort.create_one_port(
{'allowed_address_pairs': [{'ip_address': '192.168.1.123'}]})
self.network.find_port = mock.Mock(return_value=_testport)
arglist = [
'--allowed-address', 'ip-address=192.168.1.45',
_testport.name,
]
verifylist = [
('allowed_address_pairs', [{'ip-address': '192.168.1.45'}]),
('port', _testport.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
attrs = {
'allowed_address_pairs': [{'ip_address': '192.168.1.123'},
{'ip_address': '192.168.1.45'}],
}
self.network.update_port.assert_called_once_with(_testport, **attrs)
self.assertIsNone(result)
def test_overwrite_allowed_address_pair(self):
_testport = network_fakes.FakePort.create_one_port(
{'allowed_address_pairs': [{'ip_address': '192.168.1.123'}]})
self.network.find_port = mock.Mock(return_value=_testport)
arglist = [
'--allowed-address', 'ip-address=192.168.1.45',
'--no-allowed-address',
_testport.name,
]
verifylist = [
('allowed_address_pairs', [{'ip-address': '192.168.1.45'}]),
('no_allowed_address_pair', True),
('port', _testport.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
attrs = {
'allowed_address_pairs': [{'ip_address': '192.168.1.45'}],
}
self.network.update_port.assert_called_once_with(_testport, **attrs)
self.assertIsNone(result)
def test_set_no_allowed_address_pairs(self):
arglist = [
'--no-allowed-address',
self._port.name,
]
verifylist = [
('no_allowed_address_pair', True),
('port', self._port.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
attrs = {
'allowed_address_pairs': [],
}
self.network.update_port.assert_called_once_with(self._port, **attrs)
self.assertIsNone(result)
def test_port_security_enabled(self):
arglist = [
'--enable-port-security',
@ -1192,3 +1345,42 @@ class TestUnsetPort(TestPort):
self.assertRaises(exceptions.CommandError,
self.cmd.take_action,
parsed_args)
def test_unset_port_allowed_address_pair(self):
_fake_port = network_fakes.FakePort.create_one_port(
{'allowed_address_pairs': [{'ip_address': '192.168.1.123'}]})
self.network.find_port = mock.Mock(return_value=_fake_port)
arglist = [
'--allowed-address', 'ip-address=192.168.1.123',
_fake_port.name,
]
verifylist = [
('allowed_address_pairs', [{'ip-address': '192.168.1.123'}]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
attrs = {
'allowed_address_pairs': [],
}
self.network.update_port.assert_called_once_with(_fake_port, **attrs)
self.assertIsNone(result)
def test_unset_port_allowed_address_pair_not_existent(self):
_fake_port = network_fakes.FakePort.create_one_port(
{'allowed_address_pairs': [{'ip_address': '192.168.1.123'}]})
self.network.find_port = mock.Mock(return_value=_fake_port)
arglist = [
'--allowed-address', 'ip-address=192.168.1.45',
_fake_port.name,
]
verifylist = [
('allowed_address_pairs', [{'ip-address': '192.168.1.45'}]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.assertRaises(exceptions.CommandError,
self.cmd.take_action,
parsed_args)

View File

@ -0,0 +1,7 @@
---
features:
- |
Add ``--allowed-address`` option to ``port create``, ``port set`` and
``port unset`` commands. Also add ``--no-allowed-address`` option to
``port create`` and ``port set`` commands.
[Bug `1612136 <https://bugs.launchpad.net/python-openstackclient/+bug/1612136>`_]