python-openstackclient 7.0.0__py3-none-any.whl → 7.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. openstackclient/common/clientmanager.py +22 -30
  2. openstackclient/common/limits.py +3 -4
  3. openstackclient/common/quota.py +28 -23
  4. openstackclient/compute/v2/aggregate.py +29 -23
  5. openstackclient/compute/v2/hypervisor.py +5 -3
  6. openstackclient/compute/v2/server.py +5 -4
  7. openstackclient/identity/v3/application_credential.py +17 -17
  8. openstackclient/identity/v3/service.py +5 -5
  9. openstackclient/releasenotes/notes/volume-backup-created-at-list-b49ec893ae1f6b0d.yaml +4 -0
  10. openstackclient/tests/functional/identity/v3/common.py +2 -2
  11. openstackclient/tests/functional/identity/v3/test_application_credential.py +7 -7
  12. openstackclient/tests/functional/identity/v3/test_limit.py +2 -2
  13. openstackclient/tests/functional/identity/v3/test_registered_limit.py +1 -1
  14. openstackclient/tests/functional/identity/v3/test_service.py +3 -3
  15. openstackclient/tests/unit/compute/v2/test_aggregate.py +70 -42
  16. openstackclient/tests/unit/compute/v2/test_hypervisor.py +29 -3
  17. openstackclient/tests/unit/compute/v2/test_server.py +23 -62
  18. openstackclient/tests/unit/fakes.py +1 -1
  19. openstackclient/tests/unit/identity/v3/test_application_credential.py +17 -17
  20. openstackclient/tests/unit/identity/v3/test_service.py +6 -6
  21. openstackclient/tests/unit/volume/v2/test_volume_backup.py +3 -0
  22. openstackclient/volume/v2/volume_backup.py +2 -0
  23. {python_openstackclient-7.0.0.dist-info → python_openstackclient-7.1.1.dist-info}/AUTHORS +2 -0
  24. {python_openstackclient-7.0.0.dist-info → python_openstackclient-7.1.1.dist-info}/METADATA +3 -2
  25. {python_openstackclient-7.0.0.dist-info → python_openstackclient-7.1.1.dist-info}/RECORD +30 -29
  26. python_openstackclient-7.1.1.dist-info/pbr.json +1 -0
  27. python_openstackclient-7.0.0.dist-info/pbr.json +0 -1
  28. {python_openstackclient-7.0.0.dist-info → python_openstackclient-7.1.1.dist-info}/LICENSE +0 -0
  29. {python_openstackclient-7.0.0.dist-info → python_openstackclient-7.1.1.dist-info}/WHEEL +0 -0
  30. {python_openstackclient-7.0.0.dist-info → python_openstackclient-7.1.1.dist-info}/entry_points.txt +0 -0
  31. {python_openstackclient-7.0.0.dist-info → python_openstackclient-7.1.1.dist-info}/top_level.txt +0 -0
@@ -116,7 +116,6 @@ class ClientManager(clientmanager.ClientManager):
116
116
 
117
117
  def is_network_endpoint_enabled(self):
118
118
  """Check if the network endpoint is enabled"""
119
-
120
119
  # NOTE(dtroyer): is_service_available() can also return None if
121
120
  # there is no Service Catalog, callers here are
122
121
  # not expecting that so fold None into True to
@@ -125,43 +124,37 @@ class ClientManager(clientmanager.ClientManager):
125
124
 
126
125
  def is_compute_endpoint_enabled(self):
127
126
  """Check if Compute endpoint is enabled"""
128
-
129
127
  return self.is_service_available('compute') is not False
130
128
 
131
- def is_volume_endpoint_enabled(self, volume_client):
129
+ # TODO(stephenfin): Drop volume_client argument in OSC 8.0 or later.
130
+ def is_volume_endpoint_enabled(self, volume_client=None):
132
131
  """Check if volume endpoint is enabled"""
133
- # NOTE(jcross): Cinder did some interesting things with their service
134
- # name so we need to figure out which version to look
135
- # for when calling is_service_available()
136
- endpoint_data = volume_client.get_endpoint_data()
137
- # Not sure how endpoint data stores the api version for v2 API,
138
- # for v3 it is a tuple (3, 0)
139
- if endpoint_data.api_version and isinstance(
140
- endpoint_data.api_version, tuple
141
- ):
142
- volume_version = endpoint_data.api_version[0]
143
- else:
144
- # Setting volume_version as 2 here if it doesn't satisfy the
145
- # conditions for version 3
146
- volume_version = 2
147
- if (
148
- self.is_service_available("volumev%s" % volume_version)
149
- is not False
150
- ):
151
- return True
152
- elif self.is_service_available('volume') is not False:
153
- return True
154
- else:
155
- return False
132
+ return (
133
+ self.is_service_available('volume') is not False
134
+ or self.is_service_available('volumev3') is not False
135
+ or self.is_service_available('volumev2') is not False
136
+ )
156
137
 
157
138
 
158
139
  # Plugin Support
159
140
 
160
141
 
142
+ def _on_load_failure_callback(
143
+ manager: stevedore.ExtensionManager,
144
+ ep: importlib.metadata.EntryPoint,
145
+ err: Exception,
146
+ ) -> None:
147
+ sys.stderr.write(
148
+ f"WARNING: Failed to import plugin {ep.group}:{ep.name}: {err}.\n"
149
+ )
150
+
151
+
161
152
  def get_plugin_modules(group):
162
153
  """Find plugin entry points"""
163
154
  mod_list = []
164
- mgr = stevedore.ExtensionManager(group)
155
+ mgr = stevedore.ExtensionManager(
156
+ group, on_load_failure_callback=_on_load_failure_callback
157
+ )
165
158
  for ep in mgr:
166
159
  LOG.debug('Found plugin %s', ep.name)
167
160
 
@@ -180,9 +173,8 @@ def get_plugin_modules(group):
180
173
  module = importlib.import_module(module_name)
181
174
  except Exception as err:
182
175
  sys.stderr.write(
183
- "WARNING: Failed to import plugin {}: {}.\n".format(
184
- ep.name, err
185
- )
176
+ f"WARNING: Failed to import plugin {ep.group}:{ep.name}: "
177
+ f"{err}.\n"
186
178
  )
187
179
  continue
188
180
 
@@ -101,9 +101,6 @@ class ShowLimits(command.Lister):
101
101
  return parser
102
102
 
103
103
  def take_action(self, parsed_args):
104
- compute_client = self.app.client_manager.sdk_connection.compute
105
- volume_client = self.app.client_manager.sdk_connection.volume
106
-
107
104
  project_id = None
108
105
  if parsed_args.project is not None:
109
106
  identity_client = self.app.client_manager.identity
@@ -125,11 +122,13 @@ class ShowLimits(command.Lister):
125
122
  volume_limits = None
126
123
 
127
124
  if self.app.client_manager.is_compute_endpoint_enabled():
125
+ compute_client = self.app.client_manager.sdk_connection.compute
128
126
  compute_limits = compute_client.get_limits(
129
127
  reserved=parsed_args.is_reserved, tenant_id=project_id
130
128
  )
131
129
 
132
- if self.app.client_manager.is_volume_endpoint_enabled(volume_client):
130
+ if self.app.client_manager.is_volume_endpoint_enabled():
131
+ volume_client = self.app.client_manager.sdk_connection.volume
133
132
  volume_limits = volume_client.get_limits(
134
133
  project_id=project_id,
135
134
  )
@@ -565,33 +565,42 @@ class SetQuota(common.NetDetectionMixin, command.Command):
565
565
  msg = _('--force cannot be used with --class or --default')
566
566
  raise exceptions.CommandError(msg)
567
567
 
568
- compute_client = self.app.client_manager.sdk_connection.compute
569
- volume_client = self.app.client_manager.sdk_connection.volume
570
-
571
568
  compute_kwargs = {}
572
- for k, v in COMPUTE_QUOTAS.items():
573
- value = getattr(parsed_args, k, None)
574
- if value is not None:
575
- compute_kwargs[k] = value
569
+ volume_kwargs = {}
570
+ network_kwargs = {}
576
571
 
577
- if compute_kwargs and parsed_args.force is True:
578
- compute_kwargs['force'] = parsed_args.force
572
+ if self.app.client_manager.is_compute_endpoint_enabled():
573
+ compute_client = self.app.client_manager.sdk_connection.compute
579
574
 
580
- volume_kwargs = {}
581
- for k, v in VOLUME_QUOTAS.items():
582
- value = getattr(parsed_args, k, None)
583
- if value is not None:
584
- if parsed_args.volume_type and k in IMPACT_VOLUME_TYPE_QUOTAS:
585
- k = k + '_%s' % parsed_args.volume_type
586
- volume_kwargs[k] = value
575
+ for k, v in COMPUTE_QUOTAS.items():
576
+ value = getattr(parsed_args, k, None)
577
+ if value is not None:
578
+ compute_kwargs[k] = value
579
+
580
+ if compute_kwargs and parsed_args.force is True:
581
+ compute_kwargs['force'] = parsed_args.force
582
+
583
+ if self.app.client_manager.is_volume_endpoint_enabled():
584
+ volume_client = self.app.client_manager.sdk_connection.volume
585
+
586
+ for k, v in VOLUME_QUOTAS.items():
587
+ value = getattr(parsed_args, k, None)
588
+ if value is not None:
589
+ if (
590
+ parsed_args.volume_type
591
+ and k in IMPACT_VOLUME_TYPE_QUOTAS
592
+ ):
593
+ k = k + '_%s' % parsed_args.volume_type
594
+ volume_kwargs[k] = value
587
595
 
588
- network_kwargs = {}
589
596
  if self.app.client_manager.is_network_endpoint_enabled():
597
+ network_client = self.app.client_manager.network
598
+
590
599
  for k, v in NETWORK_QUOTAS.items():
591
600
  value = getattr(parsed_args, k, None)
592
601
  if value is not None:
593
602
  network_kwargs[k] = value
594
- else:
603
+ elif self.app.client_manager.is_compute_endpoint_enabled():
595
604
  for k, v in NOVA_NETWORK_QUOTAS.items():
596
605
  value = getattr(parsed_args, k, None)
597
606
  if value is not None:
@@ -632,11 +641,7 @@ class SetQuota(common.NetDetectionMixin, command.Command):
632
641
  compute_client.update_quota_set(project, **compute_kwargs)
633
642
  if volume_kwargs:
634
643
  volume_client.update_quota_set(project, **volume_kwargs)
635
- if (
636
- network_kwargs
637
- and self.app.client_manager.is_network_endpoint_enabled()
638
- ):
639
- network_client = self.app.client_manager.network
644
+ if network_kwargs:
640
645
  network_client.update_quota(project, **network_kwargs)
641
646
 
642
647
 
@@ -192,40 +192,46 @@ class ListAggregate(command.Lister):
192
192
 
193
193
  aggregates = list(compute_client.aggregates())
194
194
 
195
+ if sdk_utils.supports_microversion(compute_client, '2.41'):
196
+ column_headers = ("ID", "UUID")
197
+ columns = ("id", "uuid")
198
+ else:
199
+ column_headers = ("ID",)
200
+ columns = ("id",)
201
+
202
+ column_headers += (
203
+ "Name",
204
+ "Availability Zone",
205
+ )
206
+ columns += (
207
+ "name",
208
+ "availability_zone",
209
+ )
210
+
195
211
  if parsed_args.long:
196
212
  # Remove availability_zone from metadata because Nova doesn't
197
213
  for aggregate in aggregates:
198
214
  if 'availability_zone' in aggregate.metadata:
199
215
  aggregate.metadata.pop('availability_zone')
200
- # This is the easiest way to change column headers
201
- column_headers = (
202
- "ID",
203
- "Name",
204
- "Availability Zone",
216
+
217
+ column_headers += (
205
218
  "Properties",
206
219
  "Hosts",
207
220
  )
208
- columns = (
209
- "ID",
210
- "Name",
211
- "Availability Zone",
212
- "Metadata",
213
- "Hosts",
214
- )
215
- else:
216
- column_headers = columns = (
217
- "ID",
218
- "Name",
219
- "Availability Zone",
221
+ columns += (
222
+ "metadata",
223
+ "hosts",
220
224
  )
221
225
 
222
- data = (
223
- utils.get_item_properties(
224
- s, columns, formatters=_aggregate_formatters
225
- )
226
- for s in aggregates
226
+ return (
227
+ column_headers,
228
+ (
229
+ utils.get_item_properties(
230
+ s, columns, formatters=_aggregate_formatters
231
+ )
232
+ for s in aggregates
233
+ ),
227
234
  )
228
- return (column_headers, data)
229
235
 
230
236
 
231
237
  class RemoveAggregateHost(command.ShowOne):
@@ -165,9 +165,11 @@ class ShowHypervisor(command.ShowOne):
165
165
 
166
166
  def take_action(self, parsed_args):
167
167
  compute_client = self.app.client_manager.sdk_connection.compute
168
- hypervisor = compute_client.find_hypervisor(
169
- parsed_args.hypervisor, ignore_missing=False
170
- ).copy()
168
+
169
+ hypervisor_id = compute_client.find_hypervisor(
170
+ parsed_args.hypervisor, ignore_missing=False, details=False
171
+ ).id
172
+ hypervisor = compute_client.get_hypervisor(hypervisor_id).copy()
171
173
 
172
174
  # Some of the properties in the hypervisor object need to be processed
173
175
  # before they get reported to the user. We spend this section
@@ -3587,6 +3587,9 @@ class RebuildServer(command.ShowOne):
3587
3587
  if parsed_args.name is not None:
3588
3588
  kwargs['name'] = parsed_args.name
3589
3589
 
3590
+ if parsed_args.password is not None:
3591
+ kwargs['admin_password'] = parsed_args.password
3592
+
3590
3593
  if parsed_args.preserve_ephemeral is not None:
3591
3594
  kwargs['preserve_ephemeral'] = parsed_args.preserve_ephemeral
3592
3595
 
@@ -3725,9 +3728,7 @@ class RebuildServer(command.ShowOne):
3725
3728
  msg = _("The server status is not ACTIVE, SHUTOFF or ERROR.")
3726
3729
  raise exceptions.CommandError(msg)
3727
3730
 
3728
- server = compute_client.rebuild_server(
3729
- server, image, admin_password=parsed_args.password, **kwargs
3730
- )
3731
+ server = compute_client.rebuild_server(server, image, **kwargs)
3731
3732
 
3732
3733
  if parsed_args.wait:
3733
3734
  if utils.wait_for_status(
@@ -3839,7 +3840,7 @@ host."""
3839
3840
 
3840
3841
  kwargs = {
3841
3842
  'host': parsed_args.host,
3842
- 'password': parsed_args.password,
3843
+ 'admin_password': parsed_args.password,
3843
3844
  }
3844
3845
 
3845
3846
  if not sdk_utils.supports_microversion(compute_client, '2.14'):
@@ -186,15 +186,15 @@ class CreateApplicationCredential(command.ShowOne):
186
186
  application_credential['roles'] = msg
187
187
 
188
188
  columns = (
189
- 'ID',
190
- 'Name',
191
- 'Description',
192
- 'Project ID',
193
- 'Roles',
194
- 'Unrestricted',
195
- 'Access Rules',
196
- 'Expires At',
197
- 'Secret',
189
+ 'id',
190
+ 'name',
191
+ 'description',
192
+ 'project_id',
193
+ 'roles',
194
+ 'unrestricted',
195
+ 'access_rules',
196
+ 'expires_at',
197
+ 'secret',
198
198
  )
199
199
  return (
200
200
  columns,
@@ -337,14 +337,14 @@ class ShowApplicationCredential(command.ShowOne):
337
337
  app_cred['roles'] = msg
338
338
 
339
339
  columns = (
340
- 'ID',
341
- 'Name',
342
- 'Description',
343
- 'Project ID',
344
- 'Roles',
345
- 'Unrestricted',
346
- 'Access Rules',
347
- 'Expires At',
340
+ 'id',
341
+ 'name',
342
+ 'description',
343
+ 'project_id',
344
+ 'roles',
345
+ 'unrestricted',
346
+ 'access_rules',
347
+ 'expires_at',
348
348
  )
349
349
  return (
350
350
  columns,
@@ -37,11 +37,11 @@ def _format_service(service):
37
37
  'description',
38
38
  )
39
39
  column_headers = (
40
- 'ID',
41
- 'Name',
42
- 'Type',
43
- 'Enabled',
44
- 'Description',
40
+ 'id',
41
+ 'name',
42
+ 'type',
43
+ 'enabled',
44
+ 'description',
45
45
  )
46
46
 
47
47
  return (
@@ -0,0 +1,4 @@
1
+ ---
2
+ features:
3
+ - |
4
+ Listing volume backups now shows the created_at column.
@@ -48,7 +48,7 @@ class IdentityTests(base.TestCase):
48
48
  'parent_id',
49
49
  ]
50
50
  ROLE_FIELDS = ['id', 'name', 'domain_id', 'description']
51
- SERVICE_FIELDS = ['ID', 'Enabled', 'Name', 'Type', 'Description']
51
+ SERVICE_FIELDS = ['id', 'enabled', 'name', 'type', 'description']
52
52
  REGION_FIELDS = ['description', 'enabled', 'parent_region', 'region']
53
53
  ENDPOINT_FIELDS = [
54
54
  'id',
@@ -376,7 +376,7 @@ class IdentityTests(base.TestCase):
376
376
  if add_clean_up:
377
377
  service = self.parse_show_as_object(raw_output)
378
378
  self.addCleanup(
379
- self.openstack, 'service delete %s' % service['ID']
379
+ self.openstack, 'service delete %s' % service['id']
380
380
  )
381
381
  items = self.parse_show(raw_output)
382
382
  self.assert_show_fields(items, self.SERVICE_FIELDS)
@@ -21,13 +21,13 @@ from openstackclient.tests.functional.identity.v3 import common
21
21
 
22
22
  class ApplicationCredentialTests(common.IdentityTests):
23
23
  APPLICATION_CREDENTIAL_FIELDS = [
24
- 'ID',
25
- 'Name',
26
- 'Project ID',
27
- 'Description',
28
- 'Roles',
29
- 'Expires At',
30
- 'Unrestricted',
24
+ 'id',
25
+ 'name',
26
+ 'project_id',
27
+ 'description',
28
+ 'roles',
29
+ 'expires_at',
30
+ 'unrestricted',
31
31
  ]
32
32
  APPLICATION_CREDENTIAL_LIST_HEADERS = [
33
33
  'ID',
@@ -32,7 +32,7 @@ class LimitTestCase(common.IdentityTests):
32
32
 
33
33
  raw_output = self.openstack('service show %s' % service_id)
34
34
  items = self.parse_show(raw_output)
35
- service_name = self._extract_value_from_items('Name', items)
35
+ service_name = self._extract_value_from_items('name', items)
36
36
 
37
37
  project_name = self._create_dummy_project()
38
38
  raw_output = self.openstack('project show %s' % project_name)
@@ -73,7 +73,7 @@ class LimitTestCase(common.IdentityTests):
73
73
 
74
74
  raw_output = self.openstack('service show %s' % service_id)
75
75
  items = self.parse_show(raw_output)
76
- service_name = self._extract_value_from_items('Name', items)
76
+ service_name = self._extract_value_from_items('name', items)
77
77
 
78
78
  project_name = self._create_dummy_project()
79
79
 
@@ -29,7 +29,7 @@ class RegisteredLimitTestCase(common.IdentityTests):
29
29
  'service show' ' %(service_name)s' % {'service_name': service_name}
30
30
  )
31
31
  service_items = self.parse_show(raw_output)
32
- service_id = self._extract_value_from_items('ID', service_items)
32
+ service_id = self._extract_value_from_items('id', service_items)
33
33
 
34
34
  raw_output = self.openstack(
35
35
  'registered limit create'
@@ -61,9 +61,9 @@ class ServiceTests(common.IdentityTests):
61
61
  raw_output = self.openstack('service show %s' % new_service_name)
62
62
  # assert service details
63
63
  service = self.parse_show_as_object(raw_output)
64
- self.assertEqual(new_service_type, service['Type'])
65
- self.assertEqual(new_service_name, service['Name'])
66
- self.assertEqual(new_service_description, service['Description'])
64
+ self.assertEqual(new_service_type, service['type'])
65
+ self.assertEqual(new_service_name, service['name'])
66
+ self.assertEqual(new_service_description, service['description'])
67
67
 
68
68
  def test_service_show(self):
69
69
  service_name = self._create_dummy_service()
@@ -227,44 +227,6 @@ class TestAggregateDelete(TestAggregate):
227
227
 
228
228
 
229
229
  class TestAggregateList(TestAggregate):
230
- list_columns = (
231
- "ID",
232
- "Name",
233
- "Availability Zone",
234
- )
235
-
236
- list_columns_long = (
237
- "ID",
238
- "Name",
239
- "Availability Zone",
240
- "Properties",
241
- "Hosts",
242
- )
243
-
244
- list_data = (
245
- (
246
- TestAggregate.fake_ag.id,
247
- TestAggregate.fake_ag.name,
248
- TestAggregate.fake_ag.availability_zone,
249
- ),
250
- )
251
-
252
- list_data_long = (
253
- (
254
- TestAggregate.fake_ag.id,
255
- TestAggregate.fake_ag.name,
256
- TestAggregate.fake_ag.availability_zone,
257
- format_columns.DictColumn(
258
- {
259
- key: value
260
- for key, value in TestAggregate.fake_ag.metadata.items()
261
- if key != 'availability_zone'
262
- }
263
- ),
264
- format_columns.ListColumn(TestAggregate.fake_ag.hosts),
265
- ),
266
- )
267
-
268
230
  def setUp(self):
269
231
  super().setUp()
270
232
 
@@ -272,13 +234,54 @@ class TestAggregateList(TestAggregate):
272
234
  self.cmd = aggregate.ListAggregate(self.app, None)
273
235
 
274
236
  def test_aggregate_list(self):
237
+ self.set_compute_api_version('2.41')
238
+
239
+ parsed_args = self.check_parser(self.cmd, [], [])
240
+ columns, data = self.cmd.take_action(parsed_args)
241
+
242
+ expected_columns = (
243
+ "ID",
244
+ "UUID",
245
+ "Name",
246
+ "Availability Zone",
247
+ )
248
+ expected_data = (
249
+ (
250
+ self.fake_ag.id,
251
+ self.fake_ag.uuid,
252
+ self.fake_ag.name,
253
+ self.fake_ag.availability_zone,
254
+ ),
255
+ )
256
+
257
+ self.assertEqual(expected_columns, columns)
258
+ self.assertCountEqual(expected_data, tuple(data))
259
+
260
+ def test_aggregate_list_pre_v241(self):
261
+ self.set_compute_api_version('2.40')
262
+
275
263
  parsed_args = self.check_parser(self.cmd, [], [])
276
264
  columns, data = self.cmd.take_action(parsed_args)
277
265
 
278
- self.assertEqual(self.list_columns, columns)
279
- self.assertCountEqual(self.list_data, tuple(data))
266
+ expected_columns = (
267
+ "ID",
268
+ "Name",
269
+ "Availability Zone",
270
+ )
271
+ expected_data = (
272
+ (
273
+ self.fake_ag.id,
274
+ self.fake_ag.name,
275
+ self.fake_ag.availability_zone,
276
+ ),
277
+ )
278
+
279
+ self.assertEqual(expected_columns, columns)
280
+ self.assertCountEqual(expected_data, tuple(data))
280
281
 
281
282
  def test_aggregate_list_with_long(self):
283
+ self.set_compute_api_version('2.41')
284
+
282
285
  arglist = [
283
286
  '--long',
284
287
  ]
@@ -288,8 +291,33 @@ class TestAggregateList(TestAggregate):
288
291
  parsed_args = self.check_parser(self.cmd, arglist, vertifylist)
289
292
  columns, data = self.cmd.take_action(parsed_args)
290
293
 
291
- self.assertEqual(self.list_columns_long, columns)
292
- self.assertCountEqual(self.list_data_long, tuple(data))
294
+ expected_columns = (
295
+ "ID",
296
+ "UUID",
297
+ "Name",
298
+ "Availability Zone",
299
+ "Properties",
300
+ "Hosts",
301
+ )
302
+ expected_data = (
303
+ (
304
+ self.fake_ag.id,
305
+ self.fake_ag.uuid,
306
+ self.fake_ag.name,
307
+ self.fake_ag.availability_zone,
308
+ format_columns.DictColumn(
309
+ {
310
+ key: value
311
+ for key, value in self.fake_ag.metadata.items()
312
+ if key != 'availability_zone'
313
+ }
314
+ ),
315
+ format_columns.ListColumn(self.fake_ag.hosts),
316
+ ),
317
+ )
318
+
319
+ self.assertEqual(expected_columns, columns)
320
+ self.assertCountEqual(expected_data, tuple(data))
293
321
 
294
322
 
295
323
  class TestAggregateRemoveHost(TestAggregate):
@@ -296,13 +296,11 @@ class TestHypervisorShow(compute_fakes.TestComputev2):
296
296
  }
297
297
  )
298
298
 
299
- # Return value of compute_client.find_hypervisor
300
299
  self.compute_sdk_client.find_hypervisor.return_value = self.hypervisor
300
+ self.compute_sdk_client.get_hypervisor.return_value = self.hypervisor
301
301
 
302
- # Return value of compute_client.aggregates()
303
302
  self.compute_sdk_client.aggregates.return_value = []
304
303
 
305
- # Return value of compute_client.get_hypervisor_uptime()
306
304
  uptime_info = {
307
305
  'status': self.hypervisor.status,
308
306
  'state': self.hypervisor.state,
@@ -429,6 +427,13 @@ class TestHypervisorShow(compute_fakes.TestComputev2):
429
427
  self.assertEqual(self.columns_v288, columns)
430
428
  self.assertCountEqual(self.data_v288, data)
431
429
 
430
+ self.compute_sdk_client.find_hypervisor.assert_called_once_with(
431
+ self.hypervisor.name, ignore_missing=False, details=False
432
+ )
433
+ self.compute_sdk_client.get_hypervisor.assert_called_once_with(
434
+ self.hypervisor.id
435
+ )
436
+
432
437
  def test_hypervisor_show_pre_v288(self):
433
438
  self.set_compute_api_version('2.87')
434
439
 
@@ -448,6 +453,13 @@ class TestHypervisorShow(compute_fakes.TestComputev2):
448
453
  self.assertEqual(self.columns, columns)
449
454
  self.assertCountEqual(self.data, data)
450
455
 
456
+ self.compute_sdk_client.find_hypervisor.assert_called_once_with(
457
+ self.hypervisor.name, ignore_missing=False, details=False
458
+ )
459
+ self.compute_sdk_client.get_hypervisor.assert_called_once_with(
460
+ self.hypervisor.id
461
+ )
462
+
451
463
  def test_hypervisor_show_pre_v228(self):
452
464
  self.set_compute_api_version('2.27')
453
465
 
@@ -472,6 +484,13 @@ class TestHypervisorShow(compute_fakes.TestComputev2):
472
484
  self.assertEqual(self.columns, columns)
473
485
  self.assertCountEqual(self.data, data)
474
486
 
487
+ self.compute_sdk_client.find_hypervisor.assert_called_once_with(
488
+ self.hypervisor.name, ignore_missing=False, details=False
489
+ )
490
+ self.compute_sdk_client.get_hypervisor.assert_called_once_with(
491
+ self.hypervisor.id
492
+ )
493
+
475
494
  def test_hypervisor_show_uptime_not_implemented(self):
476
495
  self.set_compute_api_version('2.87')
477
496
 
@@ -543,3 +562,10 @@ class TestHypervisorShow(compute_fakes.TestComputev2):
543
562
 
544
563
  self.assertEqual(expected_columns, columns)
545
564
  self.assertCountEqual(expected_data, data)
565
+
566
+ self.compute_sdk_client.find_hypervisor.assert_called_once_with(
567
+ self.hypervisor.name, ignore_missing=False, details=False
568
+ )
569
+ self.compute_sdk_client.get_hypervisor.assert_called_once_with(
570
+ self.hypervisor.id
571
+ )