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>] [--mac-address <mac-address>]
[--security-group <security-group> | --no-security-group] [--security-group <security-group> | --no-security-group]
[--dns-name <dns-name>] [--dns-name <dns-name>]
[--allowed-address ip-address=<ip-address>[,mac-address=<mac-address>]]
[--project <project> [--project-domain <project-domain>]] [--project <project> [--project-domain <project-domain>]]
[--enable-port-security | --disable-port-security] [--enable-port-security | --disable-port-security]
<name> <name>
@ -97,6 +98,12 @@ Create new port
Set DNS name to this port Set DNS name to this port
(requires DNS integration extension) (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> .. option:: --project <project>
Owner's project (name or ID) Owner's project (name or ID)
@ -199,6 +206,8 @@ Set port properties
[--no-security-group] [--no-security-group]
[--enable-port-security | --disable-port-security] [--enable-port-security | --disable-port-security]
[--dns-name <dns-name>] [--dns-name <dns-name>]
[--allowed-address ip-address=<ip-address>[,mac-address=<mac-address>]]
[--no-allowed-address]
<port> <port>
.. option:: --description <description> .. option:: --description <description>
@ -281,6 +290,19 @@ Set port properties
Set DNS name to this port Set DNS name to this port
(requires DNS integration extension) (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: .. _port_set-port:
.. describe:: <port> .. describe:: <port>
@ -314,6 +336,7 @@ Unset port properties
[--fixed-ip subnet=<subnet>,ip-address=<ip-address> [...]] [--fixed-ip subnet=<subnet>,ip-address=<ip-address> [...]]
[--binding-profile <binding-profile-key> [...]] [--binding-profile <binding-profile-key> [...]]
[--security-group <security-group> [...]] [--security-group <security-group> [...]]
[--allowed-address ip-address=<ip-address>[,mac-address=<mac-address>] [...]]
<port> <port>
.. option:: --fixed-ip subnet=<subnet>,ip-address=<ip-address> .. 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) Security group which should be removed from this port (name or ID)
(repeat option to unset multiple security groups) (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: .. _port_unset-port:
.. describe:: <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 # TODO(abhiraut): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0. # 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): class CreatePort(command.ShowOne):
_description = _("Create a new port") _description = _("Create a new port")
@ -305,7 +316,7 @@ class CreatePort(command.ShowOne):
help=_("Name of this port") help=_("Name of this port")
) )
# TODO(singhj): Add support for extended options: # TODO(singhj): Add support for extended options:
# qos,dhcp, address pairs # qos,dhcp
secgroups = parser.add_mutually_exclusive_group() secgroups = parser.add_mutually_exclusive_group()
secgroups.add_argument( secgroups.add_argument(
'--security-group', '--security-group',
@ -332,7 +343,17 @@ class CreatePort(command.ShowOne):
action='store_true', action='store_true',
help=_("Disable port security for this port") 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 return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -349,6 +370,9 @@ class CreatePort(command.ShowOne):
for sg in parsed_args.security_groups] for sg in parsed_args.security_groups]
if parsed_args.no_security_group: if parsed_args.no_security_group:
attrs['security_groups'] = [] attrs['security_groups'] = []
if parsed_args.allowed_address_pairs:
attrs['allowed_address_pairs'] = (
_convert_address_pairs(parsed_args))
obj = client.create_port(**attrs) obj = client.create_port(**attrs)
display_columns, columns = _get_columns(obj) display_columns, columns = _get_columns(obj)
@ -569,7 +593,26 @@ class SetPort(command.Command):
action='store_true', action='store_true',
help=_("Disable port security for this port") 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 return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -609,6 +652,19 @@ class SetPort(command.Command):
elif parsed_args.no_security_group: elif parsed_args.no_security_group:
attrs['security_groups'] = [] 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) client.update_port(obj, **attrs)
@ -669,6 +725,19 @@ class UnsetPort(command.Command):
metavar="<port>", metavar="<port>",
help=_("Port to modify (name or ID)") 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 return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -680,6 +749,7 @@ class UnsetPort(command.Command):
tmp_fixed_ips = copy.deepcopy(obj.fixed_ips) tmp_fixed_ips = copy.deepcopy(obj.fixed_ips)
tmp_binding_profile = copy.deepcopy(obj.binding_profile) tmp_binding_profile = copy.deepcopy(obj.binding_profile)
tmp_secgroups = copy.deepcopy(obj.security_groups) 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) _prepare_fixed_ips(self.app.client_manager, parsed_args)
attrs = {} attrs = {}
if parsed_args.fixed_ip: if parsed_args.fixed_ip:
@ -708,6 +778,14 @@ class UnsetPort(command.Command):
msg = _("Port does not contain security group %s") % sg msg = _("Port does not contain security group %s") % sg
raise exceptions.CommandError(msg) raise exceptions.CommandError(msg)
attrs['security_groups'] = tmp_secgroups 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: if attrs:
client.update_port(obj, **attrs) client.update_port(obj, **attrs)

View File

@ -216,7 +216,7 @@ class TestCreatePort(TestPort):
'test-port', 'test-port',
] ]
verifylist = [ verifylist = [
('network', self._port.network_id,), ('network', self._port.network_id),
('enable', True), ('enable', True),
('binding_profile', {'parent_name': 'fake_parent', 'tag': 42}), ('binding_profile', {'parent_name': 'fake_parent', 'tag': 42}),
('name', 'test-port'), ('name', 'test-port'),
@ -351,6 +351,74 @@ class TestCreatePort(TestPort):
self.assertEqual(ref_columns, columns) self.assertEqual(ref_columns, columns)
self.assertEqual(ref_data, data) 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): def test_create_port_security_enabled(self):
arglist = [ arglist = [
'--network', self._port.network_id, '--network', self._port.network_id,
@ -996,6 +1064,91 @@ class TestSetPort(TestPort):
self.network.update_port.assert_called_once_with(_testport, **attrs) self.network.update_port.assert_called_once_with(_testport, **attrs)
self.assertIsNone(result) 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): def test_port_security_enabled(self):
arglist = [ arglist = [
'--enable-port-security', '--enable-port-security',
@ -1192,3 +1345,42 @@ class TestUnsetPort(TestPort):
self.assertRaises(exceptions.CommandError, self.assertRaises(exceptions.CommandError,
self.cmd.take_action, self.cmd.take_action,
parsed_args) 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>`_]