From 8059b3c80416297c9ebbfdf689c6c27611ff8ed7 Mon Sep 17 00:00:00 2001 From: Monty Taylor Date: Mon, 27 Mar 2017 11:32:39 -0500 Subject: [PATCH] Add list_availability_zone_names method Nodepool would like to do smart things with scheduling across AZs. In order for it to that, it needs a list of them, which we can provide. Change-Id: I9a3b97ccb797ea7a66a832b03da2bd4afd659097 --- .../notes/list-az-names-a38c277d1192471b.yaml | 3 + shade/openstackcloud.py | 23 ++++++ shade/tests/functional/test_compute.py | 4 + shade/tests/unit/test_availability_zones.py | 79 +++++++++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 releasenotes/notes/list-az-names-a38c277d1192471b.yaml create mode 100644 shade/tests/unit/test_availability_zones.py diff --git a/releasenotes/notes/list-az-names-a38c277d1192471b.yaml b/releasenotes/notes/list-az-names-a38c277d1192471b.yaml new file mode 100644 index 000000000..7b492716d --- /dev/null +++ b/releasenotes/notes/list-az-names-a38c277d1192471b.yaml @@ -0,0 +1,3 @@ +--- +features: + - Added list_availability_zone_names API call. diff --git a/shade/openstackcloud.py b/shade/openstackcloud.py index 2c7f988f2..45b48bab5 100644 --- a/shade/openstackcloud.py +++ b/shade/openstackcloud.py @@ -1733,6 +1733,29 @@ class OpenStackCloud(_normalize.Normalizer): return self._normalize_volume_types( self.manager.submit_task(_tasks.VolumeTypeList())) + @_utils.cache_on_arguments() + def list_availability_zone_names(self, unavailable=False): + """List names of availability zones. + + :param bool unavailable: Whether or not to include unavailable zones + in the output. Defaults to False. + + :returns: A list of availability zone names, or an empty list if the + list could not be fetched. + """ + try: + zones = self._compute_client.get('/os-availability-zone') + except OpenStackCloudHTTPError: + self.log.debug( + "Availability zone list could not be fetched", + exc_info=True) + return [] + ret = [] + for zone in zones: + if zone['zoneState']['available'] or unavailable: + ret.append(zone['zoneName']) + return ret + @_utils.cache_on_arguments() def list_flavors(self, get_extra=True): """List all available flavors. diff --git a/shade/tests/functional/test_compute.py b/shade/tests/functional/test_compute.py index ef4cacdcb..25e609e7f 100644 --- a/shade/tests/functional/test_compute.py +++ b/shade/tests/functional/test_compute.py @@ -148,6 +148,10 @@ class TestCompute(base.BaseFunctionalTestCase): if len(log) > 0: break + def test_list_availability_zone_names(self): + self.assertEqual( + ['nova'], self.user_cloud.list_availability_zone_names()) + def test_get_server_console_bad_server(self): self.assertRaises( exc.OpenStackCloudException, diff --git a/shade/tests/unit/test_availability_zones.py b/shade/tests/unit/test_availability_zones.py new file mode 100644 index 000000000..fbbd8cc99 --- /dev/null +++ b/shade/tests/unit/test_availability_zones.py @@ -0,0 +1,79 @@ +# Copyright (c) 2017 Red Hat, Inc. +# 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 shade.tests.unit import base +from shade.tests import fakes + + +_fake_zone_list = { + "availabilityZoneInfo": [ + { + "hosts": None, + "zoneName": "az1", + "zoneState": { + "available": True + } + }, + { + "hosts": None, + "zoneName": "nova", + "zoneState": { + "available": False + } + } + ] +} + + +class TestAvailabilityZoneNames(base.RequestsMockTestCase): + + def test_list_availability_zone_names(self): + self.register_uris([ + dict(method='GET', + uri='{endpoint}/os-availability-zone'.format( + endpoint=fakes.COMPUTE_ENDPOINT), + json=_fake_zone_list), + ]) + + self.assertEqual( + ['az1'], self.cloud.list_availability_zone_names()) + + self.assert_calls() + + def test_unauthorized_availability_zone_names(self): + self.register_uris([ + dict(method='GET', + uri='{endpoint}/os-availability-zone'.format( + endpoint=fakes.COMPUTE_ENDPOINT), + status_code=403), + ]) + + self.assertEqual( + [], self.cloud.list_availability_zone_names()) + + self.assert_calls() + + def test_list_all_availability_zone_names(self): + self.register_uris([ + dict(method='GET', + uri='{endpoint}/os-availability-zone'.format( + endpoint=fakes.COMPUTE_ENDPOINT), + json=_fake_zone_list), + ]) + + self.assertEqual( + ['az1', 'nova'], + self.cloud.list_availability_zone_names(unavailable=True)) + + self.assert_calls()