Skip to content

Commit 4072554

Browse files
committed
Support for volume service list
OSC does not support to list volume services. This patch will provide support for adding volume service related support. Closes-bug:#1550999 Implements: bp cinder-command-support Change-Id: I50ac14aeb96c4b8ddbf7b33e519feea0d126f752
1 parent 9e7f0cf commit 4072554

10 files changed

Lines changed: 660 additions & 11 deletions

File tree

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
==============
2+
volume service
3+
==============
4+
5+
Volume v1, v2
6+
7+
volume service list
8+
-------------------
9+
10+
List volume service
11+
12+
.. program:: volume service list
13+
.. code:: bash
14+
15+
os volume service list
16+
[--host <host>]
17+
[--service <service>]
18+
[--long]
19+
20+
.. _volume-service-list:
21+
.. option:: --host <host>
22+
23+
List services on specified host (name only)
24+
25+
.. option:: --service <service>
26+
27+
List only specified service (name only)
28+
29+
.. option:: --long
30+
31+
List additional fields in output

doc/source/commands.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ referring to both Compute and Volume quotas.
127127
* ``user role``: (**Identity**) roles assigned to a user
128128
* ``volume``: (**Volume**) block volumes
129129
* ``volume type``: (**Volume**) deployment-specific types of volumes available
130+
* ``volume service``: (**Volume**) services to manage block storage operations
130131

131132

132133
Plugin Objects

openstackclient/tests/volume/v1/fakes.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,97 @@
129129
}
130130

131131

132+
class FakeServiceClient(object):
133+
134+
def __init__(self, **kwargs):
135+
self.services = mock.Mock()
136+
self.services.resource_class = fakes.FakeResource(None, {})
137+
138+
139+
class TestService(utils.TestCommand):
140+
141+
def setUp(self):
142+
super(TestService, self).setUp()
143+
144+
self.app.client_manager.volume = FakeServiceClient(
145+
endpoint=fakes.AUTH_URL,
146+
token=fakes.AUTH_TOKEN
147+
)
148+
149+
150+
class FakeService(object):
151+
"""Fake one or more Services."""
152+
153+
@staticmethod
154+
def create_one_service(attrs=None):
155+
"""Create a fake service.
156+
157+
:param Dictionary attrs:
158+
A dictionary with all attributes of service
159+
:retrun:
160+
A FakeResource object with host, status, etc.
161+
"""
162+
# Set default attribute
163+
service_info = {
164+
'host': 'host_test',
165+
'binary': 'cinder_test',
166+
'status': 'enabled',
167+
'disabled_reason': 'LongHoliday-GoldenWeek',
168+
'zone': 'fake_zone',
169+
'updated_at': 'fake_date',
170+
'state': 'fake_state',
171+
}
172+
173+
# Overwrite default attributes if there are some attributes set
174+
if attrs is None:
175+
attrs = {}
176+
service_info.update(attrs)
177+
178+
service = fakes.FakeResource(
179+
None,
180+
service_info,
181+
loaded=True)
182+
183+
return service
184+
185+
@staticmethod
186+
def create_services(attrs=None, count=2):
187+
"""Create multiple fake services.
188+
189+
:param Dictionary attrs:
190+
A dictionary with all attributes of service
191+
:param Integer count:
192+
The number of services to be faked
193+
:return:
194+
A list of FakeResource objects
195+
"""
196+
services = []
197+
for n in range(0, count):
198+
services.append(FakeService.create_one_service(attrs))
199+
200+
return services
201+
202+
@staticmethod
203+
def get_services(services=None, count=2):
204+
"""Get an iterable MagicMock object with a list of faked services.
205+
206+
If services list is provided, then initialize the Mock object with the
207+
list. Otherwise create one.
208+
209+
:param List services:
210+
A list of FakeResource objects faking services
211+
:param Integer count:
212+
The number of services to be faked
213+
:return
214+
An iterable Mock object with side_effect set to a list of faked
215+
services
216+
"""
217+
if services is None:
218+
services = FakeService.create_services(count)
219+
220+
return mock.MagicMock(side_effect=services)
221+
222+
132223
class FakeImagev1Client(object):
133224

134225
def __init__(self, **kwargs):
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#
2+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
3+
# not use this file except in compliance with the License. You may obtain
4+
# a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11+
# License for the specific language governing permissions and limitations
12+
# under the License.
13+
#
14+
15+
16+
from openstackclient.tests.volume.v1 import fakes as service_fakes
17+
from openstackclient.volume.v1 import service
18+
19+
20+
class TestService(service_fakes.TestService):
21+
22+
def setUp(self):
23+
super(TestService, self).setUp()
24+
25+
# Get a shortcut to the ServiceManager Mock
26+
self.service_mock = self.app.client_manager.volume.services
27+
self.service_mock.reset_mock()
28+
29+
30+
class TestServiceList(TestService):
31+
32+
# The service to be listed
33+
services = service_fakes.FakeService.create_one_service()
34+
35+
def setUp(self):
36+
super(TestServiceList, self).setUp()
37+
38+
self.service_mock.list.return_value = [self.services]
39+
40+
# Get the command object to test
41+
self.cmd = service.ListService(self.app, None)
42+
43+
def test_service_list(self):
44+
arglist = [
45+
'--host', self.services.host,
46+
'--service', self.services.binary,
47+
]
48+
verifylist = [
49+
('host', self.services.host),
50+
('service', self.services.binary),
51+
]
52+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
53+
54+
# In base command class Lister in cliff, abstract method take_action()
55+
# returns a tuple containing the column names and an iterable
56+
# containing the data to be listed.
57+
columns, data = self.cmd.take_action(parsed_args)
58+
59+
expected_columns = [
60+
'Binary',
61+
'Host',
62+
'Zone',
63+
'Status',
64+
'State',
65+
'Updated At',
66+
]
67+
68+
# confirming if all expected columns are present in the result.
69+
self.assertEqual(expected_columns, columns)
70+
71+
datalist = ((
72+
self.services.binary,
73+
self.services.host,
74+
self.services.zone,
75+
self.services.status,
76+
self.services.state,
77+
self.services.updated_at,
78+
), )
79+
80+
# confirming if all expected values are present in the result.
81+
self.assertEqual(datalist, tuple(data))
82+
83+
# checking if proper call was made to list services
84+
self.service_mock.list.assert_called_with(
85+
self.services.host,
86+
self.services.binary,
87+
)
88+
89+
# checking if prohibited columns are present in output
90+
self.assertNotIn("Disabled Reason", columns)
91+
self.assertNotIn(self.services.disabled_reason,
92+
tuple(data))
93+
94+
def test_service_list_with_long_option(self):
95+
arglist = [
96+
'--host', self.services.host,
97+
'--service', self.services.binary,
98+
'--long'
99+
]
100+
verifylist = [
101+
('host', self.services.host),
102+
('service', self.services.binary),
103+
('long', True)
104+
]
105+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
106+
107+
# In base command class Lister in cliff, abstract method take_action()
108+
# returns a tuple containing the column names and an iterable
109+
# containing the data to be listed.
110+
columns, data = self.cmd.take_action(parsed_args)
111+
112+
expected_columns = [
113+
'Binary',
114+
'Host',
115+
'Zone',
116+
'Status',
117+
'State',
118+
'Updated At',
119+
'Disabled Reason'
120+
]
121+
122+
# confirming if all expected columns are present in the result.
123+
self.assertEqual(expected_columns, columns)
124+
125+
datalist = ((
126+
self.services.binary,
127+
self.services.host,
128+
self.services.zone,
129+
self.services.status,
130+
self.services.state,
131+
self.services.updated_at,
132+
self.services.disabled_reason,
133+
), )
134+
135+
# confirming if all expected values are present in the result.
136+
self.assertEqual(datalist, tuple(data))
137+
138+
self.service_mock.list.assert_called_with(
139+
self.services.host,
140+
self.services.binary,
141+
)

0 commit comments

Comments
 (0)