python-openstackclient 7.4.0__py3-none-any.whl → 8.1.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 (264) hide show
  1. openstackclient/common/availability_zone.py +3 -6
  2. openstackclient/common/clientmanager.py +2 -1
  3. openstackclient/common/envvars.py +57 -0
  4. openstackclient/common/extension.py +3 -11
  5. openstackclient/common/limits.py +1 -1
  6. openstackclient/common/project_cleanup.py +3 -2
  7. openstackclient/common/quota.py +54 -28
  8. openstackclient/compute/client.py +7 -5
  9. openstackclient/compute/v2/agent.py +5 -5
  10. openstackclient/compute/v2/aggregate.py +17 -15
  11. openstackclient/compute/v2/console.py +10 -4
  12. openstackclient/compute/v2/console_connection.py +48 -0
  13. openstackclient/compute/v2/flavor.py +14 -18
  14. openstackclient/compute/v2/host.py +3 -3
  15. openstackclient/compute/v2/hypervisor.py +10 -4
  16. openstackclient/compute/v2/hypervisor_stats.py +1 -1
  17. openstackclient/compute/v2/keypair.py +18 -13
  18. openstackclient/compute/v2/server.py +144 -121
  19. openstackclient/compute/v2/server_backup.py +1 -1
  20. openstackclient/compute/v2/server_event.py +8 -17
  21. openstackclient/compute/v2/server_group.py +6 -6
  22. openstackclient/compute/v2/server_image.py +1 -1
  23. openstackclient/compute/v2/server_migration.py +6 -6
  24. openstackclient/compute/v2/server_volume.py +4 -4
  25. openstackclient/compute/v2/service.py +9 -13
  26. openstackclient/compute/v2/usage.py +4 -6
  27. openstackclient/identity/client.py +2 -4
  28. openstackclient/identity/common.py +95 -17
  29. openstackclient/identity/v2_0/ec2creds.py +4 -3
  30. openstackclient/identity/v2_0/endpoint.py +12 -10
  31. openstackclient/identity/v2_0/project.py +6 -6
  32. openstackclient/identity/v2_0/role.py +1 -1
  33. openstackclient/identity/v2_0/service.py +7 -7
  34. openstackclient/identity/v2_0/user.py +6 -21
  35. openstackclient/identity/v3/access_rule.py +2 -5
  36. openstackclient/identity/v3/application_credential.py +2 -2
  37. openstackclient/identity/v3/consumer.py +4 -3
  38. openstackclient/identity/v3/credential.py +6 -7
  39. openstackclient/identity/v3/domain.py +63 -44
  40. openstackclient/identity/v3/ec2creds.py +4 -3
  41. openstackclient/identity/v3/endpoint.py +104 -88
  42. openstackclient/identity/v3/endpoint_group.py +1 -1
  43. openstackclient/identity/v3/group.py +116 -72
  44. openstackclient/identity/v3/identity_provider.py +1 -2
  45. openstackclient/identity/v3/limit.py +4 -9
  46. openstackclient/identity/v3/mapping.py +4 -3
  47. openstackclient/identity/v3/policy.py +5 -8
  48. openstackclient/identity/v3/project.py +23 -6
  49. openstackclient/identity/v3/region.py +2 -5
  50. openstackclient/identity/v3/registered_limit.py +4 -8
  51. openstackclient/identity/v3/role.py +15 -16
  52. openstackclient/identity/v3/service.py +8 -8
  53. openstackclient/identity/v3/service_provider.py +3 -6
  54. openstackclient/identity/v3/tag.py +2 -2
  55. openstackclient/identity/v3/token.py +1 -2
  56. openstackclient/identity/v3/trust.py +74 -25
  57. openstackclient/identity/v3/user.py +47 -11
  58. openstackclient/image/client.py +7 -5
  59. openstackclient/image/v1/image.py +11 -15
  60. openstackclient/image/v2/cache.py +2 -4
  61. openstackclient/image/v2/image.py +41 -48
  62. openstackclient/image/v2/metadef_namespaces.py +4 -3
  63. openstackclient/image/v2/metadef_resource_type_association.py +1 -2
  64. openstackclient/image/v2/metadef_resource_types.py +1 -2
  65. openstackclient/locale/tr_TR/LC_MESSAGES/openstackclient.po +9 -1370
  66. openstackclient/network/client.py +4 -16
  67. openstackclient/network/common.py +16 -12
  68. openstackclient/network/utils.py +3 -3
  69. openstackclient/network/v2/address_group.py +5 -9
  70. openstackclient/network/v2/address_scope.py +2 -3
  71. openstackclient/network/v2/default_security_group_rule.py +1 -2
  72. openstackclient/network/v2/floating_ip.py +69 -47
  73. openstackclient/network/v2/floating_ip_port_forwarding.py +7 -7
  74. openstackclient/network/v2/ip_availability.py +1 -2
  75. openstackclient/network/v2/l3_conntrack_helper.py +8 -12
  76. openstackclient/network/v2/local_ip.py +24 -26
  77. openstackclient/network/v2/local_ip_association.py +4 -5
  78. openstackclient/network/v2/ndp_proxy.py +9 -10
  79. openstackclient/network/v2/network.py +12 -16
  80. openstackclient/network/v2/network_agent.py +29 -37
  81. openstackclient/network/v2/network_auto_allocated_topology.py +4 -5
  82. openstackclient/network/v2/network_flavor.py +1 -1
  83. openstackclient/network/v2/network_flavor_profile.py +5 -5
  84. openstackclient/network/v2/network_meter.py +3 -3
  85. openstackclient/network/v2/network_meter_rule.py +5 -8
  86. openstackclient/network/v2/network_qos_policy.py +4 -4
  87. openstackclient/network/v2/network_qos_rule.py +7 -16
  88. openstackclient/network/v2/network_rbac.py +4 -4
  89. openstackclient/network/v2/network_segment.py +6 -7
  90. openstackclient/network/v2/network_segment_range.py +16 -20
  91. openstackclient/network/v2/network_trunk.py +24 -16
  92. openstackclient/network/v2/port.py +28 -29
  93. openstackclient/network/v2/router.py +53 -42
  94. openstackclient/network/v2/security_group.py +13 -19
  95. openstackclient/network/v2/security_group_rule.py +10 -11
  96. openstackclient/network/v2/subnet.py +31 -30
  97. openstackclient/network/v2/subnet_pool.py +4 -4
  98. openstackclient/object/client.py +2 -3
  99. openstackclient/object/v1/container.py +2 -3
  100. openstackclient/object/v1/object.py +2 -9
  101. openstackclient/shell.py +22 -5
  102. openstackclient/tests/functional/base.py +7 -3
  103. openstackclient/tests/functional/common/test_quota.py +3 -1
  104. openstackclient/tests/functional/compute/v2/common.py +12 -6
  105. openstackclient/tests/functional/compute/v2/test_keypair.py +41 -5
  106. openstackclient/tests/functional/compute/v2/test_server.py +2 -3
  107. openstackclient/tests/functional/compute/v2/test_server_event.py +1 -1
  108. openstackclient/tests/functional/identity/v2/test_user.py +1 -1
  109. openstackclient/tests/functional/identity/v3/common.py +3 -8
  110. openstackclient/tests/functional/identity/v3/test_application_credential.py +10 -10
  111. openstackclient/tests/functional/identity/v3/test_endpoint.py +3 -3
  112. openstackclient/tests/functional/identity/v3/test_group.py +3 -3
  113. openstackclient/tests/functional/identity/v3/test_idp.py +3 -7
  114. openstackclient/tests/functional/identity/v3/test_limit.py +4 -4
  115. openstackclient/tests/functional/identity/v3/test_project.py +5 -14
  116. openstackclient/tests/functional/identity/v3/test_region.py +1 -3
  117. openstackclient/tests/functional/identity/v3/test_registered_limit.py +3 -3
  118. openstackclient/tests/functional/identity/v3/test_role.py +1 -1
  119. openstackclient/tests/functional/identity/v3/test_role_assignment.py +13 -31
  120. openstackclient/tests/functional/identity/v3/test_service_provider.py +3 -7
  121. openstackclient/tests/functional/identity/v3/test_user.py +8 -8
  122. openstackclient/tests/functional/network/v2/common.py +7 -3
  123. openstackclient/tests/functional/network/v2/test_address_group.py +4 -0
  124. openstackclient/tests/functional/network/v2/test_l3_conntrack_helper.py +15 -11
  125. openstackclient/tests/functional/network/v2/test_local_ip.py +4 -0
  126. openstackclient/tests/functional/network/v2/test_network_meter_rule.py +2 -2
  127. openstackclient/tests/functional/network/v2/test_network_ndp_proxy.py +2 -3
  128. openstackclient/tests/functional/network/v2/test_network_rbac.py +2 -2
  129. openstackclient/tests/functional/network/v2/test_network_trunk.py +1 -1
  130. openstackclient/tests/functional/network/v2/test_port.py +17 -7
  131. openstackclient/tests/functional/network/v2/test_router.py +42 -0
  132. openstackclient/tests/functional/network/v2/test_subnet_pool.py +4 -0
  133. openstackclient/tests/unit/api/test_compute_v2.py +67 -87
  134. openstackclient/tests/unit/common/test_availability_zone.py +6 -14
  135. openstackclient/tests/unit/common/test_command.py +1 -1
  136. openstackclient/tests/unit/common/test_extension.py +5 -7
  137. openstackclient/tests/unit/common/test_limits.py +1 -1
  138. openstackclient/tests/unit/common/test_project_cleanup.py +5 -6
  139. openstackclient/tests/unit/common/test_quota.py +51 -28
  140. openstackclient/tests/unit/compute/v2/fakes.py +85 -315
  141. openstackclient/tests/unit/compute/v2/test_agent.py +16 -16
  142. openstackclient/tests/unit/compute/v2/test_aggregate.py +56 -60
  143. openstackclient/tests/unit/compute/v2/test_console.py +34 -17
  144. openstackclient/tests/unit/compute/v2/test_console_connection.py +72 -0
  145. openstackclient/tests/unit/compute/v2/test_flavor.py +72 -72
  146. openstackclient/tests/unit/compute/v2/test_host.py +8 -8
  147. openstackclient/tests/unit/compute/v2/test_hypervisor.py +22 -30
  148. openstackclient/tests/unit/compute/v2/test_hypervisor_stats.py +2 -2
  149. openstackclient/tests/unit/compute/v2/test_keypair.py +36 -29
  150. openstackclient/tests/unit/compute/v2/test_server.py +693 -606
  151. openstackclient/tests/unit/compute/v2/test_server_backup.py +36 -77
  152. openstackclient/tests/unit/compute/v2/test_server_event.py +18 -20
  153. openstackclient/tests/unit/compute/v2/test_server_group.py +25 -31
  154. openstackclient/tests/unit/compute/v2/test_server_image.py +37 -78
  155. openstackclient/tests/unit/compute/v2/test_server_migration.py +41 -41
  156. openstackclient/tests/unit/compute/v2/test_server_volume.py +12 -12
  157. openstackclient/tests/unit/compute/v2/test_service.py +39 -45
  158. openstackclient/tests/unit/compute/v2/test_usage.py +5 -5
  159. openstackclient/tests/unit/identity/v2_0/fakes.py +1 -1
  160. openstackclient/tests/unit/identity/v3/test_access_rule.py +1 -3
  161. openstackclient/tests/unit/identity/v3/test_application_credential.py +48 -26
  162. openstackclient/tests/unit/identity/v3/test_domain.py +115 -105
  163. openstackclient/tests/unit/identity/v3/test_endpoint.py +167 -172
  164. openstackclient/tests/unit/identity/v3/test_group.py +353 -202
  165. openstackclient/tests/unit/identity/v3/test_mappings.py +2 -2
  166. openstackclient/tests/unit/identity/v3/test_project.py +16 -0
  167. openstackclient/tests/unit/identity/v3/test_trust.py +5 -2
  168. openstackclient/tests/unit/identity/v3/test_user.py +102 -6
  169. openstackclient/tests/unit/image/v1/fakes.py +2 -2
  170. openstackclient/tests/unit/image/v1/test_image.py +8 -9
  171. openstackclient/tests/unit/image/v2/test_image.py +84 -46
  172. openstackclient/tests/unit/integ/cli/test_shell.py +1 -2
  173. openstackclient/tests/unit/network/test_common.py +2 -2
  174. openstackclient/tests/unit/network/v2/fakes.py +405 -485
  175. openstackclient/tests/unit/network/v2/test_floating_ip_compute.py +8 -14
  176. openstackclient/tests/unit/network/v2/test_floating_ip_network.py +62 -54
  177. openstackclient/tests/unit/network/v2/test_floating_ip_pool_compute.py +1 -1
  178. openstackclient/tests/unit/network/v2/test_l3_conntrack_helper.py +2 -2
  179. openstackclient/tests/unit/network/v2/test_ndp_proxy.py +1 -3
  180. openstackclient/tests/unit/network/v2/test_network.py +4 -4
  181. openstackclient/tests/unit/network/v2/test_network_agent.py +15 -29
  182. openstackclient/tests/unit/network/v2/test_network_compute.py +11 -11
  183. openstackclient/tests/unit/network/v2/test_network_qos_policy.py +16 -19
  184. openstackclient/tests/unit/network/v2/test_network_qos_rule.py +79 -152
  185. openstackclient/tests/unit/network/v2/test_network_qos_rule_type.py +4 -6
  186. openstackclient/tests/unit/network/v2/test_network_rbac.py +2 -2
  187. openstackclient/tests/unit/network/v2/test_network_trunk.py +2 -2
  188. openstackclient/tests/unit/network/v2/test_port.py +21 -22
  189. openstackclient/tests/unit/network/v2/test_router.py +130 -51
  190. openstackclient/tests/unit/network/v2/test_security_group_compute.py +11 -19
  191. openstackclient/tests/unit/network/v2/test_security_group_network.py +25 -27
  192. openstackclient/tests/unit/network/v2/test_security_group_rule_compute.py +15 -17
  193. openstackclient/tests/unit/network/v2/test_security_group_rule_network.py +33 -39
  194. openstackclient/tests/unit/object/v1/test_object_all.py +4 -3
  195. openstackclient/tests/unit/test_shell.py +16 -13
  196. openstackclient/tests/unit/volume/v2/fakes.py +1 -2
  197. openstackclient/tests/unit/volume/v2/test_service.py +57 -91
  198. openstackclient/tests/unit/volume/v2/test_volume.py +109 -106
  199. openstackclient/tests/unit/volume/v2/test_volume_backup.py +141 -148
  200. openstackclient/tests/unit/volume/v2/test_volume_snapshot.py +293 -283
  201. openstackclient/tests/unit/volume/v2/test_volume_transfer_request.py +1 -1
  202. openstackclient/tests/unit/volume/v3/fakes.py +2 -8
  203. openstackclient/tests/unit/volume/v3/test_block_storage_log_level.py +61 -71
  204. openstackclient/tests/unit/volume/v3/test_service.py +221 -141
  205. openstackclient/tests/unit/volume/v3/test_volume.py +131 -120
  206. openstackclient/tests/unit/volume/v3/test_volume_attachment.py +4 -4
  207. openstackclient/tests/unit/volume/v3/test_volume_backup.py +198 -203
  208. openstackclient/tests/unit/volume/v3/test_volume_snapshot.py +683 -49
  209. openstackclient/tests/unit/volume/v3/test_volume_transfer_request.py +1 -1
  210. openstackclient/volume/client.py +1 -3
  211. openstackclient/volume/v2/consistency_group.py +4 -8
  212. openstackclient/volume/v2/consistency_group_snapshot.py +1 -2
  213. openstackclient/volume/v2/qos_specs.py +1 -2
  214. openstackclient/volume/v2/service.py +41 -38
  215. openstackclient/volume/v2/volume.py +71 -53
  216. openstackclient/volume/v2/volume_backup.py +15 -10
  217. openstackclient/volume/v2/volume_snapshot.py +129 -93
  218. openstackclient/volume/v2/volume_transfer_request.py +0 -3
  219. openstackclient/volume/v2/volume_type.py +10 -21
  220. openstackclient/volume/v3/block_storage_cluster.py +3 -3
  221. openstackclient/volume/v3/block_storage_log_level.py +22 -28
  222. openstackclient/volume/v3/block_storage_manage.py +1 -3
  223. openstackclient/volume/v3/service.py +105 -14
  224. openstackclient/volume/v3/volume.py +218 -58
  225. openstackclient/volume/v3/volume_attachment.py +3 -2
  226. openstackclient/volume/v3/volume_backup.py +31 -27
  227. openstackclient/volume/v3/volume_group.py +2 -1
  228. openstackclient/volume/v3/volume_group_snapshot.py +2 -1
  229. openstackclient/volume/v3/volume_snapshot.py +489 -13
  230. openstackclient/volume/v3/volume_type.py +10 -21
  231. {python_openstackclient-7.4.0.dist-info → python_openstackclient-8.1.0.dist-info}/AUTHORS +11 -0
  232. python_openstackclient-8.1.0.dist-info/METADATA +264 -0
  233. {python_openstackclient-7.4.0.dist-info → python_openstackclient-8.1.0.dist-info}/RECORD +238 -259
  234. {python_openstackclient-7.4.0.dist-info → python_openstackclient-8.1.0.dist-info}/WHEEL +1 -1
  235. {python_openstackclient-7.4.0.dist-info → python_openstackclient-8.1.0.dist-info}/entry_points.txt +7 -47
  236. python_openstackclient-8.1.0.dist-info/pbr.json +1 -0
  237. openstackclient/tests/functional/volume/v1/__init__.py +0 -0
  238. openstackclient/tests/functional/volume/v1/common.py +0 -35
  239. openstackclient/tests/functional/volume/v1/test_qos.py +0 -100
  240. openstackclient/tests/functional/volume/v1/test_service.py +0 -76
  241. openstackclient/tests/functional/volume/v1/test_snapshot.py +0 -232
  242. openstackclient/tests/functional/volume/v1/test_transfer_request.py +0 -111
  243. openstackclient/tests/functional/volume/v1/test_volume.py +0 -228
  244. openstackclient/tests/functional/volume/v1/test_volume_type.py +0 -213
  245. openstackclient/tests/unit/volume/v1/__init__.py +0 -0
  246. openstackclient/tests/unit/volume/v1/fakes.py +0 -615
  247. openstackclient/tests/unit/volume/v1/test_qos_specs.py +0 -471
  248. openstackclient/tests/unit/volume/v1/test_service.py +0 -295
  249. openstackclient/tests/unit/volume/v1/test_transfer_request.py +0 -380
  250. openstackclient/tests/unit/volume/v1/test_type.py +0 -633
  251. openstackclient/tests/unit/volume/v1/test_volume.py +0 -1447
  252. openstackclient/tests/unit/volume/v1/test_volume_backup.py +0 -435
  253. openstackclient/volume/v1/__init__.py +0 -0
  254. openstackclient/volume/v1/qos_specs.py +0 -377
  255. openstackclient/volume/v1/service.py +0 -136
  256. openstackclient/volume/v1/volume.py +0 -734
  257. openstackclient/volume/v1/volume_backup.py +0 -302
  258. openstackclient/volume/v1/volume_snapshot.py +0 -433
  259. openstackclient/volume/v1/volume_transfer_request.py +0 -200
  260. openstackclient/volume/v1/volume_type.py +0 -520
  261. python_openstackclient-7.4.0.dist-info/METADATA +0 -172
  262. python_openstackclient-7.4.0.dist-info/pbr.json +0 -1
  263. {python_openstackclient-7.4.0.dist-info → python_openstackclient-8.1.0.dist-info}/LICENSE +0 -0
  264. {python_openstackclient-7.4.0.dist-info → python_openstackclient-8.1.0.dist-info}/top_level.txt +0 -0
@@ -21,7 +21,6 @@ import getpass
21
21
  import json
22
22
  import logging
23
23
  import os
24
- import typing as ty
25
24
 
26
25
  from cliff import columns as cliff_columns
27
26
  import iso8601
@@ -34,6 +33,7 @@ from osc_lib import exceptions
34
33
  from osc_lib import utils
35
34
 
36
35
  from openstackclient.api import compute_v2
36
+ from openstackclient.common import envvars
37
37
  from openstackclient.common import pagination
38
38
  from openstackclient.i18n import _
39
39
  from openstackclient.identity import common as identity_common
@@ -184,6 +184,7 @@ def _prep_server_detail(compute_client, image_client, server, *, refresh=True):
184
184
  'user_data': 'OS-EXT-SRV-ATTR:user_data',
185
185
  'vm_state': 'OS-EXT-STS:vm_state',
186
186
  'pinned_availability_zone': 'pinned_availability_zone',
187
+ 'scheduler_hints': 'scheduler_hints',
187
188
  }
188
189
  # Some columns returned by openstacksdk should not be shown because they're
189
190
  # either irrelevant or duplicates
@@ -204,7 +205,6 @@ def _prep_server_detail(compute_client, image_client, server, *, refresh=True):
204
205
  'min_count',
205
206
  'networks',
206
207
  'personality',
207
- 'scheduler_hints',
208
208
  # aliases
209
209
  'volumes',
210
210
  # unnecessary
@@ -235,6 +235,11 @@ def _prep_server_detail(compute_client, image_client, server, *, refresh=True):
235
235
 
236
236
  info = data
237
237
 
238
+ # NOTE(dviroel): microversion 2.100 is now retrieving scheduler_hints
239
+ # content from request_spec on detailed responses
240
+ if not sdk_utils.supports_microversion(compute_client, '2.100'):
241
+ info.pop('scheduler_hints', None)
242
+
238
243
  # Convert the image blob to a name
239
244
  image_info = info.get('image', {})
240
245
  if image_info and any(image_info.values()):
@@ -321,49 +326,12 @@ def _prep_server_detail(compute_client, image_client, server, *, refresh=True):
321
326
  info['OS-EXT-STS:power_state']
322
327
  )
323
328
 
324
- return info
325
-
326
-
327
- def bool_from_str(value, strict=False):
328
- true_strings = ('1', 't', 'true', 'on', 'y', 'yes')
329
- false_strings = ('0', 'f', 'false', 'off', 'n', 'no')
330
-
331
- if isinstance(value, bool):
332
- return value
333
-
334
- lowered = value.strip().lower()
335
- if lowered in true_strings:
336
- return True
337
- elif lowered in false_strings or not strict:
338
- return False
339
-
340
- msg = _(
341
- "Unrecognized value '%(value)s'; acceptable values are: %(valid)s"
342
- ) % {
343
- 'value': value,
344
- 'valid': ', '.join(
345
- f"'{s}'" for s in sorted(true_strings + false_strings)
346
- ),
347
- }
348
- raise ValueError(msg)
349
-
350
-
351
- def boolenv(*vars, default=False):
352
- """Search for the first defined of possibly many bool-like env vars.
353
-
354
- Returns the first environment variable defined in vars, or returns the
355
- default.
329
+ if 'scheduler_hints' in info:
330
+ info['scheduler_hints'] = format_columns.DictListColumn(
331
+ info.pop('scheduler_hints', {}),
332
+ )
356
333
 
357
- :param vars: Arbitrary strings to search for. Case sensitive.
358
- :param default: The default to return if no value found.
359
- :returns: A boolean corresponding to the value found, else the default if
360
- no value found.
361
- """
362
- for v in vars:
363
- value = os.environ.get(v, None)
364
- if value:
365
- return bool_from_str(value)
366
- return default
334
+ return info
367
335
 
368
336
 
369
337
  class AddFixedIP(command.ShowOne):
@@ -399,7 +367,7 @@ class AddFixedIP(command.ShowOne):
399
367
  return parser
400
368
 
401
369
  def take_action(self, parsed_args):
402
- compute_client = self.app.client_manager.sdk_connection.compute
370
+ compute_client = self.app.client_manager.compute
403
371
  server = compute_client.find_server(
404
372
  parsed_args.server, ignore_missing=False
405
373
  )
@@ -430,7 +398,7 @@ class AddFixedIP(command.ShowOne):
430
398
 
431
399
  interface = compute_client.create_server_interface(server.id, **kwargs)
432
400
 
433
- columns = (
401
+ columns: tuple[str, ...] = (
434
402
  'port_id',
435
403
  'server_id',
436
404
  'net_id',
@@ -438,7 +406,7 @@ class AddFixedIP(command.ShowOne):
438
406
  'port_state',
439
407
  'fixed_ips',
440
408
  )
441
- column_headers = (
409
+ column_headers: tuple[str, ...] = (
442
410
  'Port ID',
443
411
  'Server ID',
444
412
  'Network ID',
@@ -493,7 +461,7 @@ class AddFloatingIP(network_common.NetworkAndComputeCommand):
493
461
  return parser
494
462
 
495
463
  def take_action_network(self, client, parsed_args):
496
- compute_client = self.app.client_manager.sdk_connection.compute
464
+ compute_client = self.app.client_manager.compute
497
465
 
498
466
  attrs = {}
499
467
  obj = client.find_ip(
@@ -586,7 +554,7 @@ class AddPort(command.Command):
586
554
  return parser
587
555
 
588
556
  def take_action(self, parsed_args):
589
- compute_client = self.app.client_manager.sdk_connection.compute
557
+ compute_client = self.app.client_manager.compute
590
558
 
591
559
  server = compute_client.find_server(
592
560
  parsed_args.server, ignore_missing=False
@@ -640,7 +608,7 @@ class AddNetwork(command.Command):
640
608
  return parser
641
609
 
642
610
  def take_action(self, parsed_args):
643
- compute_client = self.app.client_manager.sdk_connection.compute
611
+ compute_client = self.app.client_manager.compute
644
612
 
645
613
  server = compute_client.find_server(
646
614
  parsed_args.server, ignore_missing=False
@@ -691,7 +659,7 @@ class AddServerSecurityGroup(command.Command):
691
659
  return parser
692
660
 
693
661
  def take_action(self, parsed_args):
694
- compute_client = self.app.client_manager.sdk_connection.compute
662
+ compute_client = self.app.client_manager.compute
695
663
 
696
664
  server = compute_client.find_server(
697
665
  parsed_args.server, ignore_missing=False
@@ -793,7 +761,7 @@ with status ``SHELVED`` or ``SHELVED_OFFLOADED``."""
793
761
  return parser
794
762
 
795
763
  def take_action(self, parsed_args):
796
- compute_client = self.app.client_manager.sdk_connection.compute
764
+ compute_client = self.app.client_manager.compute
797
765
  volume_client = self.app.client_manager.sdk_connection.volume
798
766
 
799
767
  server = compute_client.find_server(
@@ -842,8 +810,13 @@ with status ``SHELVED`` or ``SHELVED_OFFLOADED``."""
842
810
  **kwargs,
843
811
  )
844
812
 
845
- columns = ('id', 'server id', 'volume id', 'device')
846
- column_headers = ('ID', 'Server ID', 'Volume ID', 'Device')
813
+ columns: tuple[str, ...] = ('id', 'server id', 'volume id', 'device')
814
+ column_headers: tuple[str, ...] = (
815
+ 'ID',
816
+ 'Server ID',
817
+ 'Volume ID',
818
+ 'Device',
819
+ )
847
820
  if sdk_utils.supports_microversion(compute_client, '2.49'):
848
821
  columns += ('tag',)
849
822
  column_headers += ('Tag',)
@@ -1027,7 +1000,6 @@ class BDMLegacyAction(argparse.Action):
1027
1000
 
1028
1001
  class BDMAction(parseractions.MultiKeyValueAction):
1029
1002
  def __init__(self, option_strings, dest, **kwargs):
1030
- required_keys = []
1031
1003
  optional_keys = [
1032
1004
  'uuid',
1033
1005
  'source_type',
@@ -1045,7 +1017,7 @@ class BDMAction(parseractions.MultiKeyValueAction):
1045
1017
  super().__init__(
1046
1018
  option_strings,
1047
1019
  dest,
1048
- required_keys=required_keys,
1020
+ required_keys=[],
1049
1021
  optional_keys=optional_keys,
1050
1022
  **kwargs,
1051
1023
  )
@@ -1402,7 +1374,7 @@ class CreateServer(command.ShowOne):
1402
1374
  default=[],
1403
1375
  help=_(
1404
1376
  'File(s) to inject into image before boot '
1405
- '(repeat option to set multiple files)'
1377
+ '(repeat option to set multiple files) '
1406
1378
  '(supported by --os-compute-api-version 2.57 or below)'
1407
1379
  ),
1408
1380
  )
@@ -1554,7 +1526,7 @@ class CreateServer(command.ShowOne):
1554
1526
  self.app.stdout.write(f'\rProgress: {progress}')
1555
1527
  self.app.stdout.flush()
1556
1528
 
1557
- compute_client = self.app.client_manager.sdk_connection.compute
1529
+ compute_client = self.app.client_manager.compute
1558
1530
  volume_client = self.app.client_manager.volume
1559
1531
  image_client = self.app.client_manager.image
1560
1532
 
@@ -1617,8 +1589,7 @@ class CreateServer(command.ShowOne):
1617
1589
  image = images[0]
1618
1590
  else:
1619
1591
  msg = _(
1620
- 'No images match the property expected by '
1621
- '--image-property'
1592
+ 'No images match the property expected by --image-property'
1622
1593
  )
1623
1594
  raise exceptions.CommandError(msg)
1624
1595
 
@@ -1873,7 +1844,7 @@ class CreateServer(command.ShowOne):
1873
1844
 
1874
1845
  if 'delete_on_termination' in mapping:
1875
1846
  try:
1876
- value = bool_from_str(
1847
+ value = envvars.bool_from_str(
1877
1848
  mapping['delete_on_termination'],
1878
1849
  strict=True,
1879
1850
  )
@@ -1902,7 +1873,7 @@ class CreateServer(command.ShowOne):
1902
1873
 
1903
1874
  # Default to empty list if nothing was specified and let nova
1904
1875
  # decide the default behavior.
1905
- networks: ty.Union[str, ty.List[ty.Dict[str, str]], None] = []
1876
+ networks: str | list[dict[str, str]] | None = []
1906
1877
 
1907
1878
  if 'auto' in parsed_args.nics or 'none' in parsed_args.nics:
1908
1879
  if len(parsed_args.nics) > 1:
@@ -1967,7 +1938,7 @@ class CreateServer(command.ShowOne):
1967
1938
 
1968
1939
  # convert from the novaclient-derived "NIC" view to the actual
1969
1940
  # "network" view
1970
- network = {}
1941
+ network: dict[str, str] = {}
1971
1942
 
1972
1943
  if nic['net-id']:
1973
1944
  network['uuid'] = nic['net-id']
@@ -1976,14 +1947,14 @@ class CreateServer(command.ShowOne):
1976
1947
  network['port'] = nic['port-id']
1977
1948
 
1978
1949
  if nic['v4-fixed-ip']:
1979
- network['fixed'] = nic['v4-fixed-ip']
1950
+ network['fixed_ip'] = nic['v4-fixed-ip']
1980
1951
  elif nic['v6-fixed-ip']:
1981
- network['fixed'] = nic['v6-fixed-ip']
1952
+ network['fixed_ip'] = nic['v6-fixed-ip']
1982
1953
 
1983
1954
  if nic.get('tag'): # tags are optional
1984
1955
  network['tag'] = nic['tag']
1985
1956
 
1986
- networks.append(network)
1957
+ networks.append(network) # type: ignore[union-attr]
1987
1958
 
1988
1959
  if not parsed_args.nics and sdk_utils.supports_microversion(
1989
1960
  compute_client, '2.37'
@@ -2195,7 +2166,7 @@ class CreateServerDump(command.Command):
2195
2166
  return parser
2196
2167
 
2197
2168
  def take_action(self, parsed_args):
2198
- compute_client = self.app.client_manager.sdk_connection.compute
2169
+ compute_client = self.app.client_manager.compute
2199
2170
  for name_or_id in parsed_args.server:
2200
2171
  server = compute_client.find_server(name_or_id)
2201
2172
  server.trigger_crash_dump(compute_client)
@@ -2220,7 +2191,7 @@ class DeleteServer(command.Command):
2220
2191
  parser.add_argument(
2221
2192
  '--all-projects',
2222
2193
  action='store_true',
2223
- default=boolenv('ALL_PROJECTS'),
2194
+ default=envvars.boolenv('ALL_PROJECTS'),
2224
2195
  help=_(
2225
2196
  'Delete server(s) in another project by name (admin only)'
2226
2197
  '(can be specified using the ALL_PROJECTS envvar)'
@@ -2239,7 +2210,7 @@ class DeleteServer(command.Command):
2239
2210
  self.app.stdout.write(f'\rProgress: {progress}')
2240
2211
  self.app.stdout.flush()
2241
2212
 
2242
- compute_client = self.app.client_manager.sdk_connection.compute
2213
+ compute_client = self.app.client_manager.compute
2243
2214
  for server in parsed_args.server:
2244
2215
  server_obj = compute_client.find_server(
2245
2216
  server,
@@ -2386,7 +2357,7 @@ class ListServer(command.Lister):
2386
2357
  parser.add_argument(
2387
2358
  '--all-projects',
2388
2359
  action='store_true',
2389
- default=boolenv('ALL_PROJECTS'),
2360
+ default=envvars.boolenv('ALL_PROJECTS'),
2390
2361
  help=_(
2391
2362
  'Include all projects (admin only) '
2392
2363
  '(can be specified using the ALL_PROJECTS envvar)'
@@ -2424,8 +2395,7 @@ class ListServer(command.Lister):
2424
2395
  parser.add_argument(
2425
2396
  '--key-name',
2426
2397
  help=_(
2427
- 'Search by keypair name '
2428
- '(admin only before microversion 2.83)'
2398
+ 'Search by keypair name (admin only before microversion 2.83)'
2429
2399
  ),
2430
2400
  )
2431
2401
  config_drive_group = parser.add_mutually_exclusive_group()
@@ -2648,7 +2618,7 @@ class ListServer(command.Lister):
2648
2618
  return parser
2649
2619
 
2650
2620
  def take_action(self, parsed_args):
2651
- compute_client = self.app.client_manager.sdk_connection.compute
2621
+ compute_client = self.app.client_manager.compute
2652
2622
  identity_client = self.app.client_manager.identity
2653
2623
  image_client = self.app.client_manager.image
2654
2624
 
@@ -2804,12 +2774,12 @@ class ListServer(command.Lister):
2804
2774
  msg % search_opts['changes-since']
2805
2775
  )
2806
2776
 
2807
- columns = (
2777
+ columns: tuple[str, ...] = (
2808
2778
  'id',
2809
2779
  'name',
2810
2780
  'status',
2811
2781
  )
2812
- column_headers = (
2782
+ column_headers: tuple[str, ...] = (
2813
2783
  'ID',
2814
2784
  'Name',
2815
2785
  'Status',
@@ -2873,14 +2843,20 @@ class ListServer(command.Lister):
2873
2843
  'pinned_availability_zone',
2874
2844
  'hypervisor_hostname',
2875
2845
  'metadata',
2846
+ 'scheduler_hints',
2876
2847
  )
2877
2848
  column_headers += (
2878
2849
  'Availability Zone',
2879
2850
  'Pinned Availability Zone',
2880
2851
  'Host',
2881
2852
  'Properties',
2853
+ 'Scheduler Hints',
2882
2854
  )
2883
2855
 
2856
+ if parsed_args.all_projects:
2857
+ columns += ('project_id',)
2858
+ column_headers += ('Project ID',)
2859
+
2884
2860
  # support for additional columns
2885
2861
  if parsed_args.columns:
2886
2862
  for c in parsed_args.columns:
@@ -2923,6 +2899,12 @@ class ListServer(command.Lister):
2923
2899
  if c in ('Properties', "properties"):
2924
2900
  columns += ('Metadata',)
2925
2901
  column_headers += ('Properties',)
2902
+ if c in (
2903
+ 'scheduler_hints',
2904
+ "Scheduler Hints",
2905
+ ):
2906
+ columns += ('scheduler_hints',)
2907
+ column_headers += ('Scheduler Hints',)
2926
2908
 
2927
2909
  # remove duplicates
2928
2910
  column_headers = tuple(dict.fromkeys(column_headers))
@@ -3025,7 +3007,7 @@ class ListServer(command.Lister):
3025
3007
  # infrastructure failure situations.
3026
3008
  # For those servers with partial constructs we just skip the
3027
3009
  # processing of the image and flavor information.
3028
- if not hasattr(s, 'image') or not hasattr(s, 'flavor'):
3010
+ if getattr(s, 'status') == 'UNKNOWN':
3029
3011
  continue
3030
3012
 
3031
3013
  if 'id' in s.image and s.image.id is not None:
@@ -3089,6 +3071,7 @@ class ListServer(command.Lister):
3089
3071
  'metadata': format_columns.DictColumn,
3090
3072
  'security_groups_name': format_columns.ListColumn,
3091
3073
  'hypervisor_hostname': HostColumn,
3074
+ 'scheduler_hints': format_columns.DictListColumn,
3092
3075
  },
3093
3076
  )
3094
3077
  for s in data
@@ -3124,7 +3107,7 @@ A non-admin user will not be able to execute actions."""
3124
3107
  return parser
3125
3108
 
3126
3109
  def take_action(self, parsed_args):
3127
- compute_client = self.app.client_manager.sdk_connection.compute
3110
+ compute_client = self.app.client_manager.compute
3128
3111
 
3129
3112
  kwargs = {}
3130
3113
  if parsed_args.reason:
@@ -3222,7 +3205,7 @@ revert to release the new server and restart the old one."""
3222
3205
  action='store_true',
3223
3206
  default=None,
3224
3207
  help=_(
3225
- 'Allow disk over-commit on the destination host'
3208
+ 'Allow disk over-commit on the destination host '
3226
3209
  '(supported with --os-compute-api-version 2.24 or below)'
3227
3210
  ),
3228
3211
  )
@@ -3231,7 +3214,7 @@ revert to release the new server and restart the old one."""
3231
3214
  dest='disk_overcommit',
3232
3215
  action='store_false',
3233
3216
  help=_(
3234
- 'Do not over-commit disk on the destination host (default)'
3217
+ 'Do not over-commit disk on the destination host (default) '
3235
3218
  '(supported with --os-compute-api-version 2.24 or below)'
3236
3219
  ),
3237
3220
  )
@@ -3248,7 +3231,7 @@ revert to release the new server and restart the old one."""
3248
3231
  self.app.stdout.write(f'\rProgress: {progress}')
3249
3232
  self.app.stdout.flush()
3250
3233
 
3251
- compute_client = self.app.client_manager.sdk_connection.compute
3234
+ compute_client = self.app.client_manager.compute
3252
3235
 
3253
3236
  server = compute_client.find_server(
3254
3237
  parsed_args.server, ignore_missing=False
@@ -3351,7 +3334,7 @@ class PauseServer(command.Command):
3351
3334
  return parser
3352
3335
 
3353
3336
  def take_action(self, parsed_args):
3354
- compute_client = self.app.client_manager.sdk_connection.compute
3337
+ compute_client = self.app.client_manager.compute
3355
3338
  for server in parsed_args.server:
3356
3339
  server_id = compute_client.find_server(
3357
3340
  server,
@@ -3400,7 +3383,7 @@ class RebootServer(command.Command):
3400
3383
  self.app.stdout.write(f'\rProgress: {progress}')
3401
3384
  self.app.stdout.flush()
3402
3385
 
3403
- compute_client = self.app.client_manager.sdk_connection.compute
3386
+ compute_client = self.app.client_manager.compute
3404
3387
  server_id = compute_client.find_server(
3405
3388
  parsed_args.server,
3406
3389
  ignore_missing=False,
@@ -3434,7 +3417,7 @@ class RebuildServer(command.ShowOne):
3434
3417
  '--image',
3435
3418
  metavar='<image>',
3436
3419
  help=_(
3437
- 'Recreate server from the specified image (name or ID).'
3420
+ 'Recreate server from the specified image (name or ID). '
3438
3421
  'Defaults to the currently used one.'
3439
3422
  ),
3440
3423
  )
@@ -3605,7 +3588,7 @@ class RebuildServer(command.ShowOne):
3605
3588
  self.app.stdout.write(f'\rProgress: {progress}')
3606
3589
  self.app.stdout.flush()
3607
3590
 
3608
- compute_client = self.app.client_manager.sdk_connection.compute
3591
+ compute_client = self.app.client_manager.compute
3609
3592
  image_client = self.app.client_manager.image
3610
3593
 
3611
3594
  server = compute_client.find_server(
@@ -3866,7 +3849,7 @@ host."""
3866
3849
  self.app.stdout.write(f'\rProgress: {progress}')
3867
3850
  self.app.stdout.flush()
3868
3851
 
3869
- compute_client = self.app.client_manager.sdk_connection.compute
3852
+ compute_client = self.app.client_manager.compute
3870
3853
  image_client = self.app.client_manager.image
3871
3854
 
3872
3855
  if parsed_args.host:
@@ -3899,9 +3882,15 @@ host."""
3899
3882
  compute_client.evacuate_server(server, **kwargs)
3900
3883
 
3901
3884
  if parsed_args.wait:
3885
+ orig_status = server.status
3886
+ success = ['ACTIVE']
3887
+ if orig_status == 'SHUTOFF':
3888
+ success.append('SHUTOFF')
3889
+
3902
3890
  if utils.wait_for_status(
3903
3891
  compute_client.get_server,
3904
3892
  server.id,
3893
+ success_status=success,
3905
3894
  callback=_show_progress,
3906
3895
  ):
3907
3896
  self.app.stdout.write(_('Complete\n'))
@@ -3931,7 +3920,7 @@ class RemoveFixedIP(command.Command):
3931
3920
  return parser
3932
3921
 
3933
3922
  def take_action(self, parsed_args):
3934
- compute_client = self.app.client_manager.sdk_connection.compute
3923
+ compute_client = self.app.client_manager.compute
3935
3924
 
3936
3925
  server = compute_client.find_server(
3937
3926
  parsed_args.server, ignore_missing=False
@@ -3960,14 +3949,12 @@ class RemoveFloatingIP(network_common.NetworkAndComputeCommand):
3960
3949
  return parser
3961
3950
 
3962
3951
  def take_action_network(self, client, parsed_args):
3963
- attrs = {}
3964
3952
  obj = client.find_ip(
3965
3953
  parsed_args.ip_address,
3966
3954
  ignore_missing=False,
3967
3955
  )
3968
- attrs['port_id'] = None
3969
3956
 
3970
- client.update_ip(obj, **attrs)
3957
+ client.update_ip(obj, port_id=None)
3971
3958
 
3972
3959
  def take_action_compute(self, client, parsed_args):
3973
3960
  server = client.find_server(parsed_args.server, ignore_missing=False)
@@ -3992,7 +3979,7 @@ class RemovePort(command.Command):
3992
3979
  return parser
3993
3980
 
3994
3981
  def take_action(self, parsed_args):
3995
- compute_client = self.app.client_manager.sdk_connection.compute
3982
+ compute_client = self.app.client_manager.compute
3996
3983
 
3997
3984
  server = compute_client.find_server(
3998
3985
  parsed_args.server, ignore_missing=False
@@ -4031,7 +4018,7 @@ class RemoveNetwork(command.Command):
4031
4018
  return parser
4032
4019
 
4033
4020
  def take_action(self, parsed_args):
4034
- compute_client = self.app.client_manager.sdk_connection.compute
4021
+ compute_client = self.app.client_manager.compute
4035
4022
 
4036
4023
  server = compute_client.find_server(
4037
4024
  parsed_args.server, ignore_missing=False
@@ -4075,7 +4062,7 @@ class RemoveServerSecurityGroup(command.Command):
4075
4062
  return parser
4076
4063
 
4077
4064
  def take_action(self, parsed_args):
4078
- compute_client = self.app.client_manager.sdk_connection.compute
4065
+ compute_client = self.app.client_manager.compute
4079
4066
 
4080
4067
  server = compute_client.find_server(
4081
4068
  parsed_args.server, ignore_missing=False
@@ -4145,7 +4132,7 @@ volume from a server with status ``SHELVED`` or ``SHELVED_OFFLOADED``."""
4145
4132
  return parser
4146
4133
 
4147
4134
  def take_action(self, parsed_args):
4148
- compute_client = self.app.client_manager.sdk_connection.compute
4135
+ compute_client = self.app.client_manager.compute
4149
4136
  volume_client = self.app.client_manager.sdk_connection.volume
4150
4137
 
4151
4138
  server = compute_client.find_server(
@@ -4198,7 +4185,7 @@ server booted from a volume."""
4198
4185
  return parser
4199
4186
 
4200
4187
  def take_action(self, parsed_args):
4201
- compute_client = self.app.client_manager.sdk_connection.compute
4188
+ compute_client = self.app.client_manager.compute
4202
4189
  image_client = self.app.client_manager.image
4203
4190
 
4204
4191
  image_ref = None
@@ -4252,7 +4239,7 @@ release the new server and restart the old one."""
4252
4239
  '--revert',
4253
4240
  action="store_true",
4254
4241
  help=_(
4255
- '**Deprecated** Restore server state before resize'
4242
+ '**Deprecated** Restore server state before resize. '
4256
4243
  "Replaced by the 'openstack server resize revert' and "
4257
4244
  "'openstack server migration revert' commands"
4258
4245
  ),
@@ -4270,7 +4257,7 @@ release the new server and restart the old one."""
4270
4257
  self.app.stdout.write(f'\rProgress: {progress}')
4271
4258
  self.app.stdout.flush()
4272
4259
 
4273
- compute_client = self.app.client_manager.sdk_connection.compute
4260
+ compute_client = self.app.client_manager.compute
4274
4261
  server = compute_client.find_server(
4275
4262
  parsed_args.server, ignore_missing=False
4276
4263
  )
@@ -4332,7 +4319,7 @@ Confirm (verify) success of resize operation and release the old server."""
4332
4319
  return parser
4333
4320
 
4334
4321
  def take_action(self, parsed_args):
4335
- compute_client = self.app.client_manager.sdk_connection.compute
4322
+ compute_client = self.app.client_manager.compute
4336
4323
  server = compute_client.find_server(
4337
4324
  parsed_args.server, ignore_missing=False
4338
4325
  )
@@ -4380,7 +4367,7 @@ one."""
4380
4367
  return parser
4381
4368
 
4382
4369
  def take_action(self, parsed_args):
4383
- compute_client = self.app.client_manager.sdk_connection.compute
4370
+ compute_client = self.app.client_manager.compute
4384
4371
  server = compute_client.find_server(
4385
4372
  parsed_args.server, ignore_missing=False
4386
4373
  )
@@ -4424,7 +4411,7 @@ class RestoreServer(command.Command):
4424
4411
  return parser
4425
4412
 
4426
4413
  def take_action(self, parsed_args):
4427
- compute_client = self.app.client_manager.sdk_connection.compute
4414
+ compute_client = self.app.client_manager.compute
4428
4415
  for server in parsed_args.server:
4429
4416
  server_id = compute_client.find_server(
4430
4417
  server,
@@ -4447,7 +4434,7 @@ class ResumeServer(command.Command):
4447
4434
  return parser
4448
4435
 
4449
4436
  def take_action(self, parsed_args):
4450
- compute_client = self.app.client_manager.sdk_connection.compute
4437
+ compute_client = self.app.client_manager.compute
4451
4438
  for server in parsed_args.server:
4452
4439
  server_id = compute_client.find_server(
4453
4440
  server,
@@ -4475,8 +4462,7 @@ class SetServer(command.Command):
4475
4462
  password_group.add_argument(
4476
4463
  '--password',
4477
4464
  help=_(
4478
- 'Set the server password. '
4479
- 'This option requires cloud support.'
4465
+ 'Set the server password. This option requires cloud support.'
4480
4466
  ),
4481
4467
  )
4482
4468
  password_group.add_argument(
@@ -4504,15 +4490,27 @@ class SetServer(command.Command):
4504
4490
  '(repeat option to set multiple properties)'
4505
4491
  ),
4506
4492
  )
4493
+ parser.add_argument(
4494
+ '--auto-approve',
4495
+ action='store_true',
4496
+ help=_(
4497
+ "Allow server state override without asking for confirmation"
4498
+ ),
4499
+ )
4507
4500
  parser.add_argument(
4508
4501
  '--state',
4509
4502
  metavar='<state>',
4510
4503
  choices=['active', 'error'],
4511
4504
  help=_(
4512
- 'New server state '
4513
- '**WARNING** This can result in instances that are no longer '
4514
- 'usable and should be used with caution '
4515
- '(admin only)'
4505
+ 'New server state.'
4506
+ '**WARNING** Resetting the state is intended to work around '
4507
+ 'servers stuck in an intermediate state, such as deleting. '
4508
+ 'If the server is in an error state then this is almost '
4509
+ 'never the correct command to run and you should prefer hard '
4510
+ 'reboot where possible. In particular, if the server is in '
4511
+ 'an error state due to a move operation, setting the state '
4512
+ 'can result in instances that are no longer usable. Proceed '
4513
+ 'with caution. (admin only)'
4516
4514
  ),
4517
4515
  )
4518
4516
  parser.add_argument(
@@ -4547,8 +4545,22 @@ class SetServer(command.Command):
4547
4545
  )
4548
4546
  return parser
4549
4547
 
4548
+ @staticmethod
4549
+ def ask_user_yesno(msg):
4550
+ """Ask user Y/N question
4551
+
4552
+ :param str msg: question text
4553
+ :return bool: User choice
4554
+ """
4555
+ while True:
4556
+ answer = getpass.getpass('{} [{}]: '.format(msg, 'y/n'))
4557
+ if answer in ('y', 'Y', 'yes'):
4558
+ return True
4559
+ elif answer in ('n', 'N', 'no'):
4560
+ return False
4561
+
4550
4562
  def take_action(self, parsed_args):
4551
- compute_client = self.app.client_manager.sdk_connection.compute
4563
+ compute_client = self.app.client_manager.compute
4552
4564
  server = compute_client.find_server(
4553
4565
  parsed_args.server, ignore_missing=False
4554
4566
  )
@@ -4597,6 +4609,17 @@ class SetServer(command.Command):
4597
4609
  )
4598
4610
 
4599
4611
  if parsed_args.state:
4612
+ if not parsed_args.auto_approve:
4613
+ if not self.ask_user_yesno(
4614
+ _(
4615
+ "Resetting the server state can make it much harder "
4616
+ "to recover a server from an error state. If the "
4617
+ "server is in error status due to a failed move "
4618
+ "operation then this is likely not the correct "
4619
+ "approach to fix the problem. Do you wish to continue?"
4620
+ )
4621
+ ):
4622
+ return
4600
4623
  compute_client.reset_server_state(server, state=parsed_args.state)
4601
4624
 
4602
4625
  if parsed_args.root_password:
@@ -4666,7 +4689,7 @@ class ShelveServer(command.Command):
4666
4689
  self.app.stdout.write(f'\rProgress: {progress}')
4667
4690
  self.app.stdout.flush()
4668
4691
 
4669
- compute_client = self.app.client_manager.sdk_connection.compute
4692
+ compute_client = self.app.client_manager.compute
4670
4693
  server_ids = []
4671
4694
 
4672
4695
  for server in parsed_args.servers:
@@ -4761,7 +4784,7 @@ information for the server."""
4761
4784
  return parser
4762
4785
 
4763
4786
  def take_action(self, parsed_args):
4764
- compute_client = self.app.client_manager.sdk_connection.compute
4787
+ compute_client = self.app.client_manager.compute
4765
4788
  image_client = self.app.client_manager.image
4766
4789
 
4767
4790
  server = compute_client.find_server(
@@ -4891,7 +4914,7 @@ class SshServer(command.Command):
4891
4914
  return parser
4892
4915
 
4893
4916
  def take_action(self, parsed_args):
4894
- compute_client = self.app.client_manager.sdk_connection.compute
4917
+ compute_client = self.app.client_manager.compute
4895
4918
 
4896
4919
  server = compute_client.find_server(
4897
4920
  parsed_args.server, ignore_missing=False
@@ -4968,7 +4991,7 @@ class StartServer(command.Command):
4968
4991
  parser.add_argument(
4969
4992
  '--all-projects',
4970
4993
  action='store_true',
4971
- default=boolenv('ALL_PROJECTS'),
4994
+ default=envvars.boolenv('ALL_PROJECTS'),
4972
4995
  help=_(
4973
4996
  'Start server(s) in another project by name (admin only) '
4974
4997
  '(can be specified using the ALL_PROJECTS envvar)'
@@ -4977,7 +5000,7 @@ class StartServer(command.Command):
4977
5000
  return parser
4978
5001
 
4979
5002
  def take_action(self, parsed_args):
4980
- compute_client = self.app.client_manager.sdk_connection.compute
5003
+ compute_client = self.app.client_manager.compute
4981
5004
  for server in parsed_args.server:
4982
5005
  server_id = compute_client.find_server(
4983
5006
  server,
@@ -5003,16 +5026,16 @@ class StopServer(command.Command):
5003
5026
  parser.add_argument(
5004
5027
  '--all-projects',
5005
5028
  action='store_true',
5006
- default=boolenv('ALL_PROJECTS'),
5029
+ default=envvars.boolenv('ALL_PROJECTS'),
5007
5030
  help=_(
5008
- 'Stop server(s) in another project by name (admin only)'
5031
+ 'Stop server(s) in another project by name (admin only) '
5009
5032
  '(can be specified using the ALL_PROJECTS envvar)'
5010
5033
  ),
5011
5034
  )
5012
5035
  return parser
5013
5036
 
5014
5037
  def take_action(self, parsed_args):
5015
- compute_client = self.app.client_manager.sdk_connection.compute
5038
+ compute_client = self.app.client_manager.compute
5016
5039
  for server in parsed_args.server:
5017
5040
  server_id = compute_client.find_server(
5018
5041
  server,
@@ -5037,7 +5060,7 @@ class SuspendServer(command.Command):
5037
5060
  return parser
5038
5061
 
5039
5062
  def take_action(self, parsed_args):
5040
- compute_client = self.app.client_manager.sdk_connection.compute
5063
+ compute_client = self.app.client_manager.compute
5041
5064
  for server in parsed_args.server:
5042
5065
  server_id = compute_client.find_server(
5043
5066
  server,
@@ -5060,7 +5083,7 @@ class UnlockServer(command.Command):
5060
5083
  return parser
5061
5084
 
5062
5085
  def take_action(self, parsed_args):
5063
- compute_client = self.app.client_manager.sdk_connection.compute
5086
+ compute_client = self.app.client_manager.compute
5064
5087
  for server in parsed_args.server:
5065
5088
  server_id = compute_client.find_server(
5066
5089
  server,
@@ -5083,7 +5106,7 @@ class UnpauseServer(command.Command):
5083
5106
  return parser
5084
5107
 
5085
5108
  def take_action(self, parsed_args):
5086
- compute_client = self.app.client_manager.sdk_connection.compute
5109
+ compute_client = self.app.client_manager.compute
5087
5110
  for server in parsed_args.server:
5088
5111
  server_id = compute_client.find_server(
5089
5112
  server,
@@ -5105,7 +5128,7 @@ class UnrescueServer(command.Command):
5105
5128
  return parser
5106
5129
 
5107
5130
  def take_action(self, parsed_args):
5108
- compute_client = self.app.client_manager.sdk_connection.compute
5131
+ compute_client = self.app.client_manager.compute
5109
5132
  server = compute_client.find_server(
5110
5133
  parsed_args.server, ignore_missing=False
5111
5134
  )
@@ -5172,7 +5195,7 @@ class UnsetServer(command.Command):
5172
5195
  return parser
5173
5196
 
5174
5197
  def take_action(self, parsed_args):
5175
- compute_client = self.app.client_manager.sdk_connection.compute
5198
+ compute_client = self.app.client_manager.compute
5176
5199
 
5177
5200
  server = compute_client.find_server(
5178
5201
  parsed_args.server, ignore_missing=False
@@ -5263,7 +5286,7 @@ class UnshelveServer(command.Command):
5263
5286
  self.app.stdout.write(f'\rProgress: {progress}')
5264
5287
  self.app.stdout.flush()
5265
5288
 
5266
- compute_client = self.app.client_manager.sdk_connection.compute
5289
+ compute_client = self.app.client_manager.compute
5267
5290
  kwargs = {}
5268
5291
 
5269
5292
  if parsed_args.availability_zone: