summaryrefslogtreecommitdiff
path: root/openstackclient
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2016-01-22 19:23:20 +0000
committerGerrit Code Review <review@openstack.org>2016-01-22 19:23:20 +0000
commitee78fb2f782d3508cfa59df998d83f34963174ae (patch)
treef8f1029fc043c73d68267d0012290aa2f7f157cd /openstackclient
parent09be6a439a48c277af78346ce776de2df8830e98 (diff)
parenta8ec2ac49475c60c8e72a0fc3db6df778918bb49 (diff)
downloadpython-openstackclient-ee78fb2f782d3508cfa59df998d83f34963174ae.tar.gz
Merge "Support listing volume availability zones"
Diffstat (limited to 'openstackclient')
-rw-r--r--openstackclient/common/availability_zone.py75
-rw-r--r--openstackclient/tests/common/test_availability_zone.py99
-rw-r--r--openstackclient/tests/volume/v2/fakes.py54
3 files changed, 204 insertions, 24 deletions
diff --git a/openstackclient/common/availability_zone.py b/openstackclient/common/availability_zone.py
index 0fe6c73a..e72732e7 100644
--- a/openstackclient/common/availability_zone.py
+++ b/openstackclient/common/availability_zone.py
@@ -11,7 +11,7 @@
# under the License.
#
-"""Compute v2 Availability Zone action implementations"""
+"""Availability Zone action implementations"""
import copy
import logging
@@ -24,15 +24,19 @@ from openstackclient.common import utils
from openstackclient.i18n import _ # noqa
-def _xform_availability_zone(az, include_extra):
- result = []
- zone_info = {}
+def _xform_common_availability_zone(az, zone_info):
if hasattr(az, 'zoneState'):
zone_info['zone_status'] = ('available' if az.zoneState['available']
else 'not available')
if hasattr(az, 'zoneName'):
zone_info['zone_name'] = az.zoneName
+
+def _xform_compute_availability_zone(az, include_extra):
+ result = []
+ zone_info = {}
+ _xform_common_availability_zone(az, zone_info)
+
if not include_extra:
result.append(zone_info)
return result
@@ -58,6 +62,14 @@ def _xform_availability_zone(az, include_extra):
return result
+def _xform_volume_availability_zone(az):
+ result = []
+ zone_info = {}
+ _xform_common_availability_zone(az, zone_info)
+ result.append(zone_info)
+ return result
+
+
class ListAvailabilityZone(lister.Lister):
"""List availability zones and their status"""
@@ -66,6 +78,16 @@ class ListAvailabilityZone(lister.Lister):
def get_parser(self, prog_name):
parser = super(ListAvailabilityZone, self).get_parser(prog_name)
parser.add_argument(
+ '--compute',
+ action='store_true',
+ default=False,
+ help='List compute availability zones')
+ parser.add_argument(
+ '--volume',
+ action='store_true',
+ default=False,
+ help='List volume availability zones')
+ parser.add_argument(
'--long',
action='store_true',
default=False,
@@ -73,15 +95,7 @@ class ListAvailabilityZone(lister.Lister):
)
return parser
- @utils.log_method(log)
- def take_action(self, parsed_args):
-
- if parsed_args.long:
- columns = ('Zone Name', 'Zone Status',
- 'Host Name', 'Service Name', 'Service Status')
- else:
- columns = ('Zone Name', 'Zone Status')
-
+ def get_compute_availability_zones(self, parsed_args):
compute_client = self.app.client_manager.compute
try:
data = compute_client.availability_zones.list()
@@ -94,7 +108,40 @@ class ListAvailabilityZone(lister.Lister):
# Argh, the availability zones are not iterable...
result = []
for zone in data:
- result += _xform_availability_zone(zone, parsed_args.long)
+ result += _xform_compute_availability_zone(zone, parsed_args.long)
+ return result
+
+ def get_volume_availability_zones(self, parsed_args):
+ volume_client = self.app.client_manager.volume
+ try:
+ data = volume_client.availability_zones.list()
+ except Exception:
+ message = "Availability zones list not supported by " \
+ "Block Storage API"
+ self.log.warning(message)
+
+ result = []
+ for zone in data:
+ result += _xform_volume_availability_zone(zone)
+ return result
+
+ @utils.log_method(log)
+ def take_action(self, parsed_args):
+
+ if parsed_args.long:
+ columns = ('Zone Name', 'Zone Status',
+ 'Host Name', 'Service Name', 'Service Status')
+ else:
+ columns = ('Zone Name', 'Zone Status')
+
+ # Show everything by default.
+ show_all = (not parsed_args.compute and not parsed_args.volume)
+
+ result = []
+ if parsed_args.compute or show_all:
+ result += self.get_compute_availability_zones(parsed_args)
+ if parsed_args.volume or show_all:
+ result += self.get_volume_availability_zones(parsed_args)
return (columns,
(utils.get_dict_properties(
diff --git a/openstackclient/tests/common/test_availability_zone.py b/openstackclient/tests/common/test_availability_zone.py
index 35089d06..232b56c9 100644
--- a/openstackclient/tests/common/test_availability_zone.py
+++ b/openstackclient/tests/common/test_availability_zone.py
@@ -17,6 +17,7 @@ from openstackclient.common import availability_zone
from openstackclient.tests.compute.v2 import fakes as compute_fakes
from openstackclient.tests import fakes
from openstackclient.tests import utils
+from openstackclient.tests.volume.v2 import fakes as volume_fakes
def _build_compute_az_datalist(compute_az, long_datalist=False):
@@ -39,6 +40,22 @@ def _build_compute_az_datalist(compute_az, long_datalist=False):
return (datalist,)
+def _build_volume_az_datalist(volume_az, long_datalist=False):
+ datalist = ()
+ if not long_datalist:
+ datalist = (
+ volume_az.zoneName,
+ 'available',
+ )
+ else:
+ datalist = (
+ volume_az.zoneName,
+ 'available',
+ '', '', '',
+ )
+ return (datalist,)
+
+
class TestAvailabilityZone(utils.TestCommand):
def setUp(self):
@@ -53,16 +70,37 @@ class TestAvailabilityZone(utils.TestCommand):
self.compute_azs_mock = compute_client.availability_zones
self.compute_azs_mock.reset_mock()
+ volume_client = volume_fakes.FakeVolumeClient(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+ self.app.client_manager.volume = volume_client
+
+ self.volume_azs_mock = volume_client.availability_zones
+ self.volume_azs_mock.reset_mock()
+
class TestAvailabilityZoneList(TestAvailabilityZone):
compute_azs = \
compute_fakes.FakeAvailabilityZone.create_availability_zones()
+ volume_azs = \
+ volume_fakes.FakeAvailabilityZone.create_availability_zones(count=1)
+
+ short_columnslist = ('Zone Name', 'Zone Status')
+ long_columnslist = (
+ 'Zone Name',
+ 'Zone Status',
+ 'Host Name',
+ 'Service Name',
+ 'Service Status',
+ )
def setUp(self):
super(TestAvailabilityZoneList, self).setUp()
self.compute_azs_mock.list.return_value = self.compute_azs
+ self.volume_azs_mock.list.return_value = self.volume_azs
# Get the command object to test
self.cmd = availability_zone.ListAvailabilityZone(self.app, None)
@@ -76,12 +114,14 @@ class TestAvailabilityZoneList(TestAvailabilityZone):
columns, data = self.cmd.take_action(parsed_args)
self.compute_azs_mock.list.assert_called_with()
+ self.volume_azs_mock.list.assert_called_with()
- columnslist = ('Zone Name', 'Zone Status')
- self.assertEqual(columnslist, columns)
+ self.assertEqual(self.short_columnslist, columns)
datalist = ()
for compute_az in self.compute_azs:
datalist += _build_compute_az_datalist(compute_az)
+ for volume_az in self.volume_azs:
+ datalist += _build_volume_az_datalist(volume_az)
self.assertEqual(datalist, tuple(data))
def test_availability_zone_list_long(self):
@@ -97,17 +137,56 @@ class TestAvailabilityZoneList(TestAvailabilityZone):
columns, data = self.cmd.take_action(parsed_args)
self.compute_azs_mock.list.assert_called_with()
+ self.volume_azs_mock.list.assert_called_with()
- columnslist = (
- 'Zone Name',
- 'Zone Status',
- 'Host Name',
- 'Service Name',
- 'Service Status',
- )
- self.assertEqual(columnslist, columns)
+ self.assertEqual(self.long_columnslist, columns)
datalist = ()
for compute_az in self.compute_azs:
datalist += _build_compute_az_datalist(compute_az,
long_datalist=True)
+ for volume_az in self.volume_azs:
+ datalist += _build_volume_az_datalist(volume_az,
+ long_datalist=True)
+ self.assertEqual(datalist, tuple(data))
+
+ def test_availability_zone_list_compute(self):
+ arglist = [
+ '--compute',
+ ]
+ verifylist = [
+ ('compute', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # DisplayCommandBase.take_action() returns two tuples
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.compute_azs_mock.list.assert_called_with()
+ self.volume_azs_mock.list.assert_not_called()
+
+ self.assertEqual(self.short_columnslist, columns)
+ datalist = ()
+ for compute_az in self.compute_azs:
+ datalist += _build_compute_az_datalist(compute_az)
+ self.assertEqual(datalist, tuple(data))
+
+ def test_availability_zone_list_volume(self):
+ arglist = [
+ '--volume',
+ ]
+ verifylist = [
+ ('volume', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # DisplayCommandBase.take_action() returns two tuples
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.compute_azs_mock.list.assert_not_called()
+ self.volume_azs_mock.list.assert_called_with()
+
+ self.assertEqual(self.short_columnslist, columns)
+ datalist = ()
+ for volume_az in self.volume_azs:
+ datalist += _build_volume_az_datalist(volume_az)
self.assertEqual(datalist, tuple(data))
diff --git a/openstackclient/tests/volume/v2/fakes.py b/openstackclient/tests/volume/v2/fakes.py
index 60cec335..2e58e58d 100644
--- a/openstackclient/tests/volume/v2/fakes.py
+++ b/openstackclient/tests/volume/v2/fakes.py
@@ -202,6 +202,8 @@ class FakeVolumeClient(object):
self.restores.resource_class = fakes.FakeResource(None, {})
self.qos_specs = mock.Mock()
self.qos_specs.resource_class = fakes.FakeResource(None, {})
+ self.availability_zones = mock.Mock()
+ self.availability_zones.resource_class = fakes.FakeResource(None, {})
self.auth_token = kwargs['token']
self.management_url = kwargs['endpoint']
@@ -304,3 +306,55 @@ class FakeVolume(object):
volumes = FakeVolume.create_volumes(count)
return mock.MagicMock(side_effect=volumes)
+
+
+class FakeAvailabilityZone(object):
+ """Fake one or more volume availability zones (AZs)."""
+
+ @staticmethod
+ def create_one_availability_zone(attrs={}, methods={}):
+ """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.
+ """
+ # Set default attributes.
+ availability_zone = {
+ 'zoneName': uuid.uuid4().hex,
+ 'zoneState': {'available': True},
+ }
+
+ # Overwrite default attributes.
+ availability_zone.update(attrs)
+
+ 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):
+ """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:
+ A list of FakeResource objects faking the AZs
+ """
+ availability_zones = []
+ for i in range(0, count):
+ availability_zone = \
+ FakeAvailabilityZone.create_one_availability_zone(
+ attrs, methods)
+ availability_zones.append(availability_zone)
+
+ return availability_zones