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
This commit is contained in:
parent
9e7f0cf1a5
commit
4072554608
31
doc/source/command-objects/volume-service.rst
Normal file
31
doc/source/command-objects/volume-service.rst
Normal file
@ -0,0 +1,31 @@
|
||||
==============
|
||||
volume service
|
||||
==============
|
||||
|
||||
Volume v1, v2
|
||||
|
||||
volume service list
|
||||
-------------------
|
||||
|
||||
List volume service
|
||||
|
||||
.. program:: volume service list
|
||||
.. code:: bash
|
||||
|
||||
os volume service list
|
||||
[--host <host>]
|
||||
[--service <service>]
|
||||
[--long]
|
||||
|
||||
.. _volume-service-list:
|
||||
.. option:: --host <host>
|
||||
|
||||
List services on specified host (name only)
|
||||
|
||||
.. option:: --service <service>
|
||||
|
||||
List only specified service (name only)
|
||||
|
||||
.. option:: --long
|
||||
|
||||
List additional fields in output
|
@ -127,6 +127,7 @@ referring to both Compute and Volume quotas.
|
||||
* ``user role``: (**Identity**) roles assigned to a user
|
||||
* ``volume``: (**Volume**) block volumes
|
||||
* ``volume type``: (**Volume**) deployment-specific types of volumes available
|
||||
* ``volume service``: (**Volume**) services to manage block storage operations
|
||||
|
||||
|
||||
Plugin Objects
|
||||
|
@ -129,6 +129,97 @@ QOS_WITH_ASSOCIATIONS = {
|
||||
}
|
||||
|
||||
|
||||
class FakeServiceClient(object):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.services = mock.Mock()
|
||||
self.services.resource_class = fakes.FakeResource(None, {})
|
||||
|
||||
|
||||
class TestService(utils.TestCommand):
|
||||
|
||||
def setUp(self):
|
||||
super(TestService, self).setUp()
|
||||
|
||||
self.app.client_manager.volume = FakeServiceClient(
|
||||
endpoint=fakes.AUTH_URL,
|
||||
token=fakes.AUTH_TOKEN
|
||||
)
|
||||
|
||||
|
||||
class FakeService(object):
|
||||
"""Fake one or more Services."""
|
||||
|
||||
@staticmethod
|
||||
def create_one_service(attrs=None):
|
||||
"""Create a fake service.
|
||||
|
||||
:param Dictionary attrs:
|
||||
A dictionary with all attributes of service
|
||||
:retrun:
|
||||
A FakeResource object with host, status, etc.
|
||||
"""
|
||||
# Set default attribute
|
||||
service_info = {
|
||||
'host': 'host_test',
|
||||
'binary': 'cinder_test',
|
||||
'status': 'enabled',
|
||||
'disabled_reason': 'LongHoliday-GoldenWeek',
|
||||
'zone': 'fake_zone',
|
||||
'updated_at': 'fake_date',
|
||||
'state': 'fake_state',
|
||||
}
|
||||
|
||||
# Overwrite default attributes if there are some attributes set
|
||||
if attrs is None:
|
||||
attrs = {}
|
||||
service_info.update(attrs)
|
||||
|
||||
service = fakes.FakeResource(
|
||||
None,
|
||||
service_info,
|
||||
loaded=True)
|
||||
|
||||
return service
|
||||
|
||||
@staticmethod
|
||||
def create_services(attrs=None, count=2):
|
||||
"""Create multiple fake services.
|
||||
|
||||
:param Dictionary attrs:
|
||||
A dictionary with all attributes of service
|
||||
:param Integer count:
|
||||
The number of services to be faked
|
||||
:return:
|
||||
A list of FakeResource objects
|
||||
"""
|
||||
services = []
|
||||
for n in range(0, count):
|
||||
services.append(FakeService.create_one_service(attrs))
|
||||
|
||||
return services
|
||||
|
||||
@staticmethod
|
||||
def get_services(services=None, count=2):
|
||||
"""Get an iterable MagicMock object with a list of faked services.
|
||||
|
||||
If services list is provided, then initialize the Mock object with the
|
||||
list. Otherwise create one.
|
||||
|
||||
:param List services:
|
||||
A list of FakeResource objects faking services
|
||||
:param Integer count:
|
||||
The number of services to be faked
|
||||
:return
|
||||
An iterable Mock object with side_effect set to a list of faked
|
||||
services
|
||||
"""
|
||||
if services is None:
|
||||
services = FakeService.create_services(count)
|
||||
|
||||
return mock.MagicMock(side_effect=services)
|
||||
|
||||
|
||||
class FakeImagev1Client(object):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
141
openstackclient/tests/volume/v1/test_service.py
Normal file
141
openstackclient/tests/volume/v1/test_service.py
Normal file
@ -0,0 +1,141 @@
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
|
||||
from openstackclient.tests.volume.v1 import fakes as service_fakes
|
||||
from openstackclient.volume.v1 import service
|
||||
|
||||
|
||||
class TestService(service_fakes.TestService):
|
||||
|
||||
def setUp(self):
|
||||
super(TestService, self).setUp()
|
||||
|
||||
# Get a shortcut to the ServiceManager Mock
|
||||
self.service_mock = self.app.client_manager.volume.services
|
||||
self.service_mock.reset_mock()
|
||||
|
||||
|
||||
class TestServiceList(TestService):
|
||||
|
||||
# The service to be listed
|
||||
services = service_fakes.FakeService.create_one_service()
|
||||
|
||||
def setUp(self):
|
||||
super(TestServiceList, self).setUp()
|
||||
|
||||
self.service_mock.list.return_value = [self.services]
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = service.ListService(self.app, None)
|
||||
|
||||
def test_service_list(self):
|
||||
arglist = [
|
||||
'--host', self.services.host,
|
||||
'--service', self.services.binary,
|
||||
]
|
||||
verifylist = [
|
||||
('host', self.services.host),
|
||||
('service', self.services.binary),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
# In base command class Lister in cliff, abstract method take_action()
|
||||
# returns a tuple containing the column names and an iterable
|
||||
# containing the data to be listed.
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
expected_columns = [
|
||||
'Binary',
|
||||
'Host',
|
||||
'Zone',
|
||||
'Status',
|
||||
'State',
|
||||
'Updated At',
|
||||
]
|
||||
|
||||
# confirming if all expected columns are present in the result.
|
||||
self.assertEqual(expected_columns, columns)
|
||||
|
||||
datalist = ((
|
||||
self.services.binary,
|
||||
self.services.host,
|
||||
self.services.zone,
|
||||
self.services.status,
|
||||
self.services.state,
|
||||
self.services.updated_at,
|
||||
), )
|
||||
|
||||
# confirming if all expected values are present in the result.
|
||||
self.assertEqual(datalist, tuple(data))
|
||||
|
||||
# checking if proper call was made to list services
|
||||
self.service_mock.list.assert_called_with(
|
||||
self.services.host,
|
||||
self.services.binary,
|
||||
)
|
||||
|
||||
# checking if prohibited columns are present in output
|
||||
self.assertNotIn("Disabled Reason", columns)
|
||||
self.assertNotIn(self.services.disabled_reason,
|
||||
tuple(data))
|
||||
|
||||
def test_service_list_with_long_option(self):
|
||||
arglist = [
|
||||
'--host', self.services.host,
|
||||
'--service', self.services.binary,
|
||||
'--long'
|
||||
]
|
||||
verifylist = [
|
||||
('host', self.services.host),
|
||||
('service', self.services.binary),
|
||||
('long', True)
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
# In base command class Lister in cliff, abstract method take_action()
|
||||
# returns a tuple containing the column names and an iterable
|
||||
# containing the data to be listed.
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
expected_columns = [
|
||||
'Binary',
|
||||
'Host',
|
||||
'Zone',
|
||||
'Status',
|
||||
'State',
|
||||
'Updated At',
|
||||
'Disabled Reason'
|
||||
]
|
||||
|
||||
# confirming if all expected columns are present in the result.
|
||||
self.assertEqual(expected_columns, columns)
|
||||
|
||||
datalist = ((
|
||||
self.services.binary,
|
||||
self.services.host,
|
||||
self.services.zone,
|
||||
self.services.status,
|
||||
self.services.state,
|
||||
self.services.updated_at,
|
||||
self.services.disabled_reason,
|
||||
), )
|
||||
|
||||
# confirming if all expected values are present in the result.
|
||||
self.assertEqual(datalist, tuple(data))
|
||||
|
||||
self.service_mock.list.assert_called_with(
|
||||
self.services.host,
|
||||
self.services.binary,
|
||||
)
|
@ -232,6 +232,97 @@ EXTENSION = {
|
||||
}
|
||||
|
||||
|
||||
class FakeServiceClient(object):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.services = mock.Mock()
|
||||
self.services.resource_class = fakes.FakeResource(None, {})
|
||||
|
||||
|
||||
class TestService(utils.TestCommand):
|
||||
|
||||
def setUp(self):
|
||||
super(TestService, self).setUp()
|
||||
|
||||
self.app.client_manager.volume = FakeServiceClient(
|
||||
endpoint=fakes.AUTH_URL,
|
||||
token=fakes.AUTH_TOKEN
|
||||
)
|
||||
|
||||
|
||||
class FakeService(object):
|
||||
"""Fake one or more Services."""
|
||||
|
||||
@staticmethod
|
||||
def create_one_service(attrs=None):
|
||||
"""Create a fake service.
|
||||
|
||||
:param Dictionary attrs:
|
||||
A dictionary with all attributes of service
|
||||
:retrun:
|
||||
A FakeResource object with host, status, etc.
|
||||
"""
|
||||
# Set default attribute
|
||||
service_info = {
|
||||
'host': 'host_test',
|
||||
'binary': 'cinder_test',
|
||||
'status': 'enabled',
|
||||
'disabled_reason': 'LongHoliday-GoldenWeek',
|
||||
'zone': 'fake_zone',
|
||||
'updated_at': 'fake_date',
|
||||
'state': 'fake_state',
|
||||
}
|
||||
|
||||
# Overwrite default attributes if there are some attributes set
|
||||
if attrs is None:
|
||||
attrs = {}
|
||||
service_info.update(attrs)
|
||||
|
||||
service = fakes.FakeResource(
|
||||
None,
|
||||
service_info,
|
||||
loaded=True)
|
||||
|
||||
return service
|
||||
|
||||
@staticmethod
|
||||
def create_services(attrs=None, count=2):
|
||||
"""Create multiple fake services.
|
||||
|
||||
:param Dictionary attrs:
|
||||
A dictionary with all attributes of service
|
||||
:param Integer count:
|
||||
The number of services to be faked
|
||||
:return:
|
||||
A list of FakeResource objects
|
||||
"""
|
||||
services = []
|
||||
for n in range(0, count):
|
||||
services.append(FakeService.create_one_service(attrs))
|
||||
|
||||
return services
|
||||
|
||||
@staticmethod
|
||||
def get_services(services=None, count=2):
|
||||
"""Get an iterable MagicMock object with a list of faked services.
|
||||
|
||||
If services list is provided, then initialize the Mock object with the
|
||||
list. Otherwise create one.
|
||||
|
||||
:param List services:
|
||||
A list of FakeResource objects faking services
|
||||
:param Integer count:
|
||||
The number of services to be faked
|
||||
:return
|
||||
An iterable Mock object with side_effect set to a list of faked
|
||||
services
|
||||
"""
|
||||
if services is None:
|
||||
services = FakeService.create_services(count)
|
||||
|
||||
return mock.MagicMock(side_effect=services)
|
||||
|
||||
|
||||
class FakeVolumeClient(object):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
@ -243,6 +334,8 @@ class FakeVolumeClient(object):
|
||||
self.backups.resource_class = fakes.FakeResource(None, {})
|
||||
self.volume_types = mock.Mock()
|
||||
self.volume_types.resource_class = fakes.FakeResource(None, {})
|
||||
self.volume_type_access = mock.Mock()
|
||||
self.volume_type_access.resource_class = fakes.FakeResource(None, {})
|
||||
self.restores = mock.Mock()
|
||||
self.restores.resource_class = fakes.FakeResource(None, {})
|
||||
self.qos_specs = mock.Mock()
|
||||
@ -279,7 +372,7 @@ class FakeVolume(object):
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def create_one_volume(attrs={}):
|
||||
def create_one_volume(attrs=None):
|
||||
"""Create a fake volume.
|
||||
|
||||
:param Dictionary attrs:
|
||||
@ -287,6 +380,8 @@ class FakeVolume(object):
|
||||
:retrun:
|
||||
A FakeResource object with id, name, status, etc.
|
||||
"""
|
||||
attrs = attrs or {}
|
||||
|
||||
# Set default attribute
|
||||
volume_info = {
|
||||
'id': 'volume-id' + uuid.uuid4().hex,
|
||||
@ -318,7 +413,7 @@ class FakeVolume(object):
|
||||
return volume
|
||||
|
||||
@staticmethod
|
||||
def create_volumes(attrs={}, count=2):
|
||||
def create_volumes(attrs=None, count=2):
|
||||
"""Create multiple fake volumes.
|
||||
|
||||
:param Dictionary attrs:
|
||||
@ -359,16 +454,16 @@ class FakeAvailabilityZone(object):
|
||||
"""Fake one or more volume availability zones (AZs)."""
|
||||
|
||||
@staticmethod
|
||||
def create_one_availability_zone(attrs={}, methods={}):
|
||||
def create_one_availability_zone(attrs=None):
|
||||
"""Create a fake AZ.
|
||||
|
||||
:param Dictionary attrs:
|
||||
A dictionary with all attributes
|
||||
:param Dictionary methods:
|
||||
A dictionary with all methods
|
||||
:return:
|
||||
A FakeResource object with zoneName, zoneState, etc.
|
||||
"""
|
||||
attrs = attrs or {}
|
||||
|
||||
# Set default attributes.
|
||||
availability_zone = {
|
||||
'zoneName': uuid.uuid4().hex,
|
||||
@ -380,18 +475,15 @@ class FakeAvailabilityZone(object):
|
||||
|
||||
availability_zone = fakes.FakeResource(
|
||||
info=copy.deepcopy(availability_zone),
|
||||
methods=methods,
|
||||
loaded=True)
|
||||
return availability_zone
|
||||
|
||||
@staticmethod
|
||||
def create_availability_zones(attrs={}, methods={}, count=2):
|
||||
def create_availability_zones(attrs=None, count=2):
|
||||
"""Create multiple fake AZs.
|
||||
|
||||
:param Dictionary attrs:
|
||||
A dictionary with all attributes
|
||||
:param Dictionary methods:
|
||||
A dictionary with all methods
|
||||
:param int count:
|
||||
The number of AZs to fake
|
||||
:return:
|
||||
@ -400,8 +492,7 @@ class FakeAvailabilityZone(object):
|
||||
availability_zones = []
|
||||
for i in range(0, count):
|
||||
availability_zone = \
|
||||
FakeAvailabilityZone.create_one_availability_zone(
|
||||
attrs, methods)
|
||||
FakeAvailabilityZone.create_one_availability_zone(attrs)
|
||||
availability_zones.append(availability_zone)
|
||||
|
||||
return availability_zones
|
||||
|
141
openstackclient/tests/volume/v2/test_service.py
Normal file
141
openstackclient/tests/volume/v2/test_service.py
Normal file
@ -0,0 +1,141 @@
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
|
||||
from openstackclient.tests.volume.v2 import fakes as service_fakes
|
||||
from openstackclient.volume.v2 import service
|
||||
|
||||
|
||||
class TestService(service_fakes.TestService):
|
||||
|
||||
def setUp(self):
|
||||
super(TestService, self).setUp()
|
||||
|
||||
# Get a shortcut to the ServiceManager Mock
|
||||
self.service_mock = self.app.client_manager.volume.services
|
||||
self.service_mock.reset_mock()
|
||||
|
||||
|
||||
class TestServiceList(TestService):
|
||||
|
||||
# The service to be listed
|
||||
services = service_fakes.FakeService.create_one_service()
|
||||
|
||||
def setUp(self):
|
||||
super(TestServiceList, self).setUp()
|
||||
|
||||
self.service_mock.list.return_value = [self.services]
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = service.ListService(self.app, None)
|
||||
|
||||
def test_service_list(self):
|
||||
arglist = [
|
||||
'--host', self.services.host,
|
||||
'--service', self.services.binary,
|
||||
]
|
||||
verifylist = [
|
||||
('host', self.services.host),
|
||||
('service', self.services.binary),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
# In base command class Lister in cliff, abstract method take_action()
|
||||
# returns a tuple containing the column names and an iterable
|
||||
# containing the data to be listed.
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
expected_columns = [
|
||||
'Binary',
|
||||
'Host',
|
||||
'Zone',
|
||||
'Status',
|
||||
'State',
|
||||
'Updated At',
|
||||
]
|
||||
|
||||
# confirming if all expected columns are present in the result.
|
||||
self.assertEqual(expected_columns, columns)
|
||||
|
||||
datalist = ((
|
||||
self.services.binary,
|
||||
self.services.host,
|
||||
self.services.zone,
|
||||
self.services.status,
|
||||
self.services.state,
|
||||
self.services.updated_at,
|
||||
), )
|
||||
|
||||
# confirming if all expected values are present in the result.
|
||||
self.assertEqual(datalist, tuple(data))
|
||||
|
||||
# checking if proper call was made to list services
|
||||
self.service_mock.list.assert_called_with(
|
||||
self.services.host,
|
||||
self.services.binary,
|
||||
)
|
||||
|
||||
# checking if prohibited columns are present in output
|
||||
self.assertNotIn("Disabled Reason", columns)
|
||||
self.assertNotIn(self.services.disabled_reason,
|
||||
tuple(data))
|
||||
|
||||
def test_service_list_with_long_option(self):
|
||||
arglist = [
|
||||
'--host', self.services.host,
|
||||
'--service', self.services.binary,
|
||||
'--long'
|
||||
]
|
||||
verifylist = [
|
||||
('host', self.services.host),
|
||||
('service', self.services.binary),
|
||||
('long', True)
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
# In base command class Lister in cliff, abstract method take_action()
|
||||
# returns a tuple containing the column names and an iterable
|
||||
# containing the data to be listed.
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
expected_columns = [
|
||||
'Binary',
|
||||
'Host',
|
||||
'Zone',
|
||||
'Status',
|
||||
'State',
|
||||
'Updated At',
|
||||
'Disabled Reason'
|
||||
]
|
||||
|
||||
# confirming if all expected columns are present in the result.
|
||||
self.assertEqual(expected_columns, columns)
|
||||
|
||||
datalist = ((
|
||||
self.services.binary,
|
||||
self.services.host,
|
||||
self.services.zone,
|
||||
self.services.status,
|
||||
self.services.state,
|
||||
self.services.updated_at,
|
||||
self.services.disabled_reason,
|
||||
), )
|
||||
|
||||
# confirming if all expected values are present in the result.
|
||||
self.assertEqual(datalist, tuple(data))
|
||||
|
||||
self.service_mock.list.assert_called_with(
|
||||
self.services.host,
|
||||
self.services.binary,
|
||||
)
|
70
openstackclient/volume/v1/service.py
Normal file
70
openstackclient/volume/v1/service.py
Normal file
@ -0,0 +1,70 @@
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
"""Service action implementations"""
|
||||
|
||||
from openstackclient.common import command
|
||||
from openstackclient.common import utils
|
||||
|
||||
|
||||
class ListService(command.Lister):
|
||||
"""List service command"""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListService, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
"--host",
|
||||
metavar="<host>",
|
||||
help="List services on specified host (name only)")
|
||||
parser.add_argument(
|
||||
"--service",
|
||||
metavar="<service>",
|
||||
help="List only specified service (name only)")
|
||||
parser.add_argument(
|
||||
"--long",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="List additional fields in output"
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
service_client = self.app.client_manager.volume
|
||||
|
||||
if parsed_args.long:
|
||||
columns = [
|
||||
"Binary",
|
||||
"Host",
|
||||
"Zone",
|
||||
"Status",
|
||||
"State",
|
||||
"Updated At",
|
||||
"Disabled Reason"
|
||||
]
|
||||
else:
|
||||
columns = [
|
||||
"Binary",
|
||||
"Host",
|
||||
"Zone",
|
||||
"Status",
|
||||
"State",
|
||||
"Updated At"
|
||||
]
|
||||
|
||||
data = service_client.services.list(parsed_args.host,
|
||||
parsed_args.service)
|
||||
return (columns,
|
||||
(utils.get_item_properties(
|
||||
s, columns,
|
||||
) for s in data))
|
70
openstackclient/volume/v2/service.py
Normal file
70
openstackclient/volume/v2/service.py
Normal file
@ -0,0 +1,70 @@
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
"""Service action implementations"""
|
||||
|
||||
from openstackclient.common import command
|
||||
from openstackclient.common import utils
|
||||
|
||||
|
||||
class ListService(command.Lister):
|
||||
"""List service command"""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListService, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
"--host",
|
||||
metavar="<host>",
|
||||
help="List services on specified host (name only)")
|
||||
parser.add_argument(
|
||||
"--service",
|
||||
metavar="<service>",
|
||||
help="List only specified service (name only)")
|
||||
parser.add_argument(
|
||||
"--long",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="List additional fields in output"
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
service_client = self.app.client_manager.volume
|
||||
|
||||
if parsed_args.long:
|
||||
columns = [
|
||||
"Binary",
|
||||
"Host",
|
||||
"Zone",
|
||||
"Status",
|
||||
"State",
|
||||
"Updated At",
|
||||
"Disabled Reason"
|
||||
]
|
||||
else:
|
||||
columns = [
|
||||
"Binary",
|
||||
"Host",
|
||||
"Zone",
|
||||
"Status",
|
||||
"State",
|
||||
"Updated At"
|
||||
]
|
||||
|
||||
data = service_client.services.list(parsed_args.host,
|
||||
parsed_args.service)
|
||||
return (columns,
|
||||
(utils.get_item_properties(
|
||||
s, columns,
|
||||
) for s in data))
|
9
releasenotes/notes/volume_service-5e352a71dfbc828d.yaml
Normal file
9
releasenotes/notes/volume_service-5e352a71dfbc828d.yaml
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Adds support for volume service list.
|
||||
|
||||
An user can list available volume services by using
|
||||
``volume service list``
|
||||
|
||||
[Bug 1550999 'https://bugs.launchpad.net/python-openstackclient/+bug/1550999'_]
|
@ -421,6 +421,8 @@ openstack.volume.v1 =
|
||||
volume_qos_show = openstackclient.volume.v1.qos_specs:ShowQos
|
||||
volume_qos_unset = openstackclient.volume.v1.qos_specs:UnsetQos
|
||||
|
||||
volume_service_list = openstackclient.volume.v1.service:ListService
|
||||
|
||||
openstack.volume.v2 =
|
||||
backup_create = openstackclient.volume.v2.backup:CreateBackup
|
||||
backup_delete = openstackclient.volume.v2.backup:DeleteBackup
|
||||
@ -458,6 +460,8 @@ openstack.volume.v2 =
|
||||
volume_qos_show = openstackclient.volume.v2.qos_specs:ShowQos
|
||||
volume_qos_unset = openstackclient.volume.v2.qos_specs:UnsetQos
|
||||
|
||||
volume_service_list = openstackclient.volume.v2.service:ListService
|
||||
|
||||
[build_sphinx]
|
||||
source-dir = doc/source
|
||||
build-dir = doc/build
|
||||
|
Loading…
Reference in New Issue
Block a user