Skip to content

Commit 4d332de

Browse files
committed
Support listing network availability zones
Update the "os availability zone list" command to support listing network availability zones along with the currently listed compute and volume availability zones. This adds the --network option to the command in order to only list network availability zones. By default, all availability zones are listed. The --long option was also updated to include a "Zone Resource" column which is applicable to network availability zones. Example zone resources include "network" and "router". If the Network API does not support listing availability zones then a warning message will be issued when the --network option is specified. This support requires an updated release of the SDK in order to pull in [1]. [1] https://bugs.launchpad.net/python-openstacksdk/+bug/1532274 Change-Id: I78811d659b793d9d2111ea54665d5fe7e4887264 Closes-Bug: #1534202
1 parent f36177e commit 4d332de

6 files changed

Lines changed: 188 additions & 12 deletions

File tree

doc/source/command-objects/availability-zone.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
availability zone
33
=================
44

5-
Compute v2, Block Storage v2
5+
Block Storage v2, Compute v2, Network v2
66

77
availability zone list
88
----------------------
@@ -14,13 +14,18 @@ List availability zones and their status
1414
1515
os availability zone list
1616
[--compute]
17+
[--network]
1718
[--volume]
1819
[--long]
1920
2021
.. option:: --compute
2122

2223
List compute availability zones
2324

25+
.. option:: --network
26+
27+
List network availability zones
28+
2429
.. option:: --volume
2530

2631
List volume availability zones

doc/source/commands.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ the API resources will be merged, as in the ``quota`` object that has options
7070
referring to both Compute and Volume quotas.
7171

7272
* ``access token``: (**Identity**) long-lived OAuth-based token
73-
* ``availability zone``: (**Compute**, **Volume**) a logical partition of hosts or block storage services
73+
* ``availability zone``: (**Compute**, **Network**, **Volume**) a logical partition of hosts or block storage or network services
7474
* ``aggregate``: (**Compute**) a grouping of servers
7575
* ``backup``: (**Volume**) a volume copy
7676
* ``catalog``: (**Identity**) service catalog

openstackclient/common/availability_zone.py

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ def _xform_common_availability_zone(az, zone_info):
3030
if hasattr(az, 'zoneName'):
3131
zone_info['zone_name'] = az.zoneName
3232

33+
zone_info['zone_resource'] = ''
34+
3335

3436
def _xform_compute_availability_zone(az, include_extra):
3537
result = []
@@ -69,6 +71,18 @@ def _xform_volume_availability_zone(az):
6971
return result
7072

7173

74+
def _xform_network_availability_zone(az):
75+
result = []
76+
zone_info = {}
77+
zone_info['zone_name'] = getattr(az, 'name', '')
78+
zone_info['zone_status'] = getattr(az, 'state', '')
79+
if 'unavailable' == zone_info['zone_status']:
80+
zone_info['zone_status'] = 'not available'
81+
zone_info['zone_resource'] = getattr(az, 'resource', '')
82+
result.append(zone_info)
83+
return result
84+
85+
7286
class ListAvailabilityZone(command.Lister):
7387
"""List availability zones and their status"""
7488

@@ -79,6 +93,11 @@ def get_parser(self, prog_name):
7993
action='store_true',
8094
default=False,
8195
help='List compute availability zones')
96+
parser.add_argument(
97+
'--network',
98+
action='store_true',
99+
default=False,
100+
help='List network availability zones')
82101
parser.add_argument(
83102
'--volume',
84103
action='store_true',
@@ -92,7 +111,7 @@ def get_parser(self, prog_name):
92111
)
93112
return parser
94113

95-
def get_compute_availability_zones(self, parsed_args):
114+
def _get_compute_availability_zones(self, parsed_args):
96115
compute_client = self.app.client_manager.compute
97116
try:
98117
data = compute_client.availability_zones.list()
@@ -108,36 +127,63 @@ def get_compute_availability_zones(self, parsed_args):
108127
result += _xform_compute_availability_zone(zone, parsed_args.long)
109128
return result
110129

111-
def get_volume_availability_zones(self, parsed_args):
130+
def _get_volume_availability_zones(self, parsed_args):
112131
volume_client = self.app.client_manager.volume
132+
data = []
113133
try:
114134
data = volume_client.availability_zones.list()
115-
except Exception:
116-
message = "Availability zones list not supported by " \
117-
"Block Storage API"
118-
self.log.warning(message)
135+
except Exception as e:
136+
self.log.debug('Volume availability zone exception: ' + str(e))
137+
if parsed_args.volume:
138+
message = "Availability zones list not supported by " \
139+
"Block Storage API"
140+
self.log.warning(message)
119141

120142
result = []
121143
for zone in data:
122144
result += _xform_volume_availability_zone(zone)
123145
return result
124146

147+
def _get_network_availability_zones(self, parsed_args):
148+
network_client = self.app.client_manager.network
149+
data = []
150+
try:
151+
# Verify that the extension exists.
152+
network_client.find_extension('Availability Zone',
153+
ignore_missing=False)
154+
data = network_client.availability_zones()
155+
except Exception as e:
156+
self.log.debug('Network availability zone exception: ' + str(e))
157+
if parsed_args.network:
158+
message = "Availability zones list not supported by " \
159+
"Network API"
160+
self.log.warning(message)
161+
162+
result = []
163+
for zone in data:
164+
result += _xform_network_availability_zone(zone)
165+
return result
166+
125167
def take_action(self, parsed_args):
126168

127169
if parsed_args.long:
128-
columns = ('Zone Name', 'Zone Status',
170+
columns = ('Zone Name', 'Zone Status', 'Zone Resource',
129171
'Host Name', 'Service Name', 'Service Status')
130172
else:
131173
columns = ('Zone Name', 'Zone Status')
132174

133175
# Show everything by default.
134-
show_all = (not parsed_args.compute and not parsed_args.volume)
176+
show_all = (not parsed_args.compute and
177+
not parsed_args.volume and
178+
not parsed_args.network)
135179

136180
result = []
137181
if parsed_args.compute or show_all:
138-
result += self.get_compute_availability_zones(parsed_args)
182+
result += self._get_compute_availability_zones(parsed_args)
139183
if parsed_args.volume or show_all:
140-
result += self.get_volume_availability_zones(parsed_args)
184+
result += self._get_volume_availability_zones(parsed_args)
185+
if parsed_args.network or show_all:
186+
result += self._get_network_availability_zones(parsed_args)
141187

142188
return (columns,
143189
(utils.get_dict_properties(

openstackclient/tests/common/test_availability_zone.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@
1111
# under the License.
1212
#
1313

14+
import mock
1415
import six
1516

1617
from openstackclient.common import availability_zone
1718
from openstackclient.tests.compute.v2 import fakes as compute_fakes
1819
from openstackclient.tests import fakes
20+
from openstackclient.tests.network.v2 import fakes as network_fakes
1921
from openstackclient.tests import utils
2022
from openstackclient.tests.volume.v2 import fakes as volume_fakes
2123

@@ -33,6 +35,7 @@ def _build_compute_az_datalist(compute_az, long_datalist=False):
3335
datalist += (
3436
compute_az.zoneName,
3537
'available',
38+
'',
3639
host,
3740
service,
3841
'enabled :-) ' + state['updated_at'],
@@ -51,6 +54,23 @@ def _build_volume_az_datalist(volume_az, long_datalist=False):
5154
datalist = (
5255
volume_az.zoneName,
5356
'available',
57+
'', '', '', '',
58+
)
59+
return (datalist,)
60+
61+
62+
def _build_network_az_datalist(network_az, long_datalist=False):
63+
datalist = ()
64+
if not long_datalist:
65+
datalist = (
66+
network_az.name,
67+
network_az.state,
68+
)
69+
else:
70+
datalist = (
71+
network_az.name,
72+
network_az.state,
73+
network_az.resource,
5474
'', '', '',
5575
)
5676
return (datalist,)
@@ -79,18 +99,31 @@ def setUp(self):
7999
self.volume_azs_mock = volume_client.availability_zones
80100
self.volume_azs_mock.reset_mock()
81101

102+
network_client = network_fakes.FakeNetworkV2Client(
103+
endpoint=fakes.AUTH_URL,
104+
token=fakes.AUTH_TOKEN,
105+
)
106+
self.app.client_manager.network = network_client
107+
108+
network_client.availability_zones = mock.Mock()
109+
network_client.find_extension = mock.Mock()
110+
self.network_azs_mock = network_client.availability_zones
111+
82112

83113
class TestAvailabilityZoneList(TestAvailabilityZone):
84114

85115
compute_azs = \
86116
compute_fakes.FakeAvailabilityZone.create_availability_zones()
87117
volume_azs = \
88118
volume_fakes.FakeAvailabilityZone.create_availability_zones(count=1)
119+
network_azs = \
120+
network_fakes.FakeAvailabilityZone.create_availability_zones()
89121

90122
short_columnslist = ('Zone Name', 'Zone Status')
91123
long_columnslist = (
92124
'Zone Name',
93125
'Zone Status',
126+
'Zone Resource',
94127
'Host Name',
95128
'Service Name',
96129
'Service Status',
@@ -101,6 +134,7 @@ def setUp(self):
101134

102135
self.compute_azs_mock.list.return_value = self.compute_azs
103136
self.volume_azs_mock.list.return_value = self.volume_azs
137+
self.network_azs_mock.return_value = self.network_azs
104138

105139
# Get the command object to test
106140
self.cmd = availability_zone.ListAvailabilityZone(self.app, None)
@@ -115,13 +149,16 @@ def test_availability_zone_list_no_options(self):
115149

116150
self.compute_azs_mock.list.assert_called_with()
117151
self.volume_azs_mock.list.assert_called_with()
152+
self.network_azs_mock.assert_called_with()
118153

119154
self.assertEqual(self.short_columnslist, columns)
120155
datalist = ()
121156
for compute_az in self.compute_azs:
122157
datalist += _build_compute_az_datalist(compute_az)
123158
for volume_az in self.volume_azs:
124159
datalist += _build_volume_az_datalist(volume_az)
160+
for network_az in self.network_azs:
161+
datalist += _build_network_az_datalist(network_az)
125162
self.assertEqual(datalist, tuple(data))
126163

127164
def test_availability_zone_list_long(self):
@@ -138,6 +175,7 @@ def test_availability_zone_list_long(self):
138175

139176
self.compute_azs_mock.list.assert_called_with()
140177
self.volume_azs_mock.list.assert_called_with()
178+
self.network_azs_mock.assert_called_with()
141179

142180
self.assertEqual(self.long_columnslist, columns)
143181
datalist = ()
@@ -147,6 +185,9 @@ def test_availability_zone_list_long(self):
147185
for volume_az in self.volume_azs:
148186
datalist += _build_volume_az_datalist(volume_az,
149187
long_datalist=True)
188+
for network_az in self.network_azs:
189+
datalist += _build_network_az_datalist(network_az,
190+
long_datalist=True)
150191
self.assertEqual(datalist, tuple(data))
151192

152193
def test_availability_zone_list_compute(self):
@@ -163,6 +204,7 @@ def test_availability_zone_list_compute(self):
163204

164205
self.compute_azs_mock.list.assert_called_with()
165206
self.volume_azs_mock.list.assert_not_called()
207+
self.network_azs_mock.assert_not_called()
166208

167209
self.assertEqual(self.short_columnslist, columns)
168210
datalist = ()
@@ -184,9 +226,32 @@ def test_availability_zone_list_volume(self):
184226

185227
self.compute_azs_mock.list.assert_not_called()
186228
self.volume_azs_mock.list.assert_called_with()
229+
self.network_azs_mock.assert_not_called()
187230

188231
self.assertEqual(self.short_columnslist, columns)
189232
datalist = ()
190233
for volume_az in self.volume_azs:
191234
datalist += _build_volume_az_datalist(volume_az)
192235
self.assertEqual(datalist, tuple(data))
236+
237+
def test_availability_zone_list_network(self):
238+
arglist = [
239+
'--network',
240+
]
241+
verifylist = [
242+
('network', True),
243+
]
244+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
245+
246+
# DisplayCommandBase.take_action() returns two tuples
247+
columns, data = self.cmd.take_action(parsed_args)
248+
249+
self.compute_azs_mock.list.assert_not_called()
250+
self.volume_azs_mock.list.assert_not_called()
251+
self.network_azs_mock.assert_called_with()
252+
253+
self.assertEqual(self.short_columnslist, columns)
254+
datalist = ()
255+
for network_az in self.network_azs:
256+
datalist += _build_network_az_datalist(network_az)
257+
self.assertEqual(datalist, tuple(data))

openstackclient/tests/network/v2/fakes.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,59 @@ def setUp(self):
6969
)
7070

7171

72+
class FakeAvailabilityZone(object):
73+
"""Fake one or more network availability zones (AZs)."""
74+
75+
@staticmethod
76+
def create_one_availability_zone(attrs={}, methods={}):
77+
"""Create a fake AZ.
78+
79+
:param Dictionary attrs:
80+
A dictionary with all attributes
81+
:param Dictionary methods:
82+
A dictionary with all methods
83+
:return:
84+
A FakeResource object with name, state, etc.
85+
"""
86+
# Set default attributes.
87+
availability_zone = {
88+
'name': uuid.uuid4().hex,
89+
'state': 'available',
90+
'resource': 'network',
91+
}
92+
93+
# Overwrite default attributes.
94+
availability_zone.update(attrs)
95+
96+
availability_zone = fakes.FakeResource(
97+
info=copy.deepcopy(availability_zone),
98+
methods=methods,
99+
loaded=True)
100+
return availability_zone
101+
102+
@staticmethod
103+
def create_availability_zones(attrs={}, methods={}, count=2):
104+
"""Create multiple fake AZs.
105+
106+
:param Dictionary attrs:
107+
A dictionary with all attributes
108+
:param Dictionary methods:
109+
A dictionary with all methods
110+
:param int count:
111+
The number of AZs to fake
112+
:return:
113+
A list of FakeResource objects faking the AZs
114+
"""
115+
availability_zones = []
116+
for i in range(0, count):
117+
availability_zone = \
118+
FakeAvailabilityZone.create_one_availability_zone(
119+
attrs, methods)
120+
availability_zones.append(availability_zone)
121+
122+
return availability_zones
123+
124+
72125
class FakeNetwork(object):
73126
"""Fake one or more networks."""
74127

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
features:
3+
- |
4+
Add network support to `os availability zone list`
5+
[Bug `1534202 <https://bugs.launchpad.net/bugs/1534202>`_]
6+
7+
* New `--network` option to only list network availability zones.

0 commit comments

Comments
 (0)