Skip to content

Commit df69d32

Browse files
Jenkinsopenstack-gerrit
authored andcommitted
Merge "Add network extension list"
2 parents 2306059 + 25e0d2a commit df69d32

File tree

3 files changed

+126
-15
lines changed

3 files changed

+126
-15
lines changed

openstackclient/common/extension.py

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
"""Extension action implementations"""
1717

18+
import itertools
1819
import logging
1920

2021
from cliff import lister
@@ -25,28 +26,30 @@
2526
class ListExtension(lister.Lister):
2627
"""List extension command"""
2728

28-
# TODO(mfisch): add support for volume and network
29-
# when the underlying APIs support it.
30-
3129
log = logging.getLogger(__name__ + '.ListExtension')
3230

3331
def get_parser(self, prog_name):
3432
parser = super(ListExtension, self).get_parser(prog_name)
3533
parser.add_argument(
36-
'--long',
34+
'--compute',
3735
action='store_true',
3836
default=False,
39-
help='List additional fields in output')
37+
help='List extensions for the Compute API')
4038
parser.add_argument(
4139
'--identity',
4240
action='store_true',
4341
default=False,
4442
help='List extensions for the Identity API')
4543
parser.add_argument(
46-
'--compute',
44+
'--long',
4745
action='store_true',
4846
default=False,
49-
help='List extensions for the Compute API')
47+
help='List additional fields in output')
48+
parser.add_argument(
49+
'--network',
50+
action='store_true',
51+
default=False,
52+
help='List extensions for the Network API')
5053
parser.add_argument(
5154
'--volume',
5255
action='store_true',
@@ -69,7 +72,7 @@ def take_action(self, parsed_args):
6972
# user specifies one or more of the APIs to show
7073
# for now, only identity and compute are supported.
7174
show_all = (not parsed_args.identity and not parsed_args.compute
72-
and not parsed_args.volume)
75+
and not parsed_args.volume and not parsed_args.network)
7376

7477
if parsed_args.identity or show_all:
7578
identity_client = self.app.client_manager.identity
@@ -95,8 +98,33 @@ def take_action(self, parsed_args):
9598
message = "Extensions list not supported by Volume API"
9699
self.log.warning(message)
97100

98-
return (columns,
99-
(utils.get_item_properties(
100-
s, columns,
101-
formatters={},
102-
) for s in data))
101+
# Resource classes for the above
102+
extension_tuples = (
103+
utils.get_item_properties(
104+
s,
105+
columns,
106+
formatters={},
107+
) for s in data
108+
)
109+
110+
# Dictionaries for the below
111+
if parsed_args.network or show_all:
112+
network_client = self.app.client_manager.network
113+
try:
114+
data = network_client.list_extensions()['extensions']
115+
dict_tuples = (
116+
utils.get_dict_properties(
117+
s,
118+
columns,
119+
formatters={},
120+
) for s in data
121+
)
122+
extension_tuples = itertools.chain(
123+
extension_tuples,
124+
dict_tuples
125+
)
126+
except Exception:
127+
message = "Extensions list not supported by Network API"
128+
self.log.warning(message)
129+
130+
return (columns, extension_tuples)

openstackclient/tests/common/test_extension.py

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from openstackclient.tests import utils
1919

2020
from openstackclient.tests.identity.v2_0 import fakes as identity_fakes
21+
from openstackclient.tests.network.v2 import fakes as network_fakes
2122

2223

2324
class TestExtension(utils.TestCommand):
@@ -29,12 +30,15 @@ def setUp(self):
2930
endpoint=fakes.AUTH_URL,
3031
token=fakes.AUTH_TOKEN,
3132
)
32-
33-
# Get shortcuts to the ExtensionManager Mocks
3433
self.identity_extensions_mock = (
3534
self.app.client_manager.identity.extensions)
3635
self.identity_extensions_mock.reset_mock()
3736

37+
network = network_fakes.FakeNetworkV2Client()
38+
self.app.client_manager.network = network
39+
self.network_extensions_mock = network.list_extensions
40+
self.network_extensions_mock.reset_mock()
41+
3842

3943
class TestExtensionList(TestExtension):
4044

@@ -48,6 +52,13 @@ def setUp(self):
4852
loaded=True,
4953
),
5054
]
55+
self.network_extensions_mock.list.return_value = [
56+
fakes.FakeResource(
57+
None,
58+
copy.deepcopy(identity_fakes.EXTENSION),
59+
loaded=True,
60+
),
61+
]
5162

5263
# Get the command object to test
5364
self.cmd = extension.ListExtension(self.app, None)
@@ -71,6 +82,11 @@ def test_extension_list_no_options(self):
7182
identity_fakes.extension_alias,
7283
identity_fakes.extension_description,
7384
),
85+
(
86+
network_fakes.extension_name,
87+
network_fakes.extension_alias,
88+
network_fakes.extension_description,
89+
),
7490
)
7591
self.assertEqual(tuple(data), datalist)
7692

@@ -101,6 +117,14 @@ def test_extension_list_long(self):
101117
identity_fakes.extension_updated,
102118
identity_fakes.extension_links,
103119
),
120+
(
121+
network_fakes.extension_name,
122+
network_fakes.extension_namespace,
123+
network_fakes.extension_description,
124+
network_fakes.extension_alias,
125+
network_fakes.extension_updated,
126+
network_fakes.extension_links,
127+
),
104128
)
105129
self.assertEqual(tuple(data), datalist)
106130

@@ -126,3 +150,27 @@ def test_extension_list_identity(self):
126150
identity_fakes.extension_description,
127151
), )
128152
self.assertEqual(tuple(data), datalist)
153+
154+
def test_extension_list_network(self):
155+
arglist = [
156+
'--network',
157+
]
158+
verifylist = [
159+
('network', True),
160+
]
161+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
162+
163+
columns, data = self.cmd.take_action(parsed_args)
164+
165+
self.network_extensions_mock.assert_called_with()
166+
167+
collist = ('Name', 'Alias', 'Description')
168+
self.assertEqual(columns, collist)
169+
datalist = (
170+
(
171+
network_fakes.extension_name,
172+
network_fakes.extension_alias,
173+
network_fakes.extension_description,
174+
),
175+
)
176+
self.assertEqual(tuple(data), datalist)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
2+
# not use this file except in compliance with the License. You may obtain
3+
# a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10+
# License for the specific language governing permissions and limitations
11+
# under the License.
12+
#
13+
14+
import mock
15+
16+
extension_name = 'Matrix'
17+
extension_namespace = 'http://docs.openstack.org/network/'
18+
extension_description = 'Simulated reality'
19+
extension_updated = '2013-07-09T12:00:0-00:00'
20+
extension_alias = 'Dystopian'
21+
extension_links = '[{"href":''"https://github.com/os/network", "type"}]'
22+
23+
NETEXT = {
24+
'name': extension_name,
25+
'namespace': extension_namespace,
26+
'description': extension_description,
27+
'updated': extension_updated,
28+
'alias': extension_alias,
29+
'links': extension_links,
30+
}
31+
32+
33+
class FakeNetworkV2Client(object):
34+
def __init__(self, **kwargs):
35+
self.list_extensions = mock.Mock(return_value={'extensions': [NETEXT]})

0 commit comments

Comments
 (0)