summaryrefslogtreecommitdiff
path: root/openstackclient
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2016-02-03 21:01:17 +0000
committerGerrit Code Review <review@openstack.org>2016-02-03 21:01:17 +0000
commit65f8845ea8eb67c4bd6731cf5733bc3071811dc2 (patch)
tree877245449d22e35018e5396b154ec1c336a5b1ec /openstackclient
parent66df8d1413004bbb2d225ff199767dab8696fd45 (diff)
parent981621e9845934c109c5e4abd9b2ab6828744346 (diff)
downloadpython-openstackclient-65f8845ea8eb67c4bd6731cf5733bc3071811dc2.tar.gz
Merge "Add "os port show" command"
Diffstat (limited to 'openstackclient')
-rw-r--r--openstackclient/common/utils.py10
-rw-r--r--openstackclient/network/v2/port.py56
-rw-r--r--openstackclient/tests/common/test_utils.py9
-rw-r--r--openstackclient/tests/network/v2/fakes.py42
-rw-r--r--openstackclient/tests/network/v2/test_port.py87
5 files changed, 200 insertions, 4 deletions
diff --git a/openstackclient/common/utils.py b/openstackclient/common/utils.py
index 1ca2bc57..a468629b 100644
--- a/openstackclient/common/utils.py
+++ b/openstackclient/common/utils.py
@@ -142,6 +142,16 @@ def format_list(data, separator=', '):
return separator.join(sorted(data))
+def format_list_of_dicts(data):
+ """Return a formatted string of key value pairs for each dict
+
+ :param data: a list of dicts
+ :rtype: a string formatted to key='value' with dicts separated by new line
+ """
+
+ return '\n'.join(format_dict(i) for i in data)
+
+
def get_field(item, field):
try:
if isinstance(item, dict):
diff --git a/openstackclient/network/v2/port.py b/openstackclient/network/v2/port.py
index 0d5b183e..46cb031f 100644
--- a/openstackclient/network/v2/port.py
+++ b/openstackclient/network/v2/port.py
@@ -14,6 +14,42 @@
"""Port action implementations"""
from openstackclient.common import command
+from openstackclient.common import utils
+
+
+def _format_admin_state(state):
+ return 'UP' if state else 'DOWN'
+
+
+_formatters = {
+ 'admin_state_up': _format_admin_state,
+ 'allowed_address_pairs': utils.format_list_of_dicts,
+ 'binding_profile': utils.format_dict,
+ 'binding_vif_details': utils.format_dict,
+ 'dns_assignment': utils.format_list_of_dicts,
+ 'extra_dhcp_opts': utils.format_list_of_dicts,
+ 'fixed_ips': utils.format_list_of_dicts,
+ 'security_groups': utils.format_list,
+}
+
+
+def _get_columns(item):
+ columns = item.keys()
+ if 'tenant_id' in columns:
+ columns.remove('tenant_id')
+ columns.append('project_id')
+ binding_columns = [
+ 'binding:host_id',
+ 'binding:profile',
+ 'binding:vif_details',
+ 'binding:vif_type',
+ 'binding:vnic_type',
+ ]
+ for binding_column in binding_columns:
+ if binding_column in columns:
+ columns.remove(binding_column)
+ columns.append(binding_column.replace('binding:', 'binding_', 1))
+ return sorted(columns)
class DeletePort(command.Command):
@@ -35,3 +71,23 @@ class DeletePort(command.Command):
for port in parsed_args.port:
res = client.find_port(port)
client.delete_port(res)
+
+
+class ShowPort(command.ShowOne):
+ """Display port details"""
+
+ def get_parser(self, prog_name):
+ parser = super(ShowPort, self).get_parser(prog_name)
+ parser.add_argument(
+ 'port',
+ metavar="<port>",
+ help="Port to display (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)
+ columns = _get_columns(obj)
+ data = utils.get_item_properties(obj, columns, formatters=_formatters)
+ return (tuple(columns), data)
diff --git a/openstackclient/tests/common/test_utils.py b/openstackclient/tests/common/test_utils.py
index 064ad417..62e3638e 100644
--- a/openstackclient/tests/common/test_utils.py
+++ b/openstackclient/tests/common/test_utils.py
@@ -348,6 +348,15 @@ class TestFindResource(test_utils.TestCase):
self.assertEqual(expected, utils.format_list(['a', 'b', 'c']))
self.assertEqual(expected, utils.format_list(['c', 'b', 'a']))
+ def test_format_list_of_dicts(self):
+ expected = "a='b', c='d'\ne='f'"
+ sorted_data = [{'a': 'b', 'c': 'd'}, {'e': 'f'}]
+ unsorted_data = [{'c': 'd', 'a': 'b'}, {'e': 'f'}]
+ self.assertEqual(expected, utils.format_list_of_dicts(sorted_data))
+ self.assertEqual(expected, utils.format_list_of_dicts(unsorted_data))
+ self.assertEqual('', utils.format_list_of_dicts([]))
+ self.assertEqual('', utils.format_list_of_dicts([{}]))
+
def test_format_list_separator(self):
expected = 'a\nb\nc'
actual_pre_sorted = utils.format_list(['a', 'b', 'c'], separator='\n')
diff --git a/openstackclient/tests/network/v2/fakes.py b/openstackclient/tests/network/v2/fakes.py
index 95c5aca6..812a64af 100644
--- a/openstackclient/tests/network/v2/fakes.py
+++ b/openstackclient/tests/network/v2/fakes.py
@@ -172,15 +172,31 @@ class FakePort(object):
:param Dictionary methods:
A dictionary with all methods
:return:
- A FakeResource object, with id, name, admin_state_up,
- status, tenant_id
+ A FakeResource object, with id, name, etc.
"""
+
# Set default attributes.
port_attrs = {
+ 'admin_state_up': True,
+ 'allowed_address_pairs': [{}],
+ 'binding:host_id': 'binding-host-id-' + uuid.uuid4().hex,
+ 'binding:profile': {},
+ 'binding:vif_details': {},
+ 'binding:vif_type': 'ovs',
+ 'binding:vnic_type': 'normal',
+ 'device_id': 'device-id-' + uuid.uuid4().hex,
+ 'device_owner': 'compute:nova',
+ 'dns_assignment': [{}],
+ 'dns_name': 'dns-name-' + uuid.uuid4().hex,
+ 'extra_dhcp_opts': [{}],
+ 'fixed_ips': [{}],
'id': 'port-id-' + uuid.uuid4().hex,
+ 'mac_address': 'fa:16:3e:a9:4e:72',
'name': 'port-name-' + uuid.uuid4().hex,
+ 'network_id': 'network-id-' + uuid.uuid4().hex,
+ 'port_security_enabled': True,
+ 'security_groups': [],
'status': 'ACTIVE',
- 'admin_state_up': True,
'tenant_id': 'project-id-' + uuid.uuid4().hex,
}
@@ -188,7 +204,16 @@ class FakePort(object):
port_attrs.update(attrs)
# Set default methods.
- port_methods = {}
+ port_methods = {
+ 'keys': ['admin_state_up', 'allowed_address_pairs',
+ 'binding:host_id', 'binding:profile',
+ 'binding:vif_details', 'binding:vif_type',
+ 'binding:vnic_type', 'device_id', 'device_owner',
+ 'dns_assignment', 'dns_name', 'extra_dhcp_opts',
+ 'fixed_ips', 'id', 'mac_address', 'name',
+ 'network_id', 'port_security_enabled',
+ 'security_groups', 'status', 'tenant_id'],
+ }
# Overwrite default methods.
port_methods.update(methods)
@@ -196,6 +221,15 @@ class FakePort(object):
port = fakes.FakeResource(info=copy.deepcopy(port_attrs),
methods=copy.deepcopy(port_methods),
loaded=True)
+
+ # Set attributes with special mappings.
+ port.project_id = port_attrs['tenant_id']
+ port.binding_host_id = port_attrs['binding:host_id']
+ port.binding_profile = port_attrs['binding:profile']
+ port.binding_vif_details = port_attrs['binding:vif_details']
+ port.binding_vif_type = port_attrs['binding:vif_type']
+ port.binding_vnic_type = port_attrs['binding:vnic_type']
+
return port
@staticmethod
diff --git a/openstackclient/tests/network/v2/test_port.py b/openstackclient/tests/network/v2/test_port.py
index a1ddefa1..bc246bd8 100644
--- a/openstackclient/tests/network/v2/test_port.py
+++ b/openstackclient/tests/network/v2/test_port.py
@@ -13,8 +13,10 @@
import mock
+from openstackclient.common import utils
from openstackclient.network.v2 import port
from openstackclient.tests.network.v2 import fakes as network_fakes
+from openstackclient.tests import utils as tests_utils
class TestPort(network_fakes.TestNetworkV2):
@@ -51,3 +53,88 @@ class TestDeletePort(TestPort):
result = self.cmd.take_action(parsed_args)
self.network.delete_port.assert_called_with(self._port)
self.assertIsNone(result)
+
+
+class TestShowPort(TestPort):
+
+ # The port to show.
+ _port = network_fakes.FakePort.create_one_port()
+
+ columns = (
+ 'admin_state_up',
+ 'allowed_address_pairs',
+ 'binding_host_id',
+ 'binding_profile',
+ 'binding_vif_details',
+ 'binding_vif_type',
+ 'binding_vnic_type',
+ 'device_id',
+ 'device_owner',
+ 'dns_assignment',
+ 'dns_name',
+ 'extra_dhcp_opts',
+ 'fixed_ips',
+ 'id',
+ 'mac_address',
+ 'name',
+ 'network_id',
+ 'port_security_enabled',
+ 'project_id',
+ 'security_groups',
+ 'status',
+ )
+
+ data = (
+ port._format_admin_state(_port.admin_state_up),
+ utils.format_list_of_dicts(_port.allowed_address_pairs),
+ _port.binding_host_id,
+ utils.format_dict(_port.binding_profile),
+ utils.format_dict(_port.binding_vif_details),
+ _port.binding_vif_type,
+ _port.binding_vnic_type,
+ _port.device_id,
+ _port.device_owner,
+ utils.format_list_of_dicts(_port.dns_assignment),
+ _port.dns_name,
+ utils.format_list_of_dicts(_port.extra_dhcp_opts),
+ utils.format_list_of_dicts(_port.fixed_ips),
+ _port.id,
+ _port.mac_address,
+ _port.name,
+ _port.network_id,
+ _port.port_security_enabled,
+ _port.project_id,
+ utils.format_list(_port.security_groups),
+ _port.status,
+ )
+
+ def setUp(self):
+ super(TestShowPort, self).setUp()
+
+ self.network.find_port = mock.Mock(return_value=self._port)
+
+ # Get the command object to test
+ self.cmd = port.ShowPort(self.app, self.namespace)
+
+ def test_show_no_options(self):
+ arglist = []
+ verifylist = []
+
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, arglist, verifylist)
+
+ def test_show_all_options(self):
+ arglist = [
+ self._port.name,
+ ]
+ verifylist = [
+ ('port', self._port.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.find_port.assert_called_with(self._port.name,
+ ignore_missing=False)
+ self.assertEqual(tuple(self.columns), columns)
+ self.assertEqual(self.data, data)