python-openstackclient 8.2.0__py3-none-any.whl → 8.3.0__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 (226) hide show
  1. openstackclient/api/object_store_v1.py +4 -1
  2. openstackclient/command.py +27 -0
  3. openstackclient/common/availability_zone.py +1 -1
  4. openstackclient/common/clientmanager.py +59 -21
  5. openstackclient/common/configuration.py +1 -1
  6. openstackclient/common/extension.py +1 -1
  7. openstackclient/common/limits.py +1 -1
  8. openstackclient/common/module.py +4 -2
  9. openstackclient/common/project_cleanup.py +10 -8
  10. openstackclient/common/quota.py +23 -6
  11. openstackclient/common/versions.py +1 -2
  12. openstackclient/compute/v2/agent.py +1 -1
  13. openstackclient/compute/v2/aggregate.py +6 -5
  14. openstackclient/compute/v2/console.py +5 -3
  15. openstackclient/compute/v2/console_connection.py +1 -1
  16. openstackclient/compute/v2/flavor.py +1 -1
  17. openstackclient/compute/v2/host.py +1 -1
  18. openstackclient/compute/v2/hypervisor.py +1 -1
  19. openstackclient/compute/v2/hypervisor_stats.py +1 -1
  20. openstackclient/compute/v2/keypair.py +1 -1
  21. openstackclient/compute/v2/server.py +76 -27
  22. openstackclient/compute/v2/server_backup.py +1 -1
  23. openstackclient/compute/v2/server_event.py +1 -1
  24. openstackclient/compute/v2/server_group.py +4 -2
  25. openstackclient/compute/v2/server_image.py +1 -1
  26. openstackclient/compute/v2/server_migration.py +1 -1
  27. openstackclient/compute/v2/server_volume.py +1 -1
  28. openstackclient/compute/v2/service.py +1 -1
  29. openstackclient/compute/v2/usage.py +6 -4
  30. openstackclient/identity/common.py +2 -1
  31. openstackclient/identity/v2_0/catalog.py +3 -2
  32. openstackclient/identity/v2_0/ec2creds.py +1 -1
  33. openstackclient/identity/v2_0/endpoint.py +1 -1
  34. openstackclient/identity/v2_0/project.py +17 -7
  35. openstackclient/identity/v2_0/role.py +1 -1
  36. openstackclient/identity/v2_0/role_assignment.py +3 -3
  37. openstackclient/identity/v2_0/service.py +1 -1
  38. openstackclient/identity/v2_0/token.py +1 -1
  39. openstackclient/identity/v2_0/user.py +2 -2
  40. openstackclient/identity/v3/access_rule.py +16 -4
  41. openstackclient/identity/v3/application_credential.py +30 -10
  42. openstackclient/identity/v3/catalog.py +3 -3
  43. openstackclient/identity/v3/consumer.py +1 -1
  44. openstackclient/identity/v3/credential.py +1 -1
  45. openstackclient/identity/v3/domain.py +10 -4
  46. openstackclient/identity/v3/ec2creds.py +1 -1
  47. openstackclient/identity/v3/endpoint.py +33 -12
  48. openstackclient/identity/v3/endpoint_group.py +1 -1
  49. openstackclient/identity/v3/federation_protocol.py +1 -1
  50. openstackclient/identity/v3/group.py +11 -5
  51. openstackclient/identity/v3/identity_provider.py +12 -10
  52. openstackclient/identity/v3/implied_role.py +1 -1
  53. openstackclient/identity/v3/limit.py +1 -1
  54. openstackclient/identity/v3/mapping.py +1 -1
  55. openstackclient/identity/v3/policy.py +1 -1
  56. openstackclient/identity/v3/project.py +10 -3
  57. openstackclient/identity/v3/region.py +1 -1
  58. openstackclient/identity/v3/registered_limit.py +16 -11
  59. openstackclient/identity/v3/role.py +20 -39
  60. openstackclient/identity/v3/role_assignment.py +12 -23
  61. openstackclient/identity/v3/service.py +1 -1
  62. openstackclient/identity/v3/service_provider.py +1 -1
  63. openstackclient/identity/v3/tag.py +3 -2
  64. openstackclient/identity/v3/token.py +3 -2
  65. openstackclient/identity/v3/trust.py +4 -2
  66. openstackclient/identity/v3/unscoped_saml.py +1 -1
  67. openstackclient/identity/v3/user.py +22 -13
  68. openstackclient/image/v1/image.py +19 -16
  69. openstackclient/image/v2/cache.py +1 -1
  70. openstackclient/image/v2/image.py +14 -11
  71. openstackclient/image/v2/info.py +1 -1
  72. openstackclient/image/v2/metadef_namespaces.py +1 -1
  73. openstackclient/image/v2/metadef_objects.py +1 -1
  74. openstackclient/image/v2/metadef_properties.py +3 -2
  75. openstackclient/image/v2/metadef_resource_type_association.py +1 -1
  76. openstackclient/image/v2/metadef_resource_types.py +1 -1
  77. openstackclient/image/v2/task.py +1 -1
  78. openstackclient/network/common.py +10 -9
  79. openstackclient/network/v2/address_group.py +4 -3
  80. openstackclient/network/v2/address_scope.py +8 -6
  81. openstackclient/network/v2/default_security_group_rule.py +9 -8
  82. openstackclient/network/v2/floating_ip.py +16 -9
  83. openstackclient/network/v2/floating_ip_port_forwarding.py +9 -6
  84. openstackclient/network/v2/ip_availability.py +7 -4
  85. openstackclient/network/v2/l3_conntrack_helper.py +11 -4
  86. openstackclient/network/v2/local_ip.py +13 -7
  87. openstackclient/network/v2/local_ip_association.py +7 -4
  88. openstackclient/network/v2/ndp_proxy.py +13 -6
  89. openstackclient/network/v2/network.py +33 -16
  90. openstackclient/network/v2/network_agent.py +5 -5
  91. openstackclient/network/v2/network_auto_allocated_topology.py +1 -1
  92. openstackclient/network/v2/network_flavor.py +1 -1
  93. openstackclient/network/v2/network_flavor_profile.py +1 -1
  94. openstackclient/network/v2/network_meter.py +1 -1
  95. openstackclient/network/v2/network_meter_rule.py +1 -1
  96. openstackclient/network/v2/network_qos_policy.py +7 -5
  97. openstackclient/network/v2/network_qos_rule.py +1 -1
  98. openstackclient/network/v2/network_qos_rule_type.py +1 -1
  99. openstackclient/network/v2/network_rbac.py +8 -5
  100. openstackclient/network/v2/network_segment.py +2 -2
  101. openstackclient/network/v2/network_segment_range.py +13 -6
  102. openstackclient/network/v2/network_service_provider.py +1 -1
  103. openstackclient/network/v2/network_trunk.py +65 -42
  104. openstackclient/network/v2/port.py +22 -20
  105. openstackclient/network/v2/router.py +19 -8
  106. openstackclient/network/v2/security_group.py +10 -6
  107. openstackclient/network/v2/security_group_rule.py +11 -5
  108. openstackclient/network/v2/subnet.py +17 -18
  109. openstackclient/network/v2/subnet_pool.py +11 -9
  110. openstackclient/network/v2/taas/__init__.py +0 -0
  111. openstackclient/network/v2/taas/tap_flow.py +245 -0
  112. openstackclient/network/v2/taas/tap_mirror.py +237 -0
  113. openstackclient/network/v2/taas/tap_service.py +211 -0
  114. openstackclient/object/v1/account.py +1 -1
  115. openstackclient/object/v1/container.py +1 -1
  116. openstackclient/object/v1/object.py +1 -1
  117. openstackclient/shell.py +18 -8
  118. openstackclient/tests/functional/identity/v3/test_catalog.py +42 -23
  119. openstackclient/tests/functional/identity/v3/test_role_assignment.py +174 -0
  120. openstackclient/tests/functional/image/v2/test_cache.py +54 -0
  121. openstackclient/tests/functional/image/v2/test_metadef_resource_type.py +55 -0
  122. openstackclient/tests/unit/common/test_command.py +1 -1
  123. openstackclient/tests/unit/common/test_extension.py +2 -3
  124. openstackclient/tests/unit/common/test_module.py +14 -7
  125. openstackclient/tests/unit/common/test_quota.py +20 -0
  126. openstackclient/tests/unit/compute/v2/test_aggregate.py +5 -3
  127. openstackclient/tests/unit/compute/v2/test_console.py +1 -4
  128. openstackclient/tests/unit/compute/v2/test_flavor.py +1 -3
  129. openstackclient/tests/unit/compute/v2/test_hypervisor_stats.py +1 -9
  130. openstackclient/tests/unit/compute/v2/test_server.py +364 -30
  131. openstackclient/tests/unit/compute/v2/test_server_backup.py +1 -3
  132. openstackclient/tests/unit/compute/v2/test_service.py +1 -3
  133. openstackclient/tests/unit/fakes.py +35 -134
  134. openstackclient/tests/unit/identity/test_common.py +100 -0
  135. openstackclient/tests/unit/identity/v2_0/test_project.py +4 -4
  136. openstackclient/tests/unit/identity/v3/fakes.py +10 -2
  137. openstackclient/tests/unit/identity/v3/test_application_credential.py +3 -3
  138. openstackclient/tests/unit/identity/v3/test_domain.py +1 -1
  139. openstackclient/tests/unit/identity/v3/test_endpoint.py +1 -1
  140. openstackclient/tests/unit/identity/v3/test_group.py +4 -2
  141. openstackclient/tests/unit/identity/v3/test_identity_provider.py +10 -10
  142. openstackclient/tests/unit/identity/v3/test_oauth.py +1 -1
  143. openstackclient/tests/unit/identity/v3/test_project.py +1 -1
  144. openstackclient/tests/unit/identity/v3/test_registered_limit.py +2 -2
  145. openstackclient/tests/unit/identity/v3/test_role.py +1 -82
  146. openstackclient/tests/unit/identity/v3/test_user.py +7 -51
  147. openstackclient/tests/unit/image/v2/test_image.py +111 -0
  148. openstackclient/tests/unit/network/test_common.py +9 -13
  149. openstackclient/tests/unit/network/v2/taas/__init__.py +0 -0
  150. openstackclient/tests/unit/network/v2/taas/test_osc_tap_flow.py +276 -0
  151. openstackclient/tests/unit/network/v2/taas/test_osc_tap_mirror.py +288 -0
  152. openstackclient/tests/unit/network/v2/taas/test_osc_tap_service.py +271 -0
  153. openstackclient/tests/unit/network/v2/test_address_group.py +19 -22
  154. openstackclient/tests/unit/network/v2/test_address_scope.py +10 -15
  155. openstackclient/tests/unit/network/v2/test_default_security_group_rule.py +38 -49
  156. openstackclient/tests/unit/network/v2/test_floating_ip_network.py +21 -27
  157. openstackclient/tests/unit/network/v2/test_floating_ip_port_forwarding.py +21 -18
  158. openstackclient/tests/unit/network/v2/test_ip_availability.py +6 -8
  159. openstackclient/tests/unit/network/v2/test_l3_conntrack_helper.py +6 -15
  160. openstackclient/tests/unit/network/v2/test_local_ip.py +12 -23
  161. openstackclient/tests/unit/network/v2/test_local_ip_association.py +13 -18
  162. openstackclient/tests/unit/network/v2/test_ndp_proxy.py +11 -21
  163. openstackclient/tests/unit/network/v2/test_network.py +41 -37
  164. openstackclient/tests/unit/network/v2/test_network_agent.py +13 -20
  165. openstackclient/tests/unit/network/v2/test_network_auto_allocated_topology.py +5 -8
  166. openstackclient/tests/unit/network/v2/test_network_flavor.py +14 -26
  167. openstackclient/tests/unit/network/v2/test_network_flavor_profile.py +14 -17
  168. openstackclient/tests/unit/network/v2/test_network_meter.py +7 -17
  169. openstackclient/tests/unit/network/v2/test_network_meter_rule.py +10 -20
  170. openstackclient/tests/unit/network/v2/test_network_qos_policy.py +7 -13
  171. openstackclient/tests/unit/network/v2/test_network_qos_rule.py +44 -54
  172. openstackclient/tests/unit/network/v2/test_network_qos_rule_type.py +2 -7
  173. openstackclient/tests/unit/network/v2/test_network_rbac.py +21 -36
  174. openstackclient/tests/unit/network/v2/test_network_segment.py +13 -29
  175. openstackclient/tests/unit/network/v2/test_network_segment_range.py +20 -19
  176. openstackclient/tests/unit/network/v2/test_network_service_provider.py +1 -4
  177. openstackclient/tests/unit/network/v2/test_network_trunk.py +52 -47
  178. openstackclient/tests/unit/network/v2/test_port.py +75 -86
  179. openstackclient/tests/unit/network/v2/test_router.py +104 -126
  180. openstackclient/tests/unit/network/v2/test_security_group_network.py +19 -26
  181. openstackclient/tests/unit/network/v2/test_security_group_rule_network.py +17 -18
  182. openstackclient/tests/unit/network/v2/test_subnet.py +35 -46
  183. openstackclient/tests/unit/network/v2/test_subnet_pool.py +21 -33
  184. openstackclient/tests/unit/volume/test_find_resource.py +4 -13
  185. openstackclient/tests/unit/volume/v2/test_volume_backup.py +3 -1
  186. openstackclient/tests/unit/volume/v3/test_volume.py +4 -0
  187. openstackclient/tests/unit/volume/v3/test_volume_backup.py +9 -0
  188. openstackclient/volume/client.py +7 -17
  189. openstackclient/volume/v2/backup_record.py +1 -1
  190. openstackclient/volume/v2/consistency_group.py +1 -1
  191. openstackclient/volume/v2/consistency_group_snapshot.py +1 -1
  192. openstackclient/volume/v2/qos_specs.py +1 -1
  193. openstackclient/volume/v2/service.py +1 -1
  194. openstackclient/volume/v2/volume.py +2 -2
  195. openstackclient/volume/v2/volume_backend.py +1 -1
  196. openstackclient/volume/v2/volume_backup.py +5 -3
  197. openstackclient/volume/v2/volume_host.py +1 -2
  198. openstackclient/volume/v2/volume_snapshot.py +2 -2
  199. openstackclient/volume/v2/volume_transfer_request.py +1 -1
  200. openstackclient/volume/v2/volume_type.py +11 -6
  201. openstackclient/volume/v3/block_storage_cleanup.py +1 -1
  202. openstackclient/volume/v3/block_storage_cluster.py +1 -1
  203. openstackclient/volume/v3/block_storage_log_level.py +1 -1
  204. openstackclient/volume/v3/block_storage_manage.py +1 -1
  205. openstackclient/volume/v3/block_storage_resource_filter.py +1 -1
  206. openstackclient/volume/v3/service.py +1 -1
  207. openstackclient/volume/v3/volume.py +2 -2
  208. openstackclient/volume/v3/volume_attachment.py +6 -5
  209. openstackclient/volume/v3/volume_backup.py +18 -3
  210. openstackclient/volume/v3/volume_group.py +1 -1
  211. openstackclient/volume/v3/volume_group_snapshot.py +1 -1
  212. openstackclient/volume/v3/volume_group_type.py +1 -1
  213. openstackclient/volume/v3/volume_message.py +1 -1
  214. openstackclient/volume/v3/volume_snapshot.py +2 -2
  215. openstackclient/volume/v3/volume_transfer_request.py +1 -1
  216. openstackclient/volume/v3/volume_type.py +15 -9
  217. {python_openstackclient-8.2.0.dist-info → python_openstackclient-8.3.0.dist-info}/METADATA +15 -13
  218. {python_openstackclient-8.2.0.dist-info → python_openstackclient-8.3.0.dist-info}/RECORD +224 -213
  219. {python_openstackclient-8.2.0.dist-info → python_openstackclient-8.3.0.dist-info}/WHEEL +1 -1
  220. {python_openstackclient-8.2.0.dist-info → python_openstackclient-8.3.0.dist-info}/entry_points.txt +15 -0
  221. {python_openstackclient-8.2.0.dist-info → python_openstackclient-8.3.0.dist-info/licenses}/AUTHORS +10 -0
  222. python_openstackclient-8.3.0.dist-info/pbr.json +1 -0
  223. openstackclient/tests/unit/common/test_logs.py +0 -221
  224. python_openstackclient-8.2.0.dist-info/pbr.json +0 -1
  225. {python_openstackclient-8.2.0.dist-info → python_openstackclient-8.3.0.dist-info/licenses}/LICENSE +0 -0
  226. {python_openstackclient-8.2.0.dist-info → python_openstackclient-8.3.0.dist-info}/top_level.txt +0 -0
@@ -21,6 +21,7 @@ import getpass
21
21
  import json
22
22
  import logging
23
23
  import os
24
+ import typing as ty
24
25
 
25
26
  from cliff import columns as cliff_columns
26
27
  import iso8601
@@ -28,11 +29,11 @@ from openstack import exceptions as sdk_exceptions
28
29
  from openstack import utils as sdk_utils
29
30
  from osc_lib.cli import format_columns
30
31
  from osc_lib.cli import parseractions
31
- from osc_lib.command import command
32
32
  from osc_lib import exceptions
33
33
  from osc_lib import utils
34
34
 
35
35
  from openstackclient.api import compute_v2
36
+ from openstackclient import command
36
37
  from openstackclient.common import envvars
37
38
  from openstackclient.common import pagination
38
39
  from openstackclient.i18n import _
@@ -44,7 +45,7 @@ LOG = logging.getLogger(__name__)
44
45
  IMAGE_STRING_FOR_BFV = 'N/A (booted from volume)'
45
46
 
46
47
 
47
- class PowerStateColumn(cliff_columns.FormattableColumn):
48
+ class PowerStateColumn(cliff_columns.FormattableColumn[int]):
48
49
  """Generate a formatted string of a server's power state."""
49
50
 
50
51
  power_states = [
@@ -65,7 +66,7 @@ class PowerStateColumn(cliff_columns.FormattableColumn):
65
66
  return 'N/A'
66
67
 
67
68
 
68
- class AddressesColumn(cliff_columns.FormattableColumn):
69
+ class AddressesColumn(cliff_columns.FormattableColumn[ty.Any]):
69
70
  """Generate a formatted string of a server's addresses."""
70
71
 
71
72
  def human_readable(self):
@@ -86,7 +87,7 @@ class AddressesColumn(cliff_columns.FormattableColumn):
86
87
  }
87
88
 
88
89
 
89
- class HostColumn(cliff_columns.FormattableColumn):
90
+ class HostColumn(cliff_columns.FormattableColumn[str | None]):
90
91
  """Generate a formatted string of a hostname."""
91
92
 
92
93
  def human_readable(self):
@@ -183,9 +184,17 @@ def _prep_server_detail(compute_client, image_client, server, *, refresh=True):
183
184
  'updated_at': 'updated',
184
185
  'user_data': 'OS-EXT-SRV-ATTR:user_data',
185
186
  'vm_state': 'OS-EXT-STS:vm_state',
186
- 'pinned_availability_zone': 'pinned_availability_zone',
187
- 'scheduler_hints': 'scheduler_hints',
188
187
  }
188
+ # NOTE(ratailor): microversion 2.96 introduces
189
+ # pinned_availability_zone support
190
+ if sdk_utils.supports_microversion(compute_client, '2.96'):
191
+ column_map['pinned_availability_zone'] = 'pinned_availability_zone'
192
+
193
+ # NOTE(ratailor): microversion 2.100 introduces
194
+ # scheduler_hints support
195
+ if sdk_utils.supports_microversion(compute_client, '2.100'):
196
+ column_map['scheduler_hints'] = 'scheduler_hints'
197
+
189
198
  # Some columns returned by openstacksdk should not be shown because they're
190
199
  # either irrelevant or duplicates
191
200
  ignored_columns = {
@@ -240,6 +249,11 @@ def _prep_server_detail(compute_client, image_client, server, *, refresh=True):
240
249
  if not sdk_utils.supports_microversion(compute_client, '2.100'):
241
250
  info.pop('scheduler_hints', None)
242
251
 
252
+ # NOTE(ratailor): microversion 2.96 introduces
253
+ # pinned_availability_zone support
254
+ if not sdk_utils.supports_microversion(compute_client, '2.96'):
255
+ info.pop('pinned_availability_zone', None)
256
+
243
257
  # Convert the image blob to a name
244
258
  image_info = info.get('image', {})
245
259
  if image_info and any(image_info.values()):
@@ -326,10 +340,11 @@ def _prep_server_detail(compute_client, image_client, server, *, refresh=True):
326
340
  info['OS-EXT-STS:power_state']
327
341
  )
328
342
 
329
- if 'scheduler_hints' in info:
330
- info['scheduler_hints'] = format_columns.DictListColumn(
331
- info.pop('scheduler_hints', {}),
332
- )
343
+ if sdk_utils.supports_microversion(compute_client, '2.100'):
344
+ if 'scheduler_hints' in info:
345
+ info['scheduler_hints'] = format_columns.DictListColumn(
346
+ info.pop('scheduler_hints', {}),
347
+ )
333
348
 
334
349
  return info
335
350
 
@@ -2166,7 +2181,9 @@ class CreateServerDump(command.Command):
2166
2181
  def take_action(self, parsed_args):
2167
2182
  compute_client = self.app.client_manager.compute
2168
2183
  for name_or_id in parsed_args.server:
2169
- server = compute_client.find_server(name_or_id)
2184
+ server = compute_client.find_server(
2185
+ name_or_id, ignore_missing=False
2186
+ )
2170
2187
  server.trigger_crash_dump(compute_client)
2171
2188
 
2172
2189
 
@@ -2209,24 +2226,49 @@ class DeleteServer(command.Command):
2209
2226
  self.app.stdout.flush()
2210
2227
 
2211
2228
  compute_client = self.app.client_manager.compute
2229
+
2230
+ deleted_servers = []
2212
2231
  for server in parsed_args.server:
2213
- server_obj = compute_client.find_server(
2214
- server,
2215
- ignore_missing=False,
2216
- all_projects=parsed_args.all_projects,
2217
- )
2232
+ try:
2233
+ server_obj = compute_client.find_server(
2234
+ server,
2235
+ ignore_missing=False,
2236
+ all_projects=parsed_args.all_projects,
2237
+ )
2218
2238
 
2219
- compute_client.delete_server(server_obj, force=parsed_args.force)
2239
+ compute_client.delete_server(
2240
+ server_obj, force=parsed_args.force
2241
+ )
2242
+ deleted_servers.append(server_obj)
2243
+ except Exception as e:
2244
+ LOG.error(
2245
+ _(
2246
+ "Failed to delete server with "
2247
+ "name or ID '%(server)s': %(e)s"
2248
+ ),
2249
+ {'server': server, 'e': e},
2250
+ )
2220
2251
 
2221
- if parsed_args.wait:
2252
+ if parsed_args.wait:
2253
+ for server_obj in deleted_servers:
2222
2254
  try:
2223
2255
  compute_client.wait_for_delete(
2224
2256
  server_obj, callback=_show_progress
2225
2257
  )
2226
2258
  except sdk_exceptions.ResourceTimeout:
2227
2259
  msg = _('Error deleting server: %s') % server_obj.id
2260
+ deleted_servers.remove(server_obj)
2228
2261
  raise exceptions.CommandError(msg)
2229
2262
 
2263
+ fails = len(parsed_args.server) - len(deleted_servers)
2264
+ if fails > 0:
2265
+ total = len(parsed_args.server)
2266
+ msg = _("%(fails)s of %(total)s servers failed to delete.") % {
2267
+ 'fails': fails,
2268
+ 'total': total,
2269
+ }
2270
+ raise exceptions.CommandError(msg)
2271
+
2230
2272
 
2231
2273
  class PercentAction(argparse.Action):
2232
2274
  def __init__(
@@ -2838,18 +2880,21 @@ class ListServer(command.Lister):
2838
2880
  if parsed_args.long:
2839
2881
  columns += (
2840
2882
  'availability_zone',
2841
- 'pinned_availability_zone',
2842
2883
  'hypervisor_hostname',
2843
2884
  'metadata',
2844
- 'scheduler_hints',
2845
2885
  )
2846
2886
  column_headers += (
2847
2887
  'Availability Zone',
2848
- 'Pinned Availability Zone',
2849
2888
  'Host',
2850
2889
  'Properties',
2851
- 'Scheduler Hints',
2852
2890
  )
2891
+ if sdk_utils.supports_microversion(compute_client, '2.96'):
2892
+ columns += ('pinned_availability_zone',)
2893
+ column_headers += ('Pinned Availability Zone',)
2894
+
2895
+ if sdk_utils.supports_microversion(compute_client, '2.100'):
2896
+ columns += ('scheduler_hints',)
2897
+ column_headers += ('Scheduler Hints',)
2853
2898
 
2854
2899
  if parsed_args.all_projects:
2855
2900
  columns += ('project_id',)
@@ -2887,10 +2932,11 @@ class ListServer(command.Lister):
2887
2932
  column_headers += ('Availability Zone',)
2888
2933
  if c in (
2889
2934
  'pinned_availability_zone',
2890
- "Pinned Availability Zone",
2935
+ 'Pinned Availability Zone',
2891
2936
  ):
2892
- columns += ('Pinned Availability Zone',)
2893
- column_headers += ('Pinned Availability Zone',)
2937
+ if sdk_utils.supports_microversion(compute_client, '2.96'):
2938
+ columns += ('pinned_availability_zone',)
2939
+ column_headers += ('Pinned Availability Zone',)
2894
2940
  if c in ('Host', "host"):
2895
2941
  columns += ('hypervisor_hostname',)
2896
2942
  column_headers += ('Host',)
@@ -2901,8 +2947,11 @@ class ListServer(command.Lister):
2901
2947
  'scheduler_hints',
2902
2948
  "Scheduler Hints",
2903
2949
  ):
2904
- columns += ('scheduler_hints',)
2905
- column_headers += ('Scheduler Hints',)
2950
+ if sdk_utils.supports_microversion(
2951
+ compute_client, '2.100'
2952
+ ):
2953
+ columns += ('scheduler_hints',)
2954
+ column_headers += ('Scheduler Hints',)
2906
2955
 
2907
2956
  # remove duplicates
2908
2957
  column_headers = tuple(dict.fromkeys(column_headers))
@@ -17,10 +17,10 @@
17
17
 
18
18
  import importlib
19
19
 
20
- from osc_lib.command import command
21
20
  from osc_lib import exceptions
22
21
  from osc_lib import utils
23
22
 
23
+ from openstackclient import command
24
24
  from openstackclient.i18n import _
25
25
 
26
26
 
@@ -22,10 +22,10 @@ from cliff import columns
22
22
  import iso8601
23
23
  from openstack import exceptions as sdk_exceptions
24
24
  from openstack import utils as sdk_utils
25
- from osc_lib.command import command
26
25
  from osc_lib import exceptions
27
26
  from osc_lib import utils
28
27
 
28
+ from openstackclient import command
29
29
  from openstackclient.common import pagination
30
30
  from openstackclient.i18n import _
31
31
 
@@ -16,21 +16,23 @@
16
16
  """Compute v2 Server Group action implementations"""
17
17
 
18
18
  import logging
19
+ import typing as ty
19
20
 
21
+ from cliff import columns
20
22
  from openstack import utils as sdk_utils
21
23
  from osc_lib.cli import format_columns
22
24
  from osc_lib.cli import parseractions
23
- from osc_lib.command import command
24
25
  from osc_lib import exceptions
25
26
  from osc_lib import utils
26
27
 
28
+ from openstackclient import command
27
29
  from openstackclient.common import pagination
28
30
  from openstackclient.i18n import _
29
31
 
30
32
  LOG = logging.getLogger(__name__)
31
33
 
32
34
 
33
- _formatters = {
35
+ _formatters: dict[str, type[columns.FormattableColumn[ty.Any]]] = {
34
36
  'member_ids': format_columns.ListColumn,
35
37
  'policies': format_columns.ListColumn,
36
38
  'rules': format_columns.DictColumn,
@@ -19,10 +19,10 @@ import importlib
19
19
  import logging
20
20
 
21
21
  from osc_lib.cli import parseractions
22
- from osc_lib.command import command
23
22
  from osc_lib import exceptions
24
23
  from osc_lib import utils
25
24
 
25
+ from openstackclient import command
26
26
  from openstackclient.i18n import _
27
27
 
28
28
 
@@ -15,10 +15,10 @@
15
15
  import uuid
16
16
 
17
17
  from openstack import utils as sdk_utils
18
- from osc_lib.command import command
19
18
  from osc_lib import exceptions
20
19
  from osc_lib import utils
21
20
 
21
+ from openstackclient import command
22
22
  from openstackclient.common import pagination
23
23
  from openstackclient.i18n import _
24
24
  from openstackclient.identity import common as identity_common
@@ -15,10 +15,10 @@
15
15
  """Compute v2 Server action implementations"""
16
16
 
17
17
  from openstack import utils as sdk_utils
18
- from osc_lib.command import command
19
18
  from osc_lib import exceptions
20
19
  from osc_lib import utils
21
20
 
21
+ from openstackclient import command
22
22
  from openstackclient.i18n import _
23
23
 
24
24
 
@@ -18,10 +18,10 @@
18
18
  import logging
19
19
 
20
20
  from openstack import utils as sdk_utils
21
- from osc_lib.command import command
22
21
  from osc_lib import exceptions
23
22
  from osc_lib import utils
24
23
 
24
+ from openstackclient import command
25
25
  from openstackclient.i18n import _
26
26
 
27
27
 
@@ -15,19 +15,21 @@
15
15
 
16
16
  """Usage action implementations"""
17
17
 
18
+ from collections.abc import Collection
18
19
  import datetime
19
20
  import functools
21
+ import typing as ty
20
22
 
21
23
  from cliff import columns as cliff_columns
22
- from osc_lib.command import command
23
24
  from osc_lib import utils
24
25
 
26
+ from openstackclient import command
25
27
  from openstackclient.i18n import _
26
28
 
27
29
 
28
30
  # TODO(stephenfin): This exists in a couple of places and should be moved to a
29
31
  # common module
30
- class ProjectColumn(cliff_columns.FormattableColumn):
32
+ class ProjectColumn(cliff_columns.FormattableColumn[str]):
31
33
  """Formattable column for project column.
32
34
 
33
35
  Unlike the parent FormattableColumn class, the initializer of the class
@@ -53,12 +55,12 @@ class ProjectColumn(cliff_columns.FormattableColumn):
53
55
  return project
54
56
 
55
57
 
56
- class CountColumn(cliff_columns.FormattableColumn):
58
+ class CountColumn(cliff_columns.FormattableColumn[Collection[ty.Any]]):
57
59
  def human_readable(self):
58
60
  return len(self._value) if self._value is not None else None
59
61
 
60
62
 
61
- class FloatColumn(cliff_columns.FormattableColumn):
63
+ class FloatColumn(cliff_columns.FormattableColumn[float]):
62
64
  def human_readable(self):
63
65
  return float(f"{self._value:.2f}")
64
66
 
@@ -99,7 +99,8 @@ def find_service_sdk(identity_client, name_type_or_id):
99
99
 
100
100
  if next(services, None):
101
101
  msg = _(
102
- "Multiple service matches found for '%(query)s', use an ID to be more specific."
102
+ "Multiple service matches found for '%(query)s', "
103
+ "use an ID to be more specific."
103
104
  ) % {"query": name_type_or_id}
104
105
  raise exceptions.CommandError(msg)
105
106
 
@@ -14,19 +14,20 @@
14
14
  """Identity v2 Service Catalog action implementations"""
15
15
 
16
16
  import logging
17
+ import typing as ty
17
18
 
18
19
  from cliff import columns as cliff_columns
19
- from osc_lib.command import command
20
20
  from osc_lib import exceptions
21
21
  from osc_lib import utils
22
22
 
23
+ from openstackclient import command
23
24
  from openstackclient.i18n import _
24
25
 
25
26
 
26
27
  LOG = logging.getLogger(__name__)
27
28
 
28
29
 
29
- class EndpointsColumn(cliff_columns.FormattableColumn):
30
+ class EndpointsColumn(cliff_columns.FormattableColumn[ty.Any]):
30
31
  def human_readable(self):
31
32
  if not self._value:
32
33
  return ""
@@ -18,10 +18,10 @@
18
18
 
19
19
  import logging
20
20
 
21
- from osc_lib.command import command
22
21
  from osc_lib import exceptions
23
22
  from osc_lib import utils
24
23
 
24
+ from openstackclient import command
25
25
  from openstackclient.i18n import _
26
26
 
27
27
 
@@ -17,10 +17,10 @@
17
17
 
18
18
  import logging
19
19
 
20
- from osc_lib.command import command
21
20
  from osc_lib import exceptions
22
21
  from osc_lib import utils
23
22
 
23
+ from openstackclient import command
24
24
  from openstackclient.i18n import _
25
25
  from openstackclient.identity import common
26
26
 
@@ -20,10 +20,10 @@ import logging
20
20
  from keystoneauth1 import exceptions as ks_exc
21
21
  from osc_lib.cli import format_columns
22
22
  from osc_lib.cli import parseractions
23
- from osc_lib.command import command
24
23
  from osc_lib import exceptions
25
24
  from osc_lib import utils
26
25
 
26
+ from openstackclient import command
27
27
  from openstackclient.i18n import _
28
28
 
29
29
 
@@ -59,6 +59,7 @@ class CreateProject(command.ShowOne):
59
59
  parser.add_argument(
60
60
  '--property',
61
61
  metavar='<key=value>',
62
+ dest='properties',
62
63
  action=parseractions.KeyValueAction,
63
64
  help=_(
64
65
  'Add a property to <name> '
@@ -79,8 +80,8 @@ class CreateProject(command.ShowOne):
79
80
  if parsed_args.disable:
80
81
  enabled = False
81
82
  kwargs = {}
82
- if parsed_args.property:
83
- kwargs = parsed_args.property.copy()
83
+ if parsed_args.properties:
84
+ kwargs.update(parsed_args.properties)
84
85
 
85
86
  try:
86
87
  project = identity_client.tenants.create(
@@ -105,7 +106,14 @@ class CreateProject(command.ShowOne):
105
106
 
106
107
 
107
108
  class DeleteProject(command.Command):
108
- _description = _("Delete project(s)")
109
+ _description = _(
110
+ "Delete project(s). This command will remove specified "
111
+ "existing project(s) if an active user is authorized to do "
112
+ "this. If there are resources managed by other services "
113
+ "(for example, Nova, Neutron, Cinder) associated with "
114
+ "specified project(s), delete operation will proceed "
115
+ "regardless."
116
+ )
109
117
 
110
118
  def get_parser(self, prog_name):
111
119
  parser = super().get_parser(prog_name)
@@ -223,6 +231,7 @@ class SetProject(command.Command):
223
231
  parser.add_argument(
224
232
  '--property',
225
233
  metavar='<key=value>',
234
+ dest='properties',
226
235
  action=parseractions.KeyValueAction,
227
236
  help=_(
228
237
  'Set a project property '
@@ -248,8 +257,8 @@ class SetProject(command.Command):
248
257
  kwargs['enabled'] = True
249
258
  if parsed_args.disable:
250
259
  kwargs['enabled'] = False
251
- if parsed_args.property:
252
- kwargs.update(parsed_args.property)
260
+ if parsed_args.properties:
261
+ kwargs.update(parsed_args.properties)
253
262
  if 'id' in kwargs:
254
263
  del kwargs['id']
255
264
  if 'name' in kwargs:
@@ -331,6 +340,7 @@ class UnsetProject(command.Command):
331
340
  parser.add_argument(
332
341
  '--property',
333
342
  metavar='<key>',
343
+ dest='properties',
334
344
  action='append',
335
345
  default=[],
336
346
  help=_(
@@ -347,7 +357,7 @@ class UnsetProject(command.Command):
347
357
  parsed_args.project,
348
358
  )
349
359
  kwargs = project._info
350
- for key in parsed_args.property:
360
+ for key in parsed_args.properties:
351
361
  if key in kwargs:
352
362
  kwargs[key] = None
353
363
  identity_client.tenants.update(project.id, **kwargs)
@@ -18,10 +18,10 @@
18
18
  import logging
19
19
 
20
20
  from keystoneauth1 import exceptions as ks_exc
21
- from osc_lib.command import command
22
21
  from osc_lib import exceptions
23
22
  from osc_lib import utils
24
23
 
24
+ from openstackclient import command
25
25
  from openstackclient.i18n import _
26
26
 
27
27
 
@@ -13,10 +13,10 @@
13
13
 
14
14
  """Identity v2 Assignment action implementations"""
15
15
 
16
- from osc_lib.command import command
17
16
  from osc_lib import exceptions
18
17
  from osc_lib import utils
19
18
 
19
+ from openstackclient import command
20
20
  from openstackclient.i18n import _ # noqa
21
21
 
22
22
 
@@ -68,7 +68,7 @@ class ListRoleAssignment(command.Lister):
68
68
  parsed_args.user,
69
69
  )
70
70
  elif parsed_args.authuser:
71
- if auth_ref:
71
+ if auth_ref and auth_ref.user_id:
72
72
  user = utils.find_resource(
73
73
  identity_client.users, auth_ref.user_id
74
74
  )
@@ -80,7 +80,7 @@ class ListRoleAssignment(command.Lister):
80
80
  parsed_args.project,
81
81
  )
82
82
  elif parsed_args.authproject:
83
- if auth_ref:
83
+ if auth_ref and auth_ref.project_id:
84
84
  project = utils.find_resource(
85
85
  identity_client.projects, auth_ref.project_id
86
86
  )
@@ -17,10 +17,10 @@
17
17
 
18
18
  import logging
19
19
 
20
- from osc_lib.command import command
21
20
  from osc_lib import exceptions
22
21
  from osc_lib import utils
23
22
 
23
+ from openstackclient import command
24
24
  from openstackclient.i18n import _
25
25
  from openstackclient.identity import common
26
26
 
@@ -15,9 +15,9 @@
15
15
 
16
16
  """Identity v2 Token action implementations"""
17
17
 
18
- from osc_lib.command import command
19
18
  from osc_lib import exceptions
20
19
 
20
+ from openstackclient import command
21
21
  from openstackclient.i18n import _
22
22
 
23
23
 
@@ -20,17 +20,17 @@ import logging
20
20
 
21
21
  from cliff import columns as cliff_columns
22
22
  from keystoneauth1 import exceptions as ks_exc
23
- from osc_lib.command import command
24
23
  from osc_lib import exceptions
25
24
  from osc_lib import utils
26
25
 
26
+ from openstackclient import command
27
27
  from openstackclient.i18n import _
28
28
 
29
29
 
30
30
  LOG = logging.getLogger(__name__)
31
31
 
32
32
 
33
- class ProjectColumn(cliff_columns.FormattableColumn):
33
+ class ProjectColumn(cliff_columns.FormattableColumn[str]):
34
34
  """Formattable column for project column.
35
35
 
36
36
  Unlike the parent FormattableColumn class, the initializer of the
@@ -17,10 +17,10 @@
17
17
 
18
18
  import logging
19
19
 
20
- from osc_lib.command import command
21
20
  from osc_lib import exceptions
22
21
  from osc_lib import utils
23
22
 
23
+ from openstackclient import command
24
24
  from openstackclient.i18n import _
25
25
  from openstackclient.identity import common
26
26
 
@@ -44,7 +44,11 @@ class DeleteAccessRule(command.Command):
44
44
  def take_action(self, parsed_args):
45
45
  identity_client = self.app.client_manager.sdk_connection.identity
46
46
  conn = self.app.client_manager.sdk_connection
47
- user_id = conn.config.get_auth().get_user_id(conn.identity)
47
+ auth = conn.config.get_auth()
48
+ if auth is None:
49
+ # this will never happen
50
+ raise exceptions.CommandError('invalid authentication info')
51
+ user_id = auth.get_user_id(conn.identity)
48
52
 
49
53
  errors = 0
50
54
  for ac in parsed_args.access_rule:
@@ -87,7 +91,11 @@ class ListAccessRule(command.Lister):
87
91
  ).id
88
92
  else:
89
93
  conn = self.app.client_manager.sdk_connection
90
- user_id = conn.config.get_auth().get_user_id(conn.identity)
94
+ auth = conn.config.get_auth()
95
+ if auth is None:
96
+ # this will never happen
97
+ raise exceptions.CommandError('invalid authentication info')
98
+ user_id = auth.get_user_id(conn.identity)
91
99
 
92
100
  columns = ('ID', 'Service', 'Method', 'Path')
93
101
  data = identity_client.access_rules(user=user_id)
@@ -119,7 +127,11 @@ class ShowAccessRule(command.ShowOne):
119
127
  def take_action(self, parsed_args):
120
128
  identity_client = self.app.client_manager.sdk_connection.identity
121
129
  conn = self.app.client_manager.sdk_connection
122
- user_id = conn.config.get_auth().get_user_id(conn.identity)
130
+ auth = conn.config.get_auth()
131
+ if auth is None:
132
+ # this will never happen
133
+ raise exceptions.CommandError('invalid authentication info')
134
+ user_id = auth.get_user_id(conn.identity)
123
135
 
124
136
  access_rule = identity_client.get_access_rule(
125
137
  user_id, parsed_args.access_rule