Skip to content

Commit 981621e

Browse files
committed
Add "os port show" command
Add "os port show" command. Change-Id: Id87c81640e74c60ae8f247c722c64fdadff022a2 Partial-Bug: #1519909 Partially-Implements: blueprint neutron-client
1 parent f36177e commit 981621e

8 files changed

Lines changed: 222 additions & 4 deletions

File tree

doc/source/command-objects/port.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,19 @@ Delete port(s)
1919
.. describe:: <port>
2020

2121
Port(s) to delete (name or ID)
22+
23+
port show
24+
---------
25+
26+
Display port details
27+
28+
.. program:: port show
29+
.. code:: bash
30+
31+
os port show
32+
<port>
33+
34+
.. _port_show-port:
35+
.. describe:: <port>
36+
37+
Port to display (name or ID)

openstackclient/common/utils.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,16 @@ def format_list(data, separator=', '):
169169
return separator.join(sorted(data))
170170

171171

172+
def format_list_of_dicts(data):
173+
"""Return a formatted string of key value pairs for each dict
174+
175+
:param data: a list of dicts
176+
:rtype: a string formatted to key='value' with dicts separated by new line
177+
"""
178+
179+
return '\n'.join(format_dict(i) for i in data)
180+
181+
172182
def get_field(item, field):
173183
try:
174184
if isinstance(item, dict):

openstackclient/network/v2/port.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,42 @@
1414
"""Port action implementations"""
1515

1616
from openstackclient.common import command
17+
from openstackclient.common import utils
18+
19+
20+
def _format_admin_state(state):
21+
return 'UP' if state else 'DOWN'
22+
23+
24+
_formatters = {
25+
'admin_state_up': _format_admin_state,
26+
'allowed_address_pairs': utils.format_list_of_dicts,
27+
'binding_profile': utils.format_dict,
28+
'binding_vif_details': utils.format_dict,
29+
'dns_assignment': utils.format_list_of_dicts,
30+
'extra_dhcp_opts': utils.format_list_of_dicts,
31+
'fixed_ips': utils.format_list_of_dicts,
32+
'security_groups': utils.format_list,
33+
}
34+
35+
36+
def _get_columns(item):
37+
columns = item.keys()
38+
if 'tenant_id' in columns:
39+
columns.remove('tenant_id')
40+
columns.append('project_id')
41+
binding_columns = [
42+
'binding:host_id',
43+
'binding:profile',
44+
'binding:vif_details',
45+
'binding:vif_type',
46+
'binding:vnic_type',
47+
]
48+
for binding_column in binding_columns:
49+
if binding_column in columns:
50+
columns.remove(binding_column)
51+
columns.append(binding_column.replace('binding:', 'binding_', 1))
52+
return sorted(columns)
1753

1854

1955
class DeletePort(command.Command):
@@ -35,3 +71,23 @@ def take_action(self, parsed_args):
3571
for port in parsed_args.port:
3672
res = client.find_port(port)
3773
client.delete_port(res)
74+
75+
76+
class ShowPort(command.ShowOne):
77+
"""Display port details"""
78+
79+
def get_parser(self, prog_name):
80+
parser = super(ShowPort, self).get_parser(prog_name)
81+
parser.add_argument(
82+
'port',
83+
metavar="<port>",
84+
help="Port to display (name or ID)"
85+
)
86+
return parser
87+
88+
def take_action(self, parsed_args):
89+
client = self.app.client_manager.network
90+
obj = client.find_port(parsed_args.port, ignore_missing=False)
91+
columns = _get_columns(obj)
92+
data = utils.get_item_properties(obj, columns, formatters=_formatters)
93+
return (tuple(columns), data)

openstackclient/tests/common/test_utils.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,15 @@ def test_format_list(self):
348348
self.assertEqual(expected, utils.format_list(['a', 'b', 'c']))
349349
self.assertEqual(expected, utils.format_list(['c', 'b', 'a']))
350350

351+
def test_format_list_of_dicts(self):
352+
expected = "a='b', c='d'\ne='f'"
353+
sorted_data = [{'a': 'b', 'c': 'd'}, {'e': 'f'}]
354+
unsorted_data = [{'c': 'd', 'a': 'b'}, {'e': 'f'}]
355+
self.assertEqual(expected, utils.format_list_of_dicts(sorted_data))
356+
self.assertEqual(expected, utils.format_list_of_dicts(unsorted_data))
357+
self.assertEqual('', utils.format_list_of_dicts([]))
358+
self.assertEqual('', utils.format_list_of_dicts([{}]))
359+
351360
def test_format_list_separator(self):
352361
expected = 'a\nb\nc'
353362
actual_pre_sorted = utils.format_list(['a', 'b', 'c'], separator='\n')

openstackclient/tests/network/v2/fakes.py

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,30 +172,64 @@ def create_one_port(attrs={}, methods={}):
172172
:param Dictionary methods:
173173
A dictionary with all methods
174174
:return:
175-
A FakeResource object, with id, name, admin_state_up,
176-
status, tenant_id
175+
A FakeResource object, with id, name, etc.
177176
"""
177+
178178
# Set default attributes.
179179
port_attrs = {
180+
'admin_state_up': True,
181+
'allowed_address_pairs': [{}],
182+
'binding:host_id': 'binding-host-id-' + uuid.uuid4().hex,
183+
'binding:profile': {},
184+
'binding:vif_details': {},
185+
'binding:vif_type': 'ovs',
186+
'binding:vnic_type': 'normal',
187+
'device_id': 'device-id-' + uuid.uuid4().hex,
188+
'device_owner': 'compute:nova',
189+
'dns_assignment': [{}],
190+
'dns_name': 'dns-name-' + uuid.uuid4().hex,
191+
'extra_dhcp_opts': [{}],
192+
'fixed_ips': [{}],
180193
'id': 'port-id-' + uuid.uuid4().hex,
194+
'mac_address': 'fa:16:3e:a9:4e:72',
181195
'name': 'port-name-' + uuid.uuid4().hex,
196+
'network_id': 'network-id-' + uuid.uuid4().hex,
197+
'port_security_enabled': True,
198+
'security_groups': [],
182199
'status': 'ACTIVE',
183-
'admin_state_up': True,
184200
'tenant_id': 'project-id-' + uuid.uuid4().hex,
185201
}
186202

187203
# Overwrite default attributes.
188204
port_attrs.update(attrs)
189205

190206
# Set default methods.
191-
port_methods = {}
207+
port_methods = {
208+
'keys': ['admin_state_up', 'allowed_address_pairs',
209+
'binding:host_id', 'binding:profile',
210+
'binding:vif_details', 'binding:vif_type',
211+
'binding:vnic_type', 'device_id', 'device_owner',
212+
'dns_assignment', 'dns_name', 'extra_dhcp_opts',
213+
'fixed_ips', 'id', 'mac_address', 'name',
214+
'network_id', 'port_security_enabled',
215+
'security_groups', 'status', 'tenant_id'],
216+
}
192217

193218
# Overwrite default methods.
194219
port_methods.update(methods)
195220

196221
port = fakes.FakeResource(info=copy.deepcopy(port_attrs),
197222
methods=copy.deepcopy(port_methods),
198223
loaded=True)
224+
225+
# Set attributes with special mappings.
226+
port.project_id = port_attrs['tenant_id']
227+
port.binding_host_id = port_attrs['binding:host_id']
228+
port.binding_profile = port_attrs['binding:profile']
229+
port.binding_vif_details = port_attrs['binding:vif_details']
230+
port.binding_vif_type = port_attrs['binding:vif_type']
231+
port.binding_vnic_type = port_attrs['binding:vnic_type']
232+
199233
return port
200234

201235
@staticmethod

openstackclient/tests/network/v2/test_port.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313

1414
import mock
1515

16+
from openstackclient.common import utils
1617
from openstackclient.network.v2 import port
1718
from openstackclient.tests.network.v2 import fakes as network_fakes
19+
from openstackclient.tests import utils as tests_utils
1820

1921

2022
class TestPort(network_fakes.TestNetworkV2):
@@ -51,3 +53,88 @@ def test_delete(self):
5153
result = self.cmd.take_action(parsed_args)
5254
self.network.delete_port.assert_called_with(self._port)
5355
self.assertIsNone(result)
56+
57+
58+
class TestShowPort(TestPort):
59+
60+
# The port to show.
61+
_port = network_fakes.FakePort.create_one_port()
62+
63+
columns = (
64+
'admin_state_up',
65+
'allowed_address_pairs',
66+
'binding_host_id',
67+
'binding_profile',
68+
'binding_vif_details',
69+
'binding_vif_type',
70+
'binding_vnic_type',
71+
'device_id',
72+
'device_owner',
73+
'dns_assignment',
74+
'dns_name',
75+
'extra_dhcp_opts',
76+
'fixed_ips',
77+
'id',
78+
'mac_address',
79+
'name',
80+
'network_id',
81+
'port_security_enabled',
82+
'project_id',
83+
'security_groups',
84+
'status',
85+
)
86+
87+
data = (
88+
port._format_admin_state(_port.admin_state_up),
89+
utils.format_list_of_dicts(_port.allowed_address_pairs),
90+
_port.binding_host_id,
91+
utils.format_dict(_port.binding_profile),
92+
utils.format_dict(_port.binding_vif_details),
93+
_port.binding_vif_type,
94+
_port.binding_vnic_type,
95+
_port.device_id,
96+
_port.device_owner,
97+
utils.format_list_of_dicts(_port.dns_assignment),
98+
_port.dns_name,
99+
utils.format_list_of_dicts(_port.extra_dhcp_opts),
100+
utils.format_list_of_dicts(_port.fixed_ips),
101+
_port.id,
102+
_port.mac_address,
103+
_port.name,
104+
_port.network_id,
105+
_port.port_security_enabled,
106+
_port.project_id,
107+
utils.format_list(_port.security_groups),
108+
_port.status,
109+
)
110+
111+
def setUp(self):
112+
super(TestShowPort, self).setUp()
113+
114+
self.network.find_port = mock.Mock(return_value=self._port)
115+
116+
# Get the command object to test
117+
self.cmd = port.ShowPort(self.app, self.namespace)
118+
119+
def test_show_no_options(self):
120+
arglist = []
121+
verifylist = []
122+
123+
self.assertRaises(tests_utils.ParserException,
124+
self.check_parser, self.cmd, arglist, verifylist)
125+
126+
def test_show_all_options(self):
127+
arglist = [
128+
self._port.name,
129+
]
130+
verifylist = [
131+
('port', self._port.name),
132+
]
133+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
134+
135+
columns, data = self.cmd.take_action(parsed_args)
136+
137+
self.network.find_port.assert_called_with(self._port.name,
138+
ignore_missing=False)
139+
self.assertEqual(tuple(self.columns), columns)
140+
self.assertEqual(self.data, data)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
features:
3+
- |
4+
Add support for the ``port show`` command.
5+
[Bug `1519909 <https://bugs.launchpad.net/python-openstackclient/+bug/1519909>`_]

setup.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,7 @@ openstack.network.v2 =
333333
network_set = openstackclient.network.v2.network:SetNetwork
334334
network_show = openstackclient.network.v2.network:ShowNetwork
335335
port_delete = openstackclient.network.v2.port:DeletePort
336+
port_show = openstackclient.network.v2.port:ShowPort
336337
router_create = openstackclient.network.v2.router:CreateRouter
337338
router_delete = openstackclient.network.v2.router:DeleteRouter
338339
router_list = openstackclient.network.v2.router:ListRouter

0 commit comments

Comments
 (0)