python-openstackclient 6.6.1__py3-none-any.whl → 7.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 (336) hide show
  1. openstackclient/api/api.py +4 -4
  2. openstackclient/api/compute_v2.py +352 -638
  3. openstackclient/api/image_v1.py +1 -1
  4. openstackclient/api/object_store_v1.py +3 -4
  5. openstackclient/common/availability_zone.py +1 -1
  6. openstackclient/common/clientmanager.py +24 -20
  7. openstackclient/common/configuration.py +1 -1
  8. openstackclient/common/extension.py +1 -1
  9. openstackclient/common/limits.py +67 -34
  10. openstackclient/common/module.py +3 -3
  11. openstackclient/common/progressbar.py +2 -2
  12. openstackclient/common/project_cleanup.py +5 -2
  13. openstackclient/common/quota.py +299 -423
  14. openstackclient/common/versions.py +1 -1
  15. openstackclient/compute/client.py +7 -116
  16. openstackclient/compute/v2/agent.py +75 -49
  17. openstackclient/compute/v2/aggregate.py +38 -32
  18. openstackclient/compute/v2/console.py +2 -2
  19. openstackclient/compute/v2/flavor.py +6 -6
  20. openstackclient/compute/v2/host.py +38 -33
  21. openstackclient/compute/v2/hypervisor.py +9 -6
  22. openstackclient/compute/v2/keypair.py +7 -8
  23. openstackclient/compute/v2/server.py +479 -396
  24. openstackclient/compute/v2/server_backup.py +1 -1
  25. openstackclient/compute/v2/server_group.py +4 -4
  26. openstackclient/compute/v2/server_image.py +1 -1
  27. openstackclient/compute/v2/server_migration.py +3 -4
  28. openstackclient/compute/v2/service.py +4 -4
  29. openstackclient/compute/v2/usage.py +3 -3
  30. openstackclient/identity/common.py +34 -0
  31. openstackclient/identity/v2_0/catalog.py +2 -2
  32. openstackclient/identity/v2_0/ec2creds.py +4 -4
  33. openstackclient/identity/v2_0/endpoint.py +4 -4
  34. openstackclient/identity/v2_0/project.py +6 -6
  35. openstackclient/identity/v2_0/role.py +5 -5
  36. openstackclient/identity/v2_0/role_assignment.py +1 -1
  37. openstackclient/identity/v2_0/service.py +4 -4
  38. openstackclient/identity/v2_0/token.py +2 -2
  39. openstackclient/identity/v2_0/user.py +7 -7
  40. openstackclient/identity/v3/access_rule.py +3 -3
  41. openstackclient/identity/v3/application_credential.py +125 -43
  42. openstackclient/identity/v3/catalog.py +2 -2
  43. openstackclient/identity/v3/consumer.py +4 -4
  44. openstackclient/identity/v3/credential.py +5 -5
  45. openstackclient/identity/v3/domain.py +5 -5
  46. openstackclient/identity/v3/ec2creds.py +4 -4
  47. openstackclient/identity/v3/endpoint.py +7 -7
  48. openstackclient/identity/v3/endpoint_group.py +8 -10
  49. openstackclient/identity/v3/federation_protocol.py +5 -5
  50. openstackclient/identity/v3/group.py +8 -8
  51. openstackclient/identity/v3/identity_provider.py +5 -5
  52. openstackclient/identity/v3/implied_role.py +3 -3
  53. openstackclient/identity/v3/limit.py +5 -5
  54. openstackclient/identity/v3/mapping.py +5 -5
  55. openstackclient/identity/v3/policy.py +5 -5
  56. openstackclient/identity/v3/project.py +5 -5
  57. openstackclient/identity/v3/region.py +5 -5
  58. openstackclient/identity/v3/registered_limit.py +5 -5
  59. openstackclient/identity/v3/role.py +7 -7
  60. openstackclient/identity/v3/role_assignment.py +92 -140
  61. openstackclient/identity/v3/service.py +64 -34
  62. openstackclient/identity/v3/service_provider.py +4 -4
  63. openstackclient/identity/v3/tag.py +2 -2
  64. openstackclient/identity/v3/token.py +5 -5
  65. openstackclient/identity/v3/trust.py +3 -3
  66. openstackclient/identity/v3/user.py +144 -80
  67. openstackclient/image/client.py +4 -4
  68. openstackclient/image/v1/image.py +8 -9
  69. openstackclient/image/v2/cache.py +12 -10
  70. openstackclient/image/v2/metadef_objects.py +44 -0
  71. openstackclient/image/v2/metadef_resource_type_association.py +189 -0
  72. openstackclient/image/v2/task.py +1 -1
  73. openstackclient/network/common.py +6 -5
  74. openstackclient/network/utils.py +2 -2
  75. openstackclient/network/v2/address_group.py +6 -6
  76. openstackclient/network/v2/address_scope.py +5 -5
  77. openstackclient/network/v2/default_security_group_rule.py +1 -1
  78. openstackclient/network/v2/floating_ip.py +8 -10
  79. openstackclient/network/v2/floating_ip_pool.py +6 -15
  80. openstackclient/network/v2/floating_ip_port_forwarding.py +5 -13
  81. openstackclient/network/v2/ip_availability.py +2 -2
  82. openstackclient/network/v2/l3_conntrack_helper.py +5 -5
  83. openstackclient/network/v2/network.py +8 -8
  84. openstackclient/network/v2/network_agent.py +8 -8
  85. openstackclient/network/v2/network_auto_allocated_topology.py +2 -2
  86. openstackclient/network/v2/network_flavor.py +6 -8
  87. openstackclient/network/v2/network_flavor_profile.py +4 -4
  88. openstackclient/network/v2/network_meter.py +3 -3
  89. openstackclient/network/v2/network_meter_rule.py +3 -3
  90. openstackclient/network/v2/network_qos_policy.py +5 -5
  91. openstackclient/network/v2/network_qos_rule.py +9 -9
  92. openstackclient/network/v2/network_qos_rule_type.py +1 -1
  93. openstackclient/network/v2/network_rbac.py +5 -5
  94. openstackclient/network/v2/network_segment.py +5 -5
  95. openstackclient/network/v2/network_segment_range.py +7 -7
  96. openstackclient/network/v2/network_trunk.py +7 -7
  97. openstackclient/network/v2/port.py +26 -12
  98. openstackclient/network/v2/router.py +403 -54
  99. openstackclient/network/v2/security_group.py +18 -14
  100. openstackclient/network/v2/security_group_rule.py +18 -15
  101. openstackclient/network/v2/subnet.py +15 -8
  102. openstackclient/network/v2/subnet_pool.py +6 -6
  103. openstackclient/object/v1/account.py +2 -2
  104. openstackclient/object/v1/container.py +7 -7
  105. openstackclient/object/v1/object.py +7 -7
  106. openstackclient/releasenotes/notes/volume-backup-created-at-list-b49ec893ae1f6b0d.yaml +4 -0
  107. openstackclient/shell.py +4 -6
  108. openstackclient/tests/functional/base.py +1 -1
  109. openstackclient/tests/functional/common/test_extension.py +1 -1
  110. openstackclient/tests/functional/common/test_help.py +2 -2
  111. openstackclient/tests/functional/common/test_module.py +1 -1
  112. openstackclient/tests/functional/common/test_quota.py +43 -61
  113. openstackclient/tests/functional/compute/v2/common.py +2 -2
  114. openstackclient/tests/functional/compute/v2/test_flavor.py +2 -2
  115. openstackclient/tests/functional/compute/v2/test_keypair.py +1 -1
  116. openstackclient/tests/functional/compute/v2/test_server.py +5 -5
  117. openstackclient/tests/functional/compute/v2/test_server_event.py +1 -1
  118. openstackclient/tests/functional/identity/v2/common.py +3 -3
  119. openstackclient/tests/functional/identity/v3/common.py +12 -4
  120. openstackclient/tests/functional/identity/v3/test_application_credential.py +6 -12
  121. openstackclient/tests/functional/identity/v3/test_domain.py +1 -3
  122. openstackclient/tests/functional/identity/v3/test_endpoint.py +1 -1
  123. openstackclient/tests/functional/identity/v3/test_idp.py +1 -1
  124. openstackclient/tests/functional/identity/v3/test_region.py +1 -3
  125. openstackclient/tests/functional/identity/v3/test_role.py +2 -2
  126. openstackclient/tests/functional/identity/v3/test_role_assignment.py +210 -0
  127. openstackclient/tests/functional/identity/v3/test_service.py +1 -3
  128. openstackclient/tests/functional/identity/v3/test_service_provider.py +1 -3
  129. openstackclient/tests/functional/image/base.py +1 -1
  130. openstackclient/tests/functional/image/v2/test_image.py +1 -1
  131. openstackclient/tests/functional/image/v2/test_info.py +1 -1
  132. openstackclient/tests/functional/network/v2/common.py +4 -6
  133. openstackclient/tests/functional/network/v2/test_network.py +5 -3
  134. openstackclient/tests/functional/network/v2/test_network_agent.py +7 -5
  135. openstackclient/tests/functional/network/v2/test_network_qos_rule.py +4 -4
  136. openstackclient/tests/functional/network/v2/test_port.py +11 -7
  137. openstackclient/tests/functional/network/v2/test_router.py +2 -2
  138. openstackclient/tests/functional/object/v1/common.py +1 -1
  139. openstackclient/tests/functional/object/v1/test_container.py +3 -3
  140. openstackclient/tests/functional/object/v1/test_object.py +9 -13
  141. openstackclient/tests/functional/volume/base.py +1 -1
  142. openstackclient/tests/functional/volume/v1/test_service.py +1 -1
  143. openstackclient/tests/functional/volume/v1/test_snapshot.py +2 -2
  144. openstackclient/tests/functional/volume/v1/test_transfer_request.py +2 -2
  145. openstackclient/tests/functional/volume/v1/test_volume_type.py +1 -1
  146. openstackclient/tests/functional/volume/v2/test_service.py +2 -2
  147. openstackclient/tests/functional/volume/v2/test_volume_backup.py +2 -2
  148. openstackclient/tests/functional/volume/v2/test_volume_snapshot.py +2 -2
  149. openstackclient/tests/functional/volume/v2/test_volume_type.py +1 -1
  150. openstackclient/tests/functional/volume/v3/test_volume_snapshot.py +2 -2
  151. openstackclient/tests/functional/volume/v3/test_volume_type.py +1 -1
  152. openstackclient/tests/unit/api/fakes.py +1 -1
  153. openstackclient/tests/unit/api/test_api.py +2 -2
  154. openstackclient/tests/unit/api/test_compute_v2.py +522 -707
  155. openstackclient/tests/unit/api/test_image_v1.py +1 -1
  156. openstackclient/tests/unit/api/test_image_v2.py +1 -1
  157. openstackclient/tests/unit/api/test_object_store_v1.py +4 -4
  158. openstackclient/tests/unit/common/test_limits.py +73 -35
  159. openstackclient/tests/unit/common/test_logs.py +2 -2
  160. openstackclient/tests/unit/common/test_module.py +4 -2
  161. openstackclient/tests/unit/common/test_project_cleanup.py +31 -6
  162. openstackclient/tests/unit/common/test_quota.py +490 -630
  163. openstackclient/tests/unit/compute/v2/fakes.py +37 -286
  164. openstackclient/tests/unit/compute/v2/test_agent.py +189 -147
  165. openstackclient/tests/unit/compute/v2/test_aggregate.py +87 -57
  166. openstackclient/tests/unit/compute/v2/test_console.py +4 -5
  167. openstackclient/tests/unit/compute/v2/test_flavor.py +59 -68
  168. openstackclient/tests/unit/compute/v2/test_host.py +83 -54
  169. openstackclient/tests/unit/compute/v2/test_hypervisor.py +57 -34
  170. openstackclient/tests/unit/compute/v2/test_hypervisor_stats.py +2 -2
  171. openstackclient/tests/unit/compute/v2/test_keypair.py +65 -50
  172. openstackclient/tests/unit/compute/v2/test_server.py +2850 -2453
  173. openstackclient/tests/unit/compute/v2/test_server_backup.py +1 -1
  174. openstackclient/tests/unit/compute/v2/test_server_event.py +14 -39
  175. openstackclient/tests/unit/compute/v2/test_server_group.py +28 -29
  176. openstackclient/tests/unit/compute/v2/test_server_migration.py +43 -68
  177. openstackclient/tests/unit/compute/v2/test_server_volume.py +17 -34
  178. openstackclient/tests/unit/compute/v2/test_service.py +34 -52
  179. openstackclient/tests/unit/compute/v2/test_usage.py +4 -4
  180. openstackclient/tests/unit/fakes.py +12 -12
  181. openstackclient/tests/unit/identity/v2_0/fakes.py +27 -10
  182. openstackclient/tests/unit/identity/v2_0/test_catalog.py +3 -3
  183. openstackclient/tests/unit/identity/v2_0/test_endpoint.py +7 -7
  184. openstackclient/tests/unit/identity/v2_0/test_project.py +8 -8
  185. openstackclient/tests/unit/identity/v2_0/test_role.py +10 -10
  186. openstackclient/tests/unit/identity/v2_0/test_role_assignment.py +4 -4
  187. openstackclient/tests/unit/identity/v2_0/test_service.py +6 -6
  188. openstackclient/tests/unit/identity/v2_0/test_token.py +4 -4
  189. openstackclient/tests/unit/identity/v2_0/test_user.py +8 -8
  190. openstackclient/tests/unit/identity/v3/fakes.py +59 -20
  191. openstackclient/tests/unit/identity/v3/test_access_rule.py +5 -5
  192. openstackclient/tests/unit/identity/v3/test_application_credential.py +207 -230
  193. openstackclient/tests/unit/identity/v3/test_catalog.py +3 -3
  194. openstackclient/tests/unit/identity/v3/test_consumer.py +7 -8
  195. openstackclient/tests/unit/identity/v3/test_credential.py +9 -9
  196. openstackclient/tests/unit/identity/v3/test_domain.py +8 -8
  197. openstackclient/tests/unit/identity/v3/test_endpoint.py +13 -13
  198. openstackclient/tests/unit/identity/v3/test_endpoint_group.py +12 -14
  199. openstackclient/tests/unit/identity/v3/test_group.py +12 -12
  200. openstackclient/tests/unit/identity/v3/test_identity_provider.py +8 -8
  201. openstackclient/tests/unit/identity/v3/test_implied_role.py +5 -5
  202. openstackclient/tests/unit/identity/v3/test_limit.py +7 -7
  203. openstackclient/tests/unit/identity/v3/test_mappings.py +7 -7
  204. openstackclient/tests/unit/identity/v3/test_oauth.py +5 -5
  205. openstackclient/tests/unit/identity/v3/test_project.py +16 -16
  206. openstackclient/tests/unit/identity/v3/test_protocol.py +7 -7
  207. openstackclient/tests/unit/identity/v3/test_region.py +7 -7
  208. openstackclient/tests/unit/identity/v3/test_registered_limit.py +12 -13
  209. openstackclient/tests/unit/identity/v3/test_role.py +13 -13
  210. openstackclient/tests/unit/identity/v3/test_role_assignment.py +410 -331
  211. openstackclient/tests/unit/identity/v3/test_service.py +90 -94
  212. openstackclient/tests/unit/identity/v3/test_service_provider.py +7 -7
  213. openstackclient/tests/unit/identity/v3/test_token.py +4 -4
  214. openstackclient/tests/unit/identity/v3/test_trust.py +9 -9
  215. openstackclient/tests/unit/identity/v3/test_unscoped_saml.py +4 -4
  216. openstackclient/tests/unit/identity/v3/test_user.py +299 -327
  217. openstackclient/tests/unit/image/v1/test_image.py +6 -6
  218. openstackclient/tests/unit/image/v2/fakes.py +46 -9
  219. openstackclient/tests/unit/image/v2/test_cache.py +2 -2
  220. openstackclient/tests/unit/image/v2/test_image.py +3 -3
  221. openstackclient/tests/unit/image/v2/test_metadef_objects.py +62 -0
  222. openstackclient/tests/unit/image/v2/test_metadef_resource_type_association.py +131 -0
  223. openstackclient/tests/unit/integ/base.py +1 -1
  224. openstackclient/tests/unit/integ/cli/test_project.py +4 -4
  225. openstackclient/tests/unit/integ/cli/test_shell.py +7 -7
  226. openstackclient/tests/unit/network/test_common.py +12 -21
  227. openstackclient/tests/unit/network/v2/fakes.py +64 -130
  228. openstackclient/tests/unit/network/v2/test_address_group.py +15 -15
  229. openstackclient/tests/unit/network/v2/test_address_scope.py +13 -13
  230. openstackclient/tests/unit/network/v2/test_default_security_group_rule.py +49 -27
  231. openstackclient/tests/unit/network/v2/test_floating_ip_compute.py +40 -38
  232. openstackclient/tests/unit/network/v2/test_floating_ip_network.py +15 -15
  233. openstackclient/tests/unit/network/v2/test_floating_ip_pool_compute.py +4 -7
  234. openstackclient/tests/unit/network/v2/test_floating_ip_pool_network.py +3 -5
  235. openstackclient/tests/unit/network/v2/test_floating_ip_port_forwarding.py +11 -11
  236. openstackclient/tests/unit/network/v2/test_ip_availability.py +6 -6
  237. openstackclient/tests/unit/network/v2/test_l3_conntrack_helper.py +11 -21
  238. openstackclient/tests/unit/network/v2/test_local_ip.py +7 -7
  239. openstackclient/tests/unit/network/v2/test_local_ip_association.py +3 -5
  240. openstackclient/tests/unit/network/v2/test_ndp_proxy.py +13 -13
  241. openstackclient/tests/unit/network/v2/test_network.py +23 -28
  242. openstackclient/tests/unit/network/v2/test_network_agent.py +17 -21
  243. openstackclient/tests/unit/network/v2/test_network_auto_allocated_topology.py +8 -8
  244. openstackclient/tests/unit/network/v2/test_network_compute.py +66 -65
  245. openstackclient/tests/unit/network/v2/test_network_flavor.py +17 -19
  246. openstackclient/tests/unit/network/v2/test_network_flavor_profile.py +13 -13
  247. openstackclient/tests/unit/network/v2/test_network_meter.py +11 -11
  248. openstackclient/tests/unit/network/v2/test_network_meter_rule.py +11 -11
  249. openstackclient/tests/unit/network/v2/test_network_qos_policy.py +11 -21
  250. openstackclient/tests/unit/network/v2/test_network_qos_rule.py +51 -77
  251. openstackclient/tests/unit/network/v2/test_network_qos_rule_type.py +5 -9
  252. openstackclient/tests/unit/network/v2/test_network_rbac.py +12 -12
  253. openstackclient/tests/unit/network/v2/test_network_segment.py +11 -15
  254. openstackclient/tests/unit/network/v2/test_network_segment_range.py +11 -13
  255. openstackclient/tests/unit/network/v2/test_network_service_provider.py +3 -5
  256. openstackclient/tests/unit/network/v2/test_network_trunk.py +11 -11
  257. openstackclient/tests/unit/network/v2/test_port.py +22 -25
  258. openstackclient/tests/unit/network/v2/test_router.py +721 -51
  259. openstackclient/tests/unit/network/v2/test_security_group_compute.py +65 -49
  260. openstackclient/tests/unit/network/v2/test_security_group_network.py +15 -15
  261. openstackclient/tests/unit/network/v2/test_security_group_rule_compute.py +57 -45
  262. openstackclient/tests/unit/network/v2/test_security_group_rule_network.py +11 -19
  263. openstackclient/tests/unit/network/v2/test_subnet.py +29 -25
  264. openstackclient/tests/unit/network/v2/test_subnet_pool.py +15 -15
  265. openstackclient/tests/unit/object/v1/fakes.py +1 -1
  266. openstackclient/tests/unit/object/v1/test_container.py +5 -5
  267. openstackclient/tests/unit/object/v1/test_container_all.py +6 -6
  268. openstackclient/tests/unit/object/v1/test_object.py +3 -3
  269. openstackclient/tests/unit/object/v1/test_object_all.py +5 -5
  270. openstackclient/tests/unit/test_shell.py +5 -5
  271. openstackclient/tests/unit/utils.py +4 -1
  272. openstackclient/tests/unit/volume/test_find_resource.py +2 -2
  273. openstackclient/tests/unit/volume/v1/fakes.py +5 -6
  274. openstackclient/tests/unit/volume/v1/test_volume.py +5 -4
  275. openstackclient/tests/unit/volume/v2/fakes.py +39 -259
  276. openstackclient/tests/unit/volume/v2/test_consistency_group_snapshot.py +5 -5
  277. openstackclient/tests/unit/volume/v2/test_qos_specs.py +9 -9
  278. openstackclient/tests/unit/volume/v2/test_volume.py +21 -87
  279. openstackclient/tests/unit/volume/v2/test_volume_backup.py +10 -368
  280. openstackclient/tests/unit/volume/v2/test_volume_snapshot.py +1 -1
  281. openstackclient/tests/unit/volume/v2/test_volume_transfer_request.py +0 -44
  282. openstackclient/tests/unit/volume/v2/test_volume_type.py +6 -87
  283. openstackclient/tests/unit/volume/v3/fakes.py +505 -22
  284. openstackclient/tests/unit/volume/v3/test_block_storage_cleanup.py +2 -3
  285. openstackclient/tests/unit/volume/v3/test_block_storage_cluster.py +10 -11
  286. openstackclient/tests/unit/volume/v3/test_block_storage_log_level.py +10 -6
  287. openstackclient/tests/unit/volume/v3/test_block_storage_manage.py +25 -17
  288. openstackclient/tests/unit/volume/v3/test_block_storage_resource_filter.py +6 -32
  289. openstackclient/tests/unit/volume/v3/test_service.py +271 -0
  290. openstackclient/tests/unit/volume/v3/test_volume.py +2177 -33
  291. openstackclient/tests/unit/volume/v3/test_volume_attachment.py +48 -52
  292. openstackclient/tests/unit/volume/v3/test_volume_backup.py +892 -0
  293. openstackclient/tests/unit/volume/v3/test_volume_group.py +19 -20
  294. openstackclient/tests/unit/volume/v3/test_volume_group_snapshot.py +14 -34
  295. openstackclient/tests/unit/volume/v3/test_volume_group_type.py +13 -16
  296. openstackclient/tests/unit/volume/v3/test_volume_message.py +10 -11
  297. openstackclient/tests/unit/volume/v3/test_volume_snapshot.py +161 -0
  298. openstackclient/tests/unit/volume/v3/test_volume_transfer_request.py +425 -0
  299. openstackclient/tests/unit/volume/v3/test_volume_type.py +1109 -0
  300. openstackclient/volume/v1/qos_specs.py +7 -7
  301. openstackclient/volume/v1/service.py +2 -2
  302. openstackclient/volume/v1/volume.py +12 -12
  303. openstackclient/volume/v1/volume_backup.py +7 -7
  304. openstackclient/volume/v1/volume_snapshot.py +8 -8
  305. openstackclient/volume/v1/volume_transfer_request.py +5 -5
  306. openstackclient/volume/v1/volume_type.py +7 -7
  307. openstackclient/volume/v2/backup_record.py +2 -2
  308. openstackclient/volume/v2/consistency_group.py +7 -9
  309. openstackclient/volume/v2/consistency_group_snapshot.py +4 -12
  310. openstackclient/volume/v2/qos_specs.py +7 -7
  311. openstackclient/volume/v2/service.py +2 -2
  312. openstackclient/volume/v2/volume.py +80 -80
  313. openstackclient/volume/v2/volume_backend.py +2 -2
  314. openstackclient/volume/v2/volume_backup.py +9 -217
  315. openstackclient/volume/v2/volume_host.py +2 -2
  316. openstackclient/volume/v2/volume_snapshot.py +8 -8
  317. openstackclient/volume/v2/volume_transfer_request.py +5 -37
  318. openstackclient/volume/v2/volume_type.py +7 -89
  319. openstackclient/volume/v3/service.py +56 -0
  320. openstackclient/volume/v3/volume.py +971 -0
  321. openstackclient/volume/v3/volume_attachment.py +31 -29
  322. openstackclient/volume/v3/volume_backup.py +670 -0
  323. openstackclient/volume/v3/volume_message.py +1 -1
  324. openstackclient/volume/v3/volume_snapshot.py +97 -0
  325. openstackclient/volume/v3/volume_transfer_request.py +233 -0
  326. openstackclient/volume/v3/volume_type.py +967 -0
  327. {python_openstackclient-6.6.1.dist-info → python_openstackclient-7.1.0.dist-info}/AUTHORS +6 -0
  328. {python_openstackclient-6.6.1.dist-info → python_openstackclient-7.1.0.dist-info}/METADATA +4 -4
  329. python_openstackclient-7.1.0.dist-info/RECORD +503 -0
  330. {python_openstackclient-6.6.1.dist-info → python_openstackclient-7.1.0.dist-info}/entry_points.txt +33 -27
  331. python_openstackclient-7.1.0.dist-info/pbr.json +1 -0
  332. python_openstackclient-6.6.1.dist-info/RECORD +0 -489
  333. python_openstackclient-6.6.1.dist-info/pbr.json +0 -1
  334. {python_openstackclient-6.6.1.dist-info → python_openstackclient-7.1.0.dist-info}/LICENSE +0 -0
  335. {python_openstackclient-6.6.1.dist-info → python_openstackclient-7.1.0.dist-info}/WHEEL +0 -0
  336. {python_openstackclient-6.6.1.dist-info → python_openstackclient-7.1.0.dist-info}/top_level.txt +0 -0
@@ -16,15 +16,15 @@
16
16
  """Compute v2 Server action implementations"""
17
17
 
18
18
  import argparse
19
+ import base64
19
20
  import getpass
20
- import io
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
27
- from novaclient import api_versions
28
28
  from openstack import exceptions as sdk_exceptions
29
29
  from openstack import utils as sdk_utils
30
30
  from osc_lib.cli import format_columns
@@ -33,6 +33,7 @@ from osc_lib.command import command
33
33
  from osc_lib import exceptions
34
34
  from osc_lib import utils
35
35
 
36
+ from openstackclient.api import compute_v2
36
37
  from openstackclient.common import pagination
37
38
  from openstackclient.i18n import _
38
39
  from openstackclient.identity import common as identity_common
@@ -81,7 +82,7 @@ class AddressesColumn(cliff_columns.FormattableColumn):
81
82
  def machine_readable(self):
82
83
  return {
83
84
  k: [i['addr'] for i in v if 'addr' in i]
84
- for k, v in self._value.items()
85
+ for k, v in (self._value.items() if self._value else [])
85
86
  }
86
87
 
87
88
 
@@ -128,23 +129,26 @@ def _get_ip_address(addresses, address_type, ip_address_family):
128
129
  )
129
130
 
130
131
 
131
- def _prep_server_detail(compute_client, image_client, server, refresh=True):
132
+ def _prep_server_detail(compute_client, image_client, server, *, refresh=True):
132
133
  """Prepare the detailed server dict for printing
133
134
 
134
135
  :param compute_client: a compute client instance
135
136
  :param image_client: an image client instance
136
137
  :param server: a Server resource
137
138
  :param refresh: Flag indicating if ``server`` is already the latest version
138
- or if it needs to be refreshed, for example when showing
139
- the latest details of a server after creating it.
139
+ or if it needs to be refreshed, for example when showing the latest
140
+ details of a server after creating it.
140
141
  :rtype: a dict of server details
141
142
  """
142
- # Note: Some callers of this routine pass a novaclient server, and others
143
- # pass an SDK server. Column names may be different across those cases.
144
143
  info = server.to_dict()
144
+
145
145
  if refresh:
146
- server = utils.find_resource(compute_client.servers, info['id'])
147
- info.update(server.to_dict())
146
+ server = compute_client.get_server(info['id'])
147
+ # we only update if the field is not empty, to avoid overwriting
148
+ # existing values
149
+ info.update(
150
+ **{x: y for x, y in server.to_dict().items() if x not in info or y}
151
+ )
148
152
 
149
153
  # Some commands using this routine were originally implemented with the
150
154
  # nova python wrappers, and were later migrated to use the SDK. Map the
@@ -159,7 +163,6 @@ def _prep_server_detail(compute_client, image_client, server, refresh=True):
159
163
  'compute_host': 'OS-EXT-SRV-ATTR:host',
160
164
  'created_at': 'created',
161
165
  'disk_config': 'OS-DCF:diskConfig',
162
- 'flavor_id': 'flavorRef',
163
166
  'has_config_drive': 'config_drive',
164
167
  'host_id': 'hostId',
165
168
  'fault': 'fault',
@@ -180,6 +183,7 @@ def _prep_server_detail(compute_client, image_client, server, refresh=True):
180
183
  'updated_at': 'updated',
181
184
  'user_data': 'OS-EXT-SRV-ATTR:user_data',
182
185
  'vm_state': 'OS-EXT-STS:vm_state',
186
+ 'pinned_availability_zone': 'pinned_availability_zone',
183
187
  }
184
188
  # Some columns returned by openstacksdk should not be shown because they're
185
189
  # either irrelevant or duplicates
@@ -193,9 +197,13 @@ def _prep_server_detail(compute_client, image_client, server, refresh=True):
193
197
  'public_v6',
194
198
  # create-only columns
195
199
  'block_device_mapping',
200
+ 'flavor_id',
201
+ 'host',
196
202
  'image_id',
197
203
  'max_count',
198
204
  'min_count',
205
+ 'networks',
206
+ 'personality',
199
207
  'scheduler_hints',
200
208
  # aliases
201
209
  'volumes',
@@ -205,11 +213,12 @@ def _prep_server_detail(compute_client, image_client, server, refresh=True):
205
213
  # Some columns are only present in certain responses and should not be
206
214
  # shown otherwise.
207
215
  optional_columns = {
208
- 'admin_password', # removed in 2.14
209
- 'fault', # only present in errored servers
210
- 'flavor_id', # removed in 2.47
211
- 'networks', # only present in create responses
212
- 'security_groups', # only present in create, detail responses
216
+ # only in create responses if '[api] enable_instance_password' is set
217
+ 'admin_password',
218
+ # only present in errored servers
219
+ 'fault',
220
+ # only present in create, detail responses
221
+ 'security_groups',
213
222
  }
214
223
 
215
224
  data = {}
@@ -232,7 +241,7 @@ def _prep_server_detail(compute_client, image_client, server, refresh=True):
232
241
  image_id = image_info.get('id', '')
233
242
  try:
234
243
  image = image_client.get_image(image_id)
235
- info['image'] = "%s (%s)" % (image.name, image_id)
244
+ info['image'] = f"{image.name} ({image_id})"
236
245
  except Exception:
237
246
  info['image'] = image_id
238
247
  else:
@@ -249,8 +258,10 @@ def _prep_server_detail(compute_client, image_client, server, refresh=True):
249
258
  if flavor_info.get('original_name') is None: # microversion < 2.47
250
259
  flavor_id = flavor_info.get('id', '')
251
260
  try:
252
- flavor = utils.find_resource(compute_client.flavors, flavor_id)
253
- info['flavor'] = "%s (%s)" % (flavor.name, flavor_id)
261
+ flavor = compute_client.find_flavor(
262
+ flavor_id, ignore_missing=False
263
+ )
264
+ info['flavor'] = f"{flavor.name} ({flavor_id})"
254
265
  except Exception:
255
266
  info['flavor'] = flavor_id
256
267
  else: # microversion >= 2.47
@@ -283,7 +294,9 @@ def _prep_server_detail(compute_client, image_client, server, refresh=True):
283
294
  )
284
295
 
285
296
  if 'tags' in info:
286
- info.update({'tags': format_columns.ListColumn(info.pop('tags'))})
297
+ info.update(
298
+ {'tags': format_columns.ListColumn(info.pop('tags') or [])}
299
+ )
287
300
 
288
301
  # Map 'networks' to 'addresses', if present. Note that the 'networks' key
289
302
  # is used for create responses, otherwise it's 'addresses'. We know it'll
@@ -357,7 +370,7 @@ class AddFixedIP(command.ShowOne):
357
370
  _description = _("Add fixed IP address to server")
358
371
 
359
372
  def get_parser(self, prog_name):
360
- parser = super(AddFixedIP, self).get_parser(prog_name)
373
+ parser = super().get_parser(prog_name)
361
374
  parser.add_argument(
362
375
  "server",
363
376
  metavar="<server>",
@@ -480,16 +493,16 @@ class AddFloatingIP(network_common.NetworkAndComputeCommand):
480
493
  return parser
481
494
 
482
495
  def take_action_network(self, client, parsed_args):
483
- compute_client = self.app.client_manager.compute
496
+ compute_client = self.app.client_manager.sdk_connection.compute
484
497
 
485
498
  attrs = {}
486
499
  obj = client.find_ip(
487
500
  parsed_args.ip_address,
488
501
  ignore_missing=False,
489
502
  )
490
- server = utils.find_resource(
491
- compute_client.servers,
492
- parsed_args.server,
503
+
504
+ server = compute_client.find_server(
505
+ parsed_args.server, ignore_missing=False
493
506
  )
494
507
  ports = list(client.ports(device_id=server.id))
495
508
  if not ports:
@@ -539,8 +552,9 @@ class AddFloatingIP(network_common.NetworkAndComputeCommand):
539
552
  raise error
540
553
 
541
554
  def take_action_compute(self, client, parsed_args):
542
- client.api.floating_ip_add(
543
- parsed_args.server,
555
+ server = client.find_server(parsed_args.server, ignore_missing=False)
556
+ client.add_floating_ip_to_server(
557
+ server,
544
558
  parsed_args.ip_address,
545
559
  fixed_address=parsed_args.fixed_ip_address,
546
560
  )
@@ -550,7 +564,7 @@ class AddPort(command.Command):
550
564
  _description = _("Add port to server")
551
565
 
552
566
  def get_parser(self, prog_name):
553
- parser = super(AddPort, self).get_parser(prog_name)
567
+ parser = super().get_parser(prog_name)
554
568
  parser.add_argument(
555
569
  "server",
556
570
  metavar="<server>",
@@ -604,7 +618,7 @@ class AddNetwork(command.Command):
604
618
  _description = _("Add network to server")
605
619
 
606
620
  def get_parser(self, prog_name):
607
- parser = super(AddNetwork, self).get_parser(prog_name)
621
+ parser = super().get_parser(prog_name)
608
622
  parser.add_argument(
609
623
  "server",
610
624
  metavar="<server>",
@@ -659,7 +673,7 @@ class AddServerSecurityGroup(command.Command):
659
673
  _description = _("Add security group to server")
660
674
 
661
675
  def get_parser(self, prog_name):
662
- parser = super(AddServerSecurityGroup, self).get_parser(prog_name)
676
+ parser = super().get_parser(prog_name)
663
677
  parser.add_argument(
664
678
  'server',
665
679
  metavar='<server>',
@@ -673,17 +687,21 @@ class AddServerSecurityGroup(command.Command):
673
687
  return parser
674
688
 
675
689
  def take_action(self, parsed_args):
676
- compute_client = self.app.client_manager.compute
690
+ compute_client = self.app.client_manager.sdk_connection.compute
677
691
 
678
- server = utils.find_resource(
679
- compute_client.servers,
680
- parsed_args.server,
681
- )
682
- security_group = compute_client.api.security_group_find(
683
- parsed_args.group,
692
+ server = compute_client.find_server(
693
+ parsed_args.server, ignore_missing=False
684
694
  )
685
-
686
- server.add_security_group(security_group['id'])
695
+ if self.app.client_manager.is_network_endpoint_enabled():
696
+ # the server handles both names and IDs for neutron SGs, so just
697
+ # pass things through
698
+ security_group = parsed_args.group
699
+ else:
700
+ # however, if using nova-network then it needs a name, not an ID
701
+ security_group = compute_v2.find_security_group(
702
+ compute_client, parsed_args.group
703
+ )['name']
704
+ compute_client.add_security_group_to_server(server, security_group)
687
705
 
688
706
 
689
707
  class AddServerVolume(command.ShowOne):
@@ -695,7 +713,7 @@ with status ``SHELVED`` or ``SHELVED_OFFLOADED``."""
695
713
  )
696
714
 
697
715
  def get_parser(self, prog_name):
698
- parser = super(AddServerVolume, self).get_parser(prog_name)
716
+ parser = super().get_parser(prog_name)
699
717
  parser.add_argument(
700
718
  'server',
701
719
  metavar='<server>',
@@ -914,10 +932,17 @@ class NICAction(argparse.Action):
914
932
 
915
933
  if info['net-id'] and info['port-id']:
916
934
  msg = _(
917
- 'Invalid argument %s; either network or port should be '
918
- 'specified but not both'
935
+ "Invalid argument %s; either 'network' or 'port' should be "
936
+ "specified but not both"
919
937
  )
920
- raise argparse.ArgumenteError(self, msg % values)
938
+ raise argparse.ArgumentError(self, msg % values)
939
+
940
+ if info['v4-fixed-ip'] and info['v6-fixed-ip']:
941
+ msg = _(
942
+ "Invalid argument %s; either 'v4-fixed-ip' or 'v6-fixed-ip' "
943
+ "should be specified but not both"
944
+ )
945
+ raise argparse.ArgumentError(self, msg % values)
921
946
 
922
947
  getattr(namespace, self.dest).append(info)
923
948
 
@@ -1049,7 +1074,7 @@ class CreateServer(command.ShowOne):
1049
1074
  _description = _("Create a new server")
1050
1075
 
1051
1076
  def get_parser(self, prog_name):
1052
- parser = super(CreateServer, self).get_parser(prog_name)
1077
+ parser = super().get_parser(prog_name)
1053
1078
  parser.add_argument(
1054
1079
  'server_name',
1055
1080
  metavar='<server-name>',
@@ -1148,7 +1173,7 @@ class CreateServer(command.ShowOne):
1148
1173
  )
1149
1174
  parser.add_argument(
1150
1175
  '--block-device',
1151
- metavar='',
1176
+ metavar='<block-device>',
1152
1177
  action=BDMAction,
1153
1178
  dest='block_devices',
1154
1179
  default=[],
@@ -1482,7 +1507,7 @@ class CreateServer(command.ShowOne):
1482
1507
  self.app.stdout.write('\rProgress: %s' % progress)
1483
1508
  self.app.stdout.flush()
1484
1509
 
1485
- compute_client = self.app.client_manager.compute
1510
+ compute_client = self.app.client_manager.sdk_connection.compute
1486
1511
  volume_client = self.app.client_manager.volume
1487
1512
  image_client = self.app.client_manager.image
1488
1513
 
@@ -1518,7 +1543,7 @@ class CreateServer(command.ShowOne):
1518
1543
  img_dict_items.extend(list(img.properties.items()))
1519
1544
  for key, value in img_dict_items:
1520
1545
  try:
1521
- set([key, value])
1546
+ {key, value}
1522
1547
  except TypeError:
1523
1548
  if key != 'properties':
1524
1549
  LOG.debug(
@@ -1577,12 +1602,12 @@ class CreateServer(command.ShowOne):
1577
1602
  parsed_args.snapshot,
1578
1603
  ).id
1579
1604
 
1580
- flavor = utils.find_resource(
1581
- compute_client.flavors, parsed_args.flavor
1605
+ flavor = compute_client.find_flavor(
1606
+ parsed_args.flavor, ignore_missing=False
1582
1607
  )
1583
1608
 
1584
1609
  if parsed_args.file:
1585
- if compute_client.api_version >= api_versions.APIVersion('2.57'):
1610
+ if sdk_utils.supports_microversion(compute_client, '2.57'):
1586
1611
  msg = _(
1587
1612
  'Personality files are deprecated and are not supported '
1588
1613
  'for --os-compute-api-version greater than 2.56; use '
@@ -1594,8 +1619,8 @@ class CreateServer(command.ShowOne):
1594
1619
  for f in parsed_args.file:
1595
1620
  dst, src = f.split('=', 1)
1596
1621
  try:
1597
- files[dst] = io.open(src, 'rb')
1598
- except IOError as e:
1622
+ files[dst] = open(src, 'rb')
1623
+ except OSError as e:
1599
1624
  msg = _("Can't open '%(source)s': %(exception)s")
1600
1625
  raise exceptions.CommandError(
1601
1626
  msg % {'source': src, 'exception': e}
@@ -1613,18 +1638,20 @@ class CreateServer(command.ShowOne):
1613
1638
  msg = _("max instances should be > 0")
1614
1639
  raise exceptions.CommandError(msg)
1615
1640
 
1616
- userdata = None
1641
+ user_data = None
1617
1642
  if parsed_args.user_data:
1618
1643
  try:
1619
- userdata = io.open(parsed_args.user_data)
1620
- except IOError as e:
1644
+ with open(parsed_args.user_data, 'rb') as fh:
1645
+ # TODO(stephenfin): SDK should do this for us
1646
+ user_data = base64.b64encode(fh.read()).decode('utf-8')
1647
+ except OSError as e:
1621
1648
  msg = _("Can't open '%(data)s': %(exception)s")
1622
1649
  raise exceptions.CommandError(
1623
1650
  msg % {'data': parsed_args.user_data, 'exception': e}
1624
1651
  )
1625
1652
 
1626
1653
  if parsed_args.description:
1627
- if compute_client.api_version < api_versions.APIVersion("2.19"):
1654
+ if not sdk_utils.supports_microversion(compute_client, '2.19'):
1628
1655
  msg = _(
1629
1656
  '--os-compute-api-version 2.19 or greater is '
1630
1657
  'required to support the --description option'
@@ -1632,26 +1659,7 @@ class CreateServer(command.ShowOne):
1632
1659
  raise exceptions.CommandError(msg)
1633
1660
 
1634
1661
  block_device_mapping_v2 = []
1635
- if volume:
1636
- block_device_mapping_v2 = [
1637
- {
1638
- 'uuid': volume,
1639
- 'boot_index': 0,
1640
- 'source_type': 'volume',
1641
- 'destination_type': 'volume',
1642
- }
1643
- ]
1644
- elif snapshot:
1645
- block_device_mapping_v2 = [
1646
- {
1647
- 'uuid': snapshot,
1648
- 'boot_index': 0,
1649
- 'source_type': 'snapshot',
1650
- 'destination_type': 'volume',
1651
- 'delete_on_termination': False,
1652
- }
1653
- ]
1654
- elif parsed_args.boot_from_volume:
1662
+ if parsed_args.boot_from_volume:
1655
1663
  # Tell nova to create a root volume from the image provided.
1656
1664
  if not image:
1657
1665
  msg = _(
@@ -1670,6 +1678,35 @@ class CreateServer(command.ShowOne):
1670
1678
  ]
1671
1679
  # If booting from volume we do not pass an image to compute.
1672
1680
  image = None
1681
+ elif image:
1682
+ block_device_mapping_v2 = [
1683
+ {
1684
+ 'uuid': image.id,
1685
+ 'boot_index': 0,
1686
+ 'source_type': 'image',
1687
+ 'destination_type': 'local',
1688
+ 'delete_on_termination': True,
1689
+ }
1690
+ ]
1691
+ elif volume:
1692
+ block_device_mapping_v2 = [
1693
+ {
1694
+ 'uuid': volume,
1695
+ 'boot_index': 0,
1696
+ 'source_type': 'volume',
1697
+ 'destination_type': 'volume',
1698
+ }
1699
+ ]
1700
+ elif snapshot:
1701
+ block_device_mapping_v2 = [
1702
+ {
1703
+ 'uuid': snapshot,
1704
+ 'boot_index': 0,
1705
+ 'source_type': 'snapshot',
1706
+ 'destination_type': 'volume',
1707
+ 'delete_on_termination': False,
1708
+ }
1709
+ ]
1673
1710
 
1674
1711
  if parsed_args.swap:
1675
1712
  block_device_mapping_v2.append(
@@ -1745,7 +1782,7 @@ class CreateServer(command.ShowOne):
1745
1782
  raise exceptions.CommandError(msg)
1746
1783
 
1747
1784
  if 'tag' in mapping and (
1748
- compute_client.api_version < api_versions.APIVersion('2.42')
1785
+ not sdk_utils.supports_microversion(compute_client, '2.42')
1749
1786
  ):
1750
1787
  msg = _(
1751
1788
  '--os-compute-api-version 2.42 or greater is '
@@ -1754,7 +1791,7 @@ class CreateServer(command.ShowOne):
1754
1791
  raise exceptions.CommandError(msg)
1755
1792
 
1756
1793
  if 'volume_type' in mapping and (
1757
- compute_client.api_version < api_versions.APIVersion('2.67')
1794
+ not sdk_utils.supports_microversion(compute_client, '2.67')
1758
1795
  ):
1759
1796
  msg = _(
1760
1797
  '--os-compute-api-version 2.67 or greater is '
@@ -1810,7 +1847,7 @@ class CreateServer(command.ShowOne):
1810
1847
 
1811
1848
  block_device_mapping_v2.append(mapping)
1812
1849
 
1813
- if not image and not any(
1850
+ if not any(
1814
1851
  [bdm.get('boot_index') == 0 for bdm in block_device_mapping_v2]
1815
1852
  ):
1816
1853
  msg = _(
@@ -1819,10 +1856,12 @@ class CreateServer(command.ShowOne):
1819
1856
  )
1820
1857
  raise exceptions.CommandError(msg)
1821
1858
 
1822
- nics = parsed_args.nics
1859
+ # Default to empty list if nothing was specified and let nova
1860
+ # decide the default behavior.
1861
+ networks: ty.Union[str, ty.List[ty.Dict[str, str]], None] = []
1823
1862
 
1824
- if 'auto' in nics or 'none' in nics:
1825
- if len(nics) > 1:
1863
+ if 'auto' in parsed_args.nics or 'none' in parsed_args.nics:
1864
+ if len(parsed_args.nics) > 1:
1826
1865
  msg = _(
1827
1866
  'Specifying a --nic of auto or none cannot '
1828
1867
  'be used with any other --nic, --network '
@@ -1830,7 +1869,7 @@ class CreateServer(command.ShowOne):
1830
1869
  )
1831
1870
  raise exceptions.CommandError(msg)
1832
1871
 
1833
- if compute_client.api_version < api_versions.APIVersion('2.37'):
1872
+ if not sdk_utils.supports_microversion(compute_client, '2.37'):
1834
1873
  msg = _(
1835
1874
  '--os-compute-api-version 2.37 or greater is '
1836
1875
  'required to support explicit auto-allocation of a '
@@ -1838,12 +1877,12 @@ class CreateServer(command.ShowOne):
1838
1877
  )
1839
1878
  raise exceptions.CommandError(msg)
1840
1879
 
1841
- nics = nics[0]
1880
+ networks = parsed_args.nics[0]
1842
1881
  else:
1843
- for nic in nics:
1882
+ for nic in parsed_args.nics:
1844
1883
  if 'tag' in nic:
1845
- if compute_client.api_version < api_versions.APIVersion(
1846
- '2.43'
1884
+ if not sdk_utils.supports_microversion(
1885
+ compute_client, '2.43'
1847
1886
  ):
1848
1887
  msg = _(
1849
1888
  '--os-compute-api-version 2.43 or greater is '
@@ -1869,9 +1908,11 @@ class CreateServer(command.ShowOne):
1869
1908
  nic['port-id'] = port.id
1870
1909
  else:
1871
1910
  if nic['net-id']:
1872
- nic['net-id'] = compute_client.api.network_find(
1911
+ net = compute_v2.find_network(
1912
+ compute_client,
1873
1913
  nic['net-id'],
1874
- )['id']
1914
+ )
1915
+ nic['net-id'] = net['id']
1875
1916
 
1876
1917
  if nic['port-id']:
1877
1918
  msg = _(
@@ -1880,18 +1921,35 @@ class CreateServer(command.ShowOne):
1880
1921
  )
1881
1922
  raise exceptions.CommandError(msg)
1882
1923
 
1883
- if not nics:
1924
+ # convert from the novaclient-derived "NIC" view to the actual
1925
+ # "network" view
1926
+ network = {}
1927
+
1928
+ if nic['net-id']:
1929
+ network['uuid'] = nic['net-id']
1930
+
1931
+ if nic['port-id']:
1932
+ network['port'] = nic['port-id']
1933
+
1934
+ if nic['v4-fixed-ip']:
1935
+ network['fixed'] = nic['v4-fixed-ip']
1936
+ elif nic['v6-fixed-ip']:
1937
+ network['fixed'] = nic['v6-fixed-ip']
1938
+
1939
+ if nic.get('tag'): # tags are optional
1940
+ network['tag'] = nic['tag']
1941
+
1942
+ networks.append(network)
1943
+
1944
+ if not parsed_args.nics and sdk_utils.supports_microversion(
1945
+ compute_client, '2.37'
1946
+ ):
1884
1947
  # Compute API version >= 2.37 requires a value, so default to
1885
1948
  # 'auto' to maintain legacy behavior if a nic wasn't specified.
1886
- if compute_client.api_version >= api_versions.APIVersion('2.37'):
1887
- nics = 'auto'
1888
- else:
1889
- # Default to empty list if nothing was specified and let nova
1890
- # decide the default behavior.
1891
- nics = []
1949
+ networks = 'auto'
1892
1950
 
1893
1951
  # Check security group exist and convert ID to name
1894
- security_group_names = []
1952
+ security_groups = []
1895
1953
  if self.app.client_manager.is_network_endpoint_enabled():
1896
1954
  network_client = self.app.client_manager.network
1897
1955
  for each_sg in parsed_args.security_group:
@@ -1900,12 +1958,12 @@ class CreateServer(command.ShowOne):
1900
1958
  )
1901
1959
  # Use security group ID to avoid multiple security group have
1902
1960
  # same name in neutron networking backend
1903
- security_group_names.append(sg.id)
1961
+ security_groups.append({'name': sg.id})
1904
1962
  else:
1905
1963
  # Handle nova-network case
1906
1964
  for each_sg in parsed_args.security_group:
1907
- sg = compute_client.api.security_group_find(each_sg)
1908
- security_group_names.append(sg['name'])
1965
+ sg = compute_v2.find_security_group(compute_client, each_sg)
1966
+ security_groups.append({'name': sg['name']})
1909
1967
 
1910
1968
  hints = {}
1911
1969
  for key, values in parsed_args.hints.items():
@@ -1916,9 +1974,8 @@ class CreateServer(command.ShowOne):
1916
1974
  hints[key] = values
1917
1975
 
1918
1976
  if parsed_args.server_group:
1919
- server_group_obj = utils.find_resource(
1920
- compute_client.server_groups,
1921
- parsed_args.server_group,
1977
+ server_group_obj = compute_client.find_server_group(
1978
+ parsed_args.server_group, ignore_missing=False
1922
1979
  )
1923
1980
  hints['group'] = server_group_obj.id
1924
1981
 
@@ -1940,69 +1997,89 @@ class CreateServer(command.ShowOne):
1940
1997
  else:
1941
1998
  config_drive = parsed_args.config_drive
1942
1999
 
1943
- boot_args = [parsed_args.server_name, image, flavor]
1944
-
1945
- boot_kwargs = dict(
1946
- meta=parsed_args.properties,
1947
- files=files,
1948
- reservation_id=None,
1949
- min_count=parsed_args.min,
1950
- max_count=parsed_args.max,
1951
- security_groups=security_group_names,
1952
- userdata=userdata,
1953
- key_name=parsed_args.key_name,
1954
- availability_zone=parsed_args.availability_zone,
1955
- admin_pass=parsed_args.password,
1956
- block_device_mapping_v2=block_device_mapping_v2,
1957
- nics=nics,
1958
- scheduler_hints=hints,
1959
- config_drive=config_drive,
1960
- )
2000
+ kwargs = {
2001
+ 'name': parsed_args.server_name,
2002
+ 'image_id': image.id if image else '',
2003
+ 'flavor_id': flavor.id,
2004
+ 'min_count': parsed_args.min,
2005
+ 'max_count': parsed_args.max,
2006
+ }
1961
2007
 
1962
2008
  if parsed_args.description:
1963
- boot_kwargs['description'] = parsed_args.description
2009
+ kwargs['description'] = parsed_args.description
2010
+
2011
+ if parsed_args.availability_zone:
2012
+ kwargs['availability_zone'] = parsed_args.availability_zone
2013
+
2014
+ if parsed_args.password:
2015
+ kwargs['admin_password'] = parsed_args.password
2016
+
2017
+ if parsed_args.properties:
2018
+ kwargs['metadata'] = parsed_args.properties
2019
+
2020
+ if parsed_args.key_name:
2021
+ kwargs['key_name'] = parsed_args.key_name
2022
+
2023
+ if user_data:
2024
+ kwargs['user_data'] = user_data
2025
+
2026
+ if files:
2027
+ kwargs['personality'] = files
2028
+
2029
+ if security_groups:
2030
+ kwargs['security_groups'] = security_groups
2031
+
2032
+ if block_device_mapping_v2:
2033
+ kwargs['block_device_mapping'] = block_device_mapping_v2
2034
+
2035
+ if hints:
2036
+ kwargs['scheduler_hints'] = hints
2037
+
2038
+ if networks is not None:
2039
+ kwargs['networks'] = networks
2040
+
2041
+ if config_drive is not None:
2042
+ kwargs['config_drive'] = config_drive
1964
2043
 
1965
2044
  if parsed_args.tags:
1966
- if compute_client.api_version < api_versions.APIVersion('2.52'):
2045
+ if not sdk_utils.supports_microversion(compute_client, '2.52'):
1967
2046
  msg = _(
1968
2047
  '--os-compute-api-version 2.52 or greater is required to '
1969
2048
  'support the --tag option'
1970
2049
  )
1971
2050
  raise exceptions.CommandError(msg)
1972
2051
 
1973
- boot_kwargs['tags'] = parsed_args.tags
2052
+ kwargs['tags'] = parsed_args.tags
1974
2053
 
1975
2054
  if parsed_args.host:
1976
- if compute_client.api_version < api_versions.APIVersion("2.74"):
2055
+ if not sdk_utils.supports_microversion(compute_client, '2.74'):
1977
2056
  msg = _(
1978
2057
  '--os-compute-api-version 2.74 or greater is required to '
1979
2058
  'support the --host option'
1980
2059
  )
1981
2060
  raise exceptions.CommandError(msg)
1982
2061
 
1983
- boot_kwargs['host'] = parsed_args.host
2062
+ kwargs['host'] = parsed_args.host
1984
2063
 
1985
2064
  if parsed_args.hypervisor_hostname:
1986
- if compute_client.api_version < api_versions.APIVersion("2.74"):
2065
+ if not sdk_utils.supports_microversion(compute_client, '2.74'):
1987
2066
  msg = _(
1988
2067
  '--os-compute-api-version 2.74 or greater is required to '
1989
2068
  'support the --hypervisor-hostname option'
1990
2069
  )
1991
2070
  raise exceptions.CommandError(msg)
1992
2071
 
1993
- boot_kwargs[
1994
- 'hypervisor_hostname'
1995
- ] = parsed_args.hypervisor_hostname
2072
+ kwargs['hypervisor_hostname'] = parsed_args.hypervisor_hostname
1996
2073
 
1997
2074
  if parsed_args.hostname:
1998
- if compute_client.api_version < api_versions.APIVersion("2.90"):
2075
+ if not sdk_utils.supports_microversion(compute_client, '2.90'):
1999
2076
  msg = _(
2000
2077
  '--os-compute-api-version 2.90 or greater is required to '
2001
2078
  'support the --hostname option'
2002
2079
  )
2003
2080
  raise exceptions.CommandError(msg)
2004
2081
 
2005
- boot_kwargs['hostname'] = parsed_args.hostname
2082
+ kwargs['hostname'] = parsed_args.hostname
2006
2083
 
2007
2084
  # TODO(stephenfin): Handle OS_TRUSTED_IMAGE_CERTIFICATE_IDS
2008
2085
  if parsed_args.trusted_image_certs:
@@ -2012,7 +2089,7 @@ class CreateServer(command.ShowOne):
2012
2089
  'servers booted directly from images'
2013
2090
  )
2014
2091
  raise exceptions.CommandError(msg)
2015
- if compute_client.api_version < api_versions.APIVersion('2.63'):
2092
+ if not sdk_utils.supports_microversion(compute_client, '2.63'):
2016
2093
  msg = _(
2017
2094
  '--os-compute-api-version 2.63 or greater is required to '
2018
2095
  'support the --trusted-image-cert option'
@@ -2020,25 +2097,22 @@ class CreateServer(command.ShowOne):
2020
2097
  raise exceptions.CommandError(msg)
2021
2098
 
2022
2099
  certs = parsed_args.trusted_image_certs
2023
- boot_kwargs['trusted_image_certificates'] = certs
2100
+ kwargs['trusted_image_certificates'] = certs
2024
2101
 
2025
- LOG.debug('boot_args: %s', boot_args)
2026
- LOG.debug('boot_kwargs: %s', boot_kwargs)
2102
+ LOG.debug('boot_kwargs: %s', kwargs)
2027
2103
 
2028
2104
  # Wrap the call to catch exceptions in order to close files
2029
2105
  try:
2030
- server = compute_client.servers.create(*boot_args, **boot_kwargs)
2106
+ server = compute_client.create_server(**kwargs)
2031
2107
  finally:
2032
2108
  # Clean up open files - make sure they are not strings
2033
2109
  for f in files:
2034
2110
  if hasattr(f, 'close'):
2035
2111
  f.close()
2036
- if hasattr(userdata, 'close'):
2037
- userdata.close()
2038
2112
 
2039
2113
  if parsed_args.wait:
2040
2114
  if utils.wait_for_status(
2041
- compute_client.servers.get,
2115
+ compute_client.get_server,
2042
2116
  server.id,
2043
2117
  callback=_show_progress,
2044
2118
  ):
@@ -2047,8 +2121,8 @@ class CreateServer(command.ShowOne):
2047
2121
  msg = _('Error creating server: %s') % parsed_args.server_name
2048
2122
  raise exceptions.CommandError(msg)
2049
2123
 
2050
- details = _prep_server_detail(compute_client, image_client, server)
2051
- return zip(*sorted(details.items()))
2124
+ data = _prep_server_detail(compute_client, image_client, server)
2125
+ return zip(*sorted(data.items()))
2052
2126
 
2053
2127
 
2054
2128
  class CreateServerDump(command.Command):
@@ -2064,7 +2138,7 @@ class CreateServerDump(command.Command):
2064
2138
  """
2065
2139
 
2066
2140
  def get_parser(self, prog_name):
2067
- parser = super(CreateServerDump, self).get_parser(prog_name)
2141
+ parser = super().get_parser(prog_name)
2068
2142
  parser.add_argument(
2069
2143
  'server',
2070
2144
  metavar='<server>',
@@ -2084,7 +2158,7 @@ class DeleteServer(command.Command):
2084
2158
  _description = _("Delete server(s)")
2085
2159
 
2086
2160
  def get_parser(self, prog_name):
2087
- parser = super(DeleteServer, self).get_parser(prog_name)
2161
+ parser = super().get_parser(prog_name)
2088
2162
  parser.add_argument(
2089
2163
  'server',
2090
2164
  metavar='<server>',
@@ -2118,25 +2192,22 @@ class DeleteServer(command.Command):
2118
2192
  self.app.stdout.write('\rProgress: %s' % progress)
2119
2193
  self.app.stdout.flush()
2120
2194
 
2121
- compute_client = self.app.client_manager.compute
2195
+ compute_client = self.app.client_manager.sdk_connection.compute
2122
2196
  for server in parsed_args.server:
2123
- server_obj = utils.find_resource(
2124
- compute_client.servers,
2197
+ server_obj = compute_client.find_server(
2125
2198
  server,
2126
- all_tenants=parsed_args.all_projects,
2199
+ ignore_missing=False,
2200
+ all_projects=parsed_args.all_projects,
2127
2201
  )
2128
2202
 
2129
- if parsed_args.force:
2130
- compute_client.servers.force_delete(server_obj.id)
2131
- else:
2132
- compute_client.servers.delete(server_obj.id)
2203
+ compute_client.delete_server(server_obj, force=parsed_args.force)
2133
2204
 
2134
2205
  if parsed_args.wait:
2135
- if not utils.wait_for_delete(
2136
- compute_client.servers,
2137
- server_obj.id,
2138
- callback=_show_progress,
2139
- ):
2206
+ try:
2207
+ compute_client.wait_for_delete(
2208
+ server_obj, callback=_show_progress
2209
+ )
2210
+ except sdk_exceptions.ResourceTimeout:
2140
2211
  msg = _('Error deleting server: %s') % server_obj.id
2141
2212
  raise exceptions.CommandError(msg)
2142
2213
 
@@ -2189,7 +2260,7 @@ class ListServer(command.Lister):
2189
2260
  _description = _("List servers")
2190
2261
 
2191
2262
  def get_parser(self, prog_name):
2192
- parser = super(ListServer, self).get_parser(prog_name)
2263
+ parser = super().get_parser(prog_name)
2193
2264
  parser.add_argument(
2194
2265
  '--reservation-id',
2195
2266
  metavar='<reservation-id>',
@@ -2457,7 +2528,7 @@ class ListServer(command.Lister):
2457
2528
  action='store_true',
2458
2529
  default=False,
2459
2530
  help=_(
2460
- 'When looking up flavor and image names, look them up'
2531
+ 'When looking up flavor and image names, look them up '
2461
2532
  'one by one as needed instead of all together (default). '
2462
2533
  'Mutually exclusive with "--no-name-lookup|-n" option.'
2463
2534
  ),
@@ -2752,11 +2823,13 @@ class ListServer(command.Lister):
2752
2823
  if parsed_args.long:
2753
2824
  columns += (
2754
2825
  'availability_zone',
2826
+ 'pinned_availability_zone',
2755
2827
  'hypervisor_hostname',
2756
2828
  'metadata',
2757
2829
  )
2758
2830
  column_headers += (
2759
2831
  'Availability Zone',
2832
+ 'Pinned Availability Zone',
2760
2833
  'Host',
2761
2834
  'Properties',
2762
2835
  )
@@ -2791,6 +2864,12 @@ class ListServer(command.Lister):
2791
2864
  if c in ('Availability Zone', "availability_zone"):
2792
2865
  columns += ('availability_zone',)
2793
2866
  column_headers += ('Availability Zone',)
2867
+ if c in (
2868
+ 'pinned_availability_zone',
2869
+ "Pinned Availability Zone",
2870
+ ):
2871
+ columns += ('Pinned Availability Zone',)
2872
+ column_headers += ('Pinned Availability Zone',)
2794
2873
  if c in ('Host', "host"):
2795
2874
  columns += ('hypervisor_hostname',)
2796
2875
  column_headers += ('Host',)
@@ -2834,11 +2913,12 @@ class ListServer(command.Lister):
2834
2913
  # there are infra failures
2835
2914
  if parsed_args.name_lookup_one_by_one or image_id:
2836
2915
  for image_id in image_ids:
2837
- # "Image Name" is not crucial, so we swallow any exceptions
2838
2916
  try:
2839
2917
  images[image_id] = image_client.get_image(image_id)
2840
2918
  except Exception:
2841
- pass
2919
+ # retrieving image names is not crucial, so we swallow
2920
+ # any exceptions
2921
+ pass # nosec: B110
2842
2922
  else:
2843
2923
  try:
2844
2924
  # some deployments can have *loads* of images so we only
@@ -2857,33 +2937,37 @@ class ListServer(command.Lister):
2857
2937
  for i in images_list:
2858
2938
  images[i.id] = i
2859
2939
  except Exception:
2860
- pass
2940
+ # retrieving image names is not crucial, so we swallow any
2941
+ # exceptions
2942
+ pass # nosec: B110
2861
2943
 
2862
2944
  # create a dict that maps flavor_id to flavor object, which is used
2863
2945
  # to display the "Flavor Name" column. Note that 'flavor.id' is not
2864
2946
  # present on microversion 2.47 or later and 'flavor' won't be
2865
2947
  # present if there are infra failures
2866
2948
  if parsed_args.name_lookup_one_by_one or flavor_id:
2867
- for f_id in set(
2949
+ for f_id in {
2868
2950
  s.flavor['id']
2869
2951
  for s in data
2870
2952
  if s.flavor and s.flavor.get('id')
2871
- ):
2872
- # "Flavor Name" is not crucial, so we swallow any
2873
- # exceptions
2953
+ }:
2874
2954
  try:
2875
2955
  flavors[f_id] = compute_client.find_flavor(
2876
2956
  f_id, ignore_missing=False
2877
2957
  )
2878
2958
  except Exception:
2879
- pass
2959
+ # retrieving flavor names is not crucial, so we swallow
2960
+ # any exceptions
2961
+ pass # nosec: B110
2880
2962
  else:
2881
2963
  try:
2882
2964
  flavors_list = compute_client.flavors(is_public=None)
2883
2965
  for i in flavors_list:
2884
2966
  flavors[i.id] = i
2885
2967
  except Exception:
2886
- pass
2968
+ # retrieving flavor names is not crucial, so we swallow any
2969
+ # exceptions
2970
+ pass # nosec: B110
2887
2971
 
2888
2972
  # Populate image_name, image_id, flavor_name and flavor_id attributes
2889
2973
  # of server objects so that we can display those columns.
@@ -2974,7 +3058,7 @@ A non-admin user will not be able to execute actions."""
2974
3058
  )
2975
3059
 
2976
3060
  def get_parser(self, prog_name):
2977
- parser = super(LockServer, self).get_parser(prog_name)
3061
+ parser = super().get_parser(prog_name)
2978
3062
  parser.add_argument(
2979
3063
  'server',
2980
3064
  metavar='<server>',
@@ -3038,7 +3122,7 @@ revert to release the new server and restart the old one."""
3038
3122
  )
3039
3123
 
3040
3124
  def get_parser(self, prog_name):
3041
- parser = super(MigrateServer, self).get_parser(prog_name)
3125
+ parser = super().get_parser(prog_name)
3042
3126
  parser.add_argument(
3043
3127
  'server',
3044
3128
  metavar='<server>',
@@ -3117,11 +3201,10 @@ revert to release the new server and restart the old one."""
3117
3201
  self.app.stdout.write('\rProgress: %s' % progress)
3118
3202
  self.app.stdout.flush()
3119
3203
 
3120
- compute_client = self.app.client_manager.compute
3204
+ compute_client = self.app.client_manager.sdk_connection.compute
3121
3205
 
3122
- server = utils.find_resource(
3123
- compute_client.servers,
3124
- parsed_args.server,
3206
+ server = compute_client.find_server(
3207
+ parsed_args.server, ignore_missing=False
3125
3208
  )
3126
3209
 
3127
3210
  if parsed_args.live_migration:
@@ -3129,9 +3212,7 @@ revert to release the new server and restart the old one."""
3129
3212
 
3130
3213
  block_migration = parsed_args.block_migration
3131
3214
  if block_migration is None:
3132
- if compute_client.api_version < api_versions.APIVersion(
3133
- '2.25'
3134
- ):
3215
+ if not sdk_utils.supports_microversion(compute_client, '2.25'):
3135
3216
  block_migration = False
3136
3217
  else:
3137
3218
  block_migration = 'auto'
@@ -3144,10 +3225,8 @@ revert to release the new server and restart the old one."""
3144
3225
  # want to support, so if the user is using --live-migration
3145
3226
  # and --host, we want to enforce that they are using version
3146
3227
  # 2.30 or greater.
3147
- if (
3148
- parsed_args.host
3149
- and compute_client.api_version
3150
- < api_versions.APIVersion('2.30')
3228
+ if parsed_args.host and not sdk_utils.supports_microversion(
3229
+ compute_client, '2.30'
3151
3230
  ):
3152
3231
  raise exceptions.CommandError(
3153
3232
  '--os-compute-api-version 2.30 or greater is required '
@@ -3157,13 +3236,13 @@ revert to release the new server and restart the old one."""
3157
3236
  # The host parameter is required in the API even if None.
3158
3237
  kwargs['host'] = parsed_args.host
3159
3238
 
3160
- if compute_client.api_version < api_versions.APIVersion('2.25'):
3161
- kwargs['disk_over_commit'] = parsed_args.disk_overcommit
3239
+ if not sdk_utils.supports_microversion(compute_client, '2.25'):
3240
+ kwargs['disk_overcommit'] = parsed_args.disk_overcommit
3162
3241
  # We can't use an argparse default value because then we can't
3163
3242
  # distinguish between explicit 'False' and unset for the below
3164
3243
  # case (microversion >= 2.25)
3165
- if kwargs['disk_over_commit'] is None:
3166
- kwargs['disk_over_commit'] = False
3244
+ if kwargs['disk_overcommit'] is None:
3245
+ kwargs['disk_overcommit'] = False
3167
3246
  elif parsed_args.disk_overcommit is not None:
3168
3247
  # TODO(stephenfin): Raise an error here in OSC 7.0
3169
3248
  msg = _(
@@ -3174,7 +3253,7 @@ revert to release the new server and restart the old one."""
3174
3253
  )
3175
3254
  self.log.warning(msg)
3176
3255
 
3177
- server.live_migrate(**kwargs)
3256
+ compute_client.live_migrate_server(server, **kwargs)
3178
3257
  else: # cold migration
3179
3258
  if parsed_args.block_migration or parsed_args.disk_overcommit:
3180
3259
  raise exceptions.CommandError(
@@ -3183,9 +3262,7 @@ revert to release the new server and restart the old one."""
3183
3262
  "specified"
3184
3263
  )
3185
3264
  if parsed_args.host:
3186
- if compute_client.api_version < api_versions.APIVersion(
3187
- '2.56'
3188
- ):
3265
+ if not sdk_utils.supports_microversion(compute_client, '2.56'):
3189
3266
  msg = _(
3190
3267
  '--os-compute-api-version 2.56 or greater is '
3191
3268
  'required to use --host without --live-migration.'
@@ -3193,16 +3270,21 @@ revert to release the new server and restart the old one."""
3193
3270
  raise exceptions.CommandError(msg)
3194
3271
 
3195
3272
  kwargs = {'host': parsed_args.host} if parsed_args.host else {}
3196
- server.migrate(**kwargs)
3273
+ compute_client.migrate_server(server, **kwargs)
3197
3274
 
3198
3275
  if parsed_args.wait:
3199
3276
  if utils.wait_for_status(
3200
- compute_client.servers.get,
3277
+ compute_client.get_server,
3201
3278
  server.id,
3202
- success_status=['active', 'verify_resize'],
3279
+ success_status=('active', 'verify_resize'),
3203
3280
  callback=_show_progress,
3204
3281
  ):
3205
- self.app.stdout.write(_('Complete\n'))
3282
+ self.app.stdout.write(
3283
+ _(
3284
+ 'Complete, check success/failure by '
3285
+ 'openstack server migration/event list/show\n'
3286
+ )
3287
+ )
3206
3288
  else:
3207
3289
  msg = _('Error migrating server: %s') % server.id
3208
3290
  raise exceptions.CommandError(msg)
@@ -3212,7 +3294,7 @@ class PauseServer(command.Command):
3212
3294
  _description = _("Pause server(s)")
3213
3295
 
3214
3296
  def get_parser(self, prog_name):
3215
- parser = super(PauseServer, self).get_parser(prog_name)
3297
+ parser = super().get_parser(prog_name)
3216
3298
  parser.add_argument(
3217
3299
  'server',
3218
3300
  metavar='<server>',
@@ -3295,7 +3377,7 @@ class RebuildServer(command.ShowOne):
3295
3377
  _description = _("Rebuild server")
3296
3378
 
3297
3379
  def get_parser(self, prog_name):
3298
- parser = super(RebuildServer, self).get_parser(prog_name)
3380
+ parser = super().get_parser(prog_name)
3299
3381
  parser.add_argument(
3300
3382
  'server',
3301
3383
  metavar='<server>',
@@ -3476,11 +3558,11 @@ class RebuildServer(command.ShowOne):
3476
3558
  self.app.stdout.write('\rProgress: %s' % progress)
3477
3559
  self.app.stdout.flush()
3478
3560
 
3479
- compute_client = self.app.client_manager.compute
3561
+ compute_client = self.app.client_manager.sdk_connection.compute
3480
3562
  image_client = self.app.client_manager.image
3481
3563
 
3482
- server = utils.find_resource(
3483
- compute_client.servers, parsed_args.server
3564
+ server = compute_client.find_server(
3565
+ parsed_args.server, ignore_missing=False
3484
3566
  )
3485
3567
 
3486
3568
  # If parsed_args.image is not set and if the instance is image backed,
@@ -3492,7 +3574,7 @@ class RebuildServer(command.ShowOne):
3492
3574
  parsed_args.image, ignore_missing=False
3493
3575
  )
3494
3576
  else:
3495
- if not server.image:
3577
+ if not server.image or not server.image.id:
3496
3578
  msg = _(
3497
3579
  'The --image option is required when rebuilding a '
3498
3580
  'volume-backed server'
@@ -3505,14 +3587,17 @@ class RebuildServer(command.ShowOne):
3505
3587
  if parsed_args.name is not None:
3506
3588
  kwargs['name'] = parsed_args.name
3507
3589
 
3590
+ if parsed_args.password is not None:
3591
+ kwargs['admin_password'] = parsed_args.password
3592
+
3508
3593
  if parsed_args.preserve_ephemeral is not None:
3509
3594
  kwargs['preserve_ephemeral'] = parsed_args.preserve_ephemeral
3510
3595
 
3511
3596
  if parsed_args.properties:
3512
- kwargs['meta'] = parsed_args.properties
3597
+ kwargs['metadata'] = parsed_args.properties
3513
3598
 
3514
3599
  if parsed_args.description:
3515
- if compute_client.api_version < api_versions.APIVersion('2.19'):
3600
+ if not sdk_utils.supports_microversion(compute_client, '2.19'):
3516
3601
  msg = _(
3517
3602
  '--os-compute-api-version 2.19 or greater is required to '
3518
3603
  'support the --description option'
@@ -3522,7 +3607,7 @@ class RebuildServer(command.ShowOne):
3522
3607
  kwargs['description'] = parsed_args.description
3523
3608
 
3524
3609
  if parsed_args.key_name:
3525
- if compute_client.api_version < api_versions.APIVersion('2.54'):
3610
+ if not sdk_utils.supports_microversion(compute_client, '2.54'):
3526
3611
  msg = _(
3527
3612
  '--os-compute-api-version 2.54 or greater is required to '
3528
3613
  'support the --key-name option'
@@ -3531,7 +3616,7 @@ class RebuildServer(command.ShowOne):
3531
3616
 
3532
3617
  kwargs['key_name'] = parsed_args.key_name
3533
3618
  elif parsed_args.no_key_name:
3534
- if compute_client.api_version < api_versions.APIVersion('2.54'):
3619
+ if not sdk_utils.supports_microversion(compute_client, '2.54'):
3535
3620
  msg = _(
3536
3621
  '--os-compute-api-version 2.54 or greater is required to '
3537
3622
  'support the --no-key-name option'
@@ -3540,9 +3625,8 @@ class RebuildServer(command.ShowOne):
3540
3625
 
3541
3626
  kwargs['key_name'] = None
3542
3627
 
3543
- userdata = None
3544
3628
  if parsed_args.user_data:
3545
- if compute_client.api_version < api_versions.APIVersion('2.54'):
3629
+ if not sdk_utils.supports_microversion(compute_client, '2.54'):
3546
3630
  msg = _(
3547
3631
  '--os-compute-api-version 2.54 or greater is required to '
3548
3632
  'support the --user-data option'
@@ -3550,27 +3634,29 @@ class RebuildServer(command.ShowOne):
3550
3634
  raise exceptions.CommandError(msg)
3551
3635
 
3552
3636
  try:
3553
- userdata = io.open(parsed_args.user_data)
3554
- except IOError as e:
3637
+ with open(parsed_args.user_data, 'rb') as fh:
3638
+ # TODO(stephenfin): SDK should do this for us
3639
+ user_data = base64.b64encode(fh.read()).decode('utf-8')
3640
+ except OSError as e:
3555
3641
  msg = _("Can't open '%(data)s': %(exception)s")
3556
3642
  raise exceptions.CommandError(
3557
3643
  msg % {'data': parsed_args.user_data, 'exception': e}
3558
3644
  )
3559
3645
 
3560
- kwargs['userdata'] = userdata
3646
+ kwargs['user_data'] = user_data
3561
3647
  elif parsed_args.no_user_data:
3562
- if compute_client.api_version < api_versions.APIVersion('2.54'):
3648
+ if not sdk_utils.supports_microversion(compute_client, '2.54'):
3563
3649
  msg = _(
3564
3650
  '--os-compute-api-version 2.54 or greater is required to '
3565
3651
  'support the --no-user-data option'
3566
3652
  )
3567
3653
  raise exceptions.CommandError(msg)
3568
3654
 
3569
- kwargs['userdata'] = None
3655
+ kwargs['user_data'] = None
3570
3656
 
3571
3657
  # TODO(stephenfin): Handle OS_TRUSTED_IMAGE_CERTIFICATE_IDS
3572
3658
  if parsed_args.trusted_image_certs:
3573
- if compute_client.api_version < api_versions.APIVersion('2.63'):
3659
+ if not sdk_utils.supports_microversion(compute_client, '2.63'):
3574
3660
  msg = _(
3575
3661
  '--os-compute-api-version 2.63 or greater is required to '
3576
3662
  'support the --trusted-certs option'
@@ -3580,7 +3666,7 @@ class RebuildServer(command.ShowOne):
3580
3666
  certs = parsed_args.trusted_image_certs
3581
3667
  kwargs['trusted_image_certificates'] = certs
3582
3668
  elif parsed_args.no_trusted_image_certs:
3583
- if compute_client.api_version < api_versions.APIVersion('2.63'):
3669
+ if not sdk_utils.supports_microversion(compute_client, '2.63'):
3584
3670
  msg = _(
3585
3671
  '--os-compute-api-version 2.63 or greater is required to '
3586
3672
  'support the --no-trusted-certs option'
@@ -3590,7 +3676,7 @@ class RebuildServer(command.ShowOne):
3590
3676
  kwargs['trusted_image_certificates'] = None
3591
3677
 
3592
3678
  if parsed_args.hostname:
3593
- if compute_client.api_version < api_versions.APIVersion('2.90'):
3679
+ if not sdk_utils.supports_microversion(compute_client, '2.90'):
3594
3680
  msg = _(
3595
3681
  '--os-compute-api-version 2.90 or greater is required to '
3596
3682
  'support the --hostname option'
@@ -3599,9 +3685,8 @@ class RebuildServer(command.ShowOne):
3599
3685
 
3600
3686
  kwargs['hostname'] = parsed_args.hostname
3601
3687
 
3602
- v2_93 = api_versions.APIVersion('2.93')
3603
3688
  if parsed_args.reimage_boot_volume:
3604
- if compute_client.api_version < v2_93:
3689
+ if not sdk_utils.supports_microversion(compute_client, '2.93'):
3605
3690
  msg = _(
3606
3691
  '--os-compute-api-version 2.93 or greater is required to '
3607
3692
  'support the --reimage-boot-volume option'
@@ -3610,8 +3695,8 @@ class RebuildServer(command.ShowOne):
3610
3695
  else:
3611
3696
  # force user to explicitly request reimaging of volume-backed
3612
3697
  # server
3613
- if not server.image:
3614
- if compute_client.api_version >= v2_93:
3698
+ if not server.image or not server.image.id:
3699
+ if sdk_utils.supports_microversion(compute_client, '2.93'):
3615
3700
  msg = (
3616
3701
  '--reimage-boot-volume is required to rebuild a '
3617
3702
  'volume-backed server'
@@ -3643,15 +3728,11 @@ class RebuildServer(command.ShowOne):
3643
3728
  msg = _("The server status is not ACTIVE, SHUTOFF or ERROR.")
3644
3729
  raise exceptions.CommandError(msg)
3645
3730
 
3646
- try:
3647
- server = server.rebuild(image, parsed_args.password, **kwargs)
3648
- finally:
3649
- if userdata and hasattr(userdata, 'close'):
3650
- userdata.close()
3731
+ server = compute_client.rebuild_server(server, image, **kwargs)
3651
3732
 
3652
3733
  if parsed_args.wait:
3653
3734
  if utils.wait_for_status(
3654
- compute_client.servers.get,
3735
+ compute_client.get_server,
3655
3736
  server.id,
3656
3737
  callback=_show_progress,
3657
3738
  success_status=success_status,
@@ -3661,10 +3742,10 @@ class RebuildServer(command.ShowOne):
3661
3742
  msg = _('Error rebuilding server: %s') % server.id
3662
3743
  raise exceptions.CommandError(msg)
3663
3744
 
3664
- details = _prep_server_detail(
3745
+ data = _prep_server_detail(
3665
3746
  compute_client, image_client, server, refresh=False
3666
3747
  )
3667
- return zip(*sorted(details.items()))
3748
+ return zip(*sorted(data.items()))
3668
3749
 
3669
3750
 
3670
3751
  class EvacuateServer(command.ShowOne):
@@ -3686,13 +3767,12 @@ host."""
3686
3767
  )
3687
3768
 
3688
3769
  def get_parser(self, prog_name):
3689
- parser = super(EvacuateServer, self).get_parser(prog_name)
3770
+ parser = super().get_parser(prog_name)
3690
3771
  parser.add_argument(
3691
3772
  'server',
3692
3773
  metavar='<server>',
3693
3774
  help=_('Server (name or ID)'),
3694
3775
  )
3695
-
3696
3776
  parser.add_argument(
3697
3777
  '--wait',
3698
3778
  action='store_true',
@@ -3739,11 +3819,11 @@ host."""
3739
3819
  self.app.stdout.write('\rProgress: %s' % progress)
3740
3820
  self.app.stdout.flush()
3741
3821
 
3742
- compute_client = self.app.client_manager.compute
3822
+ compute_client = self.app.client_manager.sdk_connection.compute
3743
3823
  image_client = self.app.client_manager.image
3744
3824
 
3745
3825
  if parsed_args.host:
3746
- if compute_client.api_version < api_versions.APIVersion('2.29'):
3826
+ if not sdk_utils.supports_microversion(compute_client, '2.29'):
3747
3827
  msg = _(
3748
3828
  '--os-compute-api-version 2.29 or later is required '
3749
3829
  'to specify a preferred host.'
@@ -3751,7 +3831,7 @@ host."""
3751
3831
  raise exceptions.CommandError(msg)
3752
3832
 
3753
3833
  if parsed_args.shared_storage:
3754
- if compute_client.api_version > api_versions.APIVersion('2.13'):
3834
+ if sdk_utils.supports_microversion(compute_client, '2.14'):
3755
3835
  msg = _(
3756
3836
  '--os-compute-api-version 2.13 or earlier is required '
3757
3837
  'to specify shared-storage.'
@@ -3763,18 +3843,17 @@ host."""
3763
3843
  'password': parsed_args.password,
3764
3844
  }
3765
3845
 
3766
- if compute_client.api_version <= api_versions.APIVersion('2.13'):
3846
+ if not sdk_utils.supports_microversion(compute_client, '2.14'):
3767
3847
  kwargs['on_shared_storage'] = parsed_args.shared_storage
3768
3848
 
3769
- server = utils.find_resource(
3770
- compute_client.servers, parsed_args.server
3849
+ server = compute_client.find_server(
3850
+ parsed_args.server, ignore_missing=False
3771
3851
  )
3772
-
3773
- server.evacuate(**kwargs)
3852
+ compute_client.evacuate_server(server, **kwargs)
3774
3853
 
3775
3854
  if parsed_args.wait:
3776
3855
  if utils.wait_for_status(
3777
- compute_client.servers.get,
3856
+ compute_client.get_server,
3778
3857
  server.id,
3779
3858
  callback=_show_progress,
3780
3859
  ):
@@ -3783,17 +3862,15 @@ host."""
3783
3862
  msg = _('Error evacuating server: %s') % server.id
3784
3863
  raise exceptions.CommandError(msg)
3785
3864
 
3786
- details = _prep_server_detail(
3787
- compute_client, image_client, server, refresh=True
3788
- )
3789
- return zip(*sorted(details.items()))
3865
+ data = _prep_server_detail(compute_client, image_client, server)
3866
+ return zip(*sorted(data.items()))
3790
3867
 
3791
3868
 
3792
3869
  class RemoveFixedIP(command.Command):
3793
3870
  _description = _("Remove fixed IP address from server")
3794
3871
 
3795
3872
  def get_parser(self, prog_name):
3796
- parser = super(RemoveFixedIP, self).get_parser(prog_name)
3873
+ parser = super().get_parser(prog_name)
3797
3874
  parser.add_argument(
3798
3875
  "server",
3799
3876
  metavar="<server>",
@@ -3807,13 +3884,14 @@ class RemoveFixedIP(command.Command):
3807
3884
  return parser
3808
3885
 
3809
3886
  def take_action(self, parsed_args):
3810
- compute_client = self.app.client_manager.compute
3887
+ compute_client = self.app.client_manager.sdk_connection.compute
3811
3888
 
3812
- server = utils.find_resource(
3813
- compute_client.servers, parsed_args.server
3889
+ server = compute_client.find_server(
3890
+ parsed_args.server, ignore_missing=False
3891
+ )
3892
+ compute_client.remove_fixed_ip_from_server(
3893
+ server, parsed_args.ip_address
3814
3894
  )
3815
-
3816
- server.remove_fixed_ip(parsed_args.ip_address)
3817
3895
 
3818
3896
 
3819
3897
  class RemoveFloatingIP(network_common.NetworkAndComputeCommand):
@@ -3845,17 +3923,15 @@ class RemoveFloatingIP(network_common.NetworkAndComputeCommand):
3845
3923
  client.update_ip(obj, **attrs)
3846
3924
 
3847
3925
  def take_action_compute(self, client, parsed_args):
3848
- client.api.floating_ip_remove(
3849
- parsed_args.server,
3850
- parsed_args.ip_address,
3851
- )
3926
+ server = client.find_server(parsed_args.server, ignore_missing=False)
3927
+ client.remove_floating_ip_from_server(server, parsed_args.ip_address)
3852
3928
 
3853
3929
 
3854
3930
  class RemovePort(command.Command):
3855
3931
  _description = _("Remove port from server")
3856
3932
 
3857
3933
  def get_parser(self, prog_name):
3858
- parser = super(RemovePort, self).get_parser(prog_name)
3934
+ parser = super().get_parser(prog_name)
3859
3935
  parser.add_argument(
3860
3936
  "server",
3861
3937
  metavar="<server>",
@@ -3894,7 +3970,7 @@ class RemoveNetwork(command.Command):
3894
3970
  _description = _("Remove all ports of a network from server")
3895
3971
 
3896
3972
  def get_parser(self, prog_name):
3897
- parser = super(RemoveNetwork, self).get_parser(prog_name)
3973
+ parser = super().get_parser(prog_name)
3898
3974
  parser.add_argument(
3899
3975
  "server",
3900
3976
  metavar="<server>",
@@ -3934,32 +4010,38 @@ class RemoveServerSecurityGroup(command.Command):
3934
4010
  _description = _("Remove security group from server")
3935
4011
 
3936
4012
  def get_parser(self, prog_name):
3937
- parser = super(RemoveServerSecurityGroup, self).get_parser(prog_name)
4013
+ parser = super().get_parser(prog_name)
3938
4014
  parser.add_argument(
3939
4015
  'server',
3940
4016
  metavar='<server>',
3941
- help=_('Name or ID of server to use'),
4017
+ help=_('Server (name or ID)'),
3942
4018
  )
3943
4019
  parser.add_argument(
3944
4020
  'group',
3945
4021
  metavar='<group>',
3946
- help=_('Name or ID of security group to remove from server'),
4022
+ help=_('Security group to remove (name or ID)'),
3947
4023
  )
3948
4024
  return parser
3949
4025
 
3950
4026
  def take_action(self, parsed_args):
3951
- compute_client = self.app.client_manager.compute
4027
+ compute_client = self.app.client_manager.sdk_connection.compute
3952
4028
 
3953
- server = utils.find_resource(
3954
- compute_client.servers,
3955
- parsed_args.server,
4029
+ server = compute_client.find_server(
4030
+ parsed_args.server, ignore_missing=False
3956
4031
  )
3957
- security_group = compute_client.api.security_group_find(
3958
- parsed_args.group,
4032
+ if self.app.client_manager.is_network_endpoint_enabled():
4033
+ # the server handles both names and IDs for neutron SGs, so just
4034
+ # pass things through
4035
+ security_group = parsed_args.group
4036
+ else:
4037
+ # however, if using nova-network then it needs a name, not an ID
4038
+ security_group = compute_v2.find_security_group(
4039
+ compute_client, parsed_args.group
4040
+ )['name']
4041
+ compute_client.remove_security_group_from_server(
4042
+ server, security_group
3959
4043
  )
3960
4044
 
3961
- server.remove_security_group(security_group['id'])
3962
-
3963
4045
 
3964
4046
  class RemoveServerVolume(command.Command):
3965
4047
  _description = _(
@@ -3970,7 +4052,7 @@ volume from a server with status ``SHELVED`` or ``SHELVED_OFFLOADED``."""
3970
4052
  )
3971
4053
 
3972
4054
  def get_parser(self, prog_name):
3973
- parser = super(RemoveServerVolume, self).get_parser(prog_name)
4055
+ parser = super().get_parser(prog_name)
3974
4056
  parser.add_argument(
3975
4057
  'server',
3976
4058
  metavar='<server>',
@@ -4012,7 +4094,7 @@ server booted from a volume."""
4012
4094
  )
4013
4095
 
4014
4096
  def get_parser(self, prog_name):
4015
- parser = super(RescueServer, self).get_parser(prog_name)
4097
+ parser = super().get_parser(prog_name)
4016
4098
  parser.add_argument(
4017
4099
  'server',
4018
4100
  metavar='<server>',
@@ -4022,34 +4104,36 @@ server booted from a volume."""
4022
4104
  '--image',
4023
4105
  metavar='<image>',
4024
4106
  help=_(
4025
- 'Image (name or ID) to use for the rescue mode.'
4026
- ' Defaults to the currently used one.'
4107
+ 'Image (name or ID) to use for the rescue mode '
4108
+ '(defaults to the currently used one)'
4027
4109
  ),
4028
4110
  )
4029
4111
  parser.add_argument(
4030
4112
  '--password',
4031
4113
  metavar='<password>',
4032
4114
  help=_(
4033
- 'Set the password on the rescued instance. '
4034
- 'This option requires cloud support.'
4115
+ 'Set the password on the rescued instance '
4116
+ '(requires cloud support)'
4035
4117
  ),
4036
4118
  )
4037
4119
  return parser
4038
4120
 
4039
4121
  def take_action(self, parsed_args):
4040
- compute_client = self.app.client_manager.compute
4122
+ compute_client = self.app.client_manager.sdk_connection.compute
4041
4123
  image_client = self.app.client_manager.image
4042
4124
 
4043
- image = None
4125
+ image_ref = None
4044
4126
  if parsed_args.image:
4045
- image = image_client.find_image(
4127
+ image_ref = image_client.find_image(
4046
4128
  parsed_args.image, ignore_missing=False
4047
- )
4129
+ ).id
4048
4130
 
4049
- utils.find_resource(
4050
- compute_client.servers,
4051
- parsed_args.server,
4052
- ).rescue(image=image, password=parsed_args.password)
4131
+ server = compute_client.find_server(
4132
+ parsed_args.server, ignore_missing=False
4133
+ )
4134
+ compute_client.rescue_server(
4135
+ server, admin_pass=parsed_args.password, image_ref=image_ref
4136
+ )
4053
4137
 
4054
4138
 
4055
4139
  class ResizeServer(command.Command):
@@ -4064,13 +4148,13 @@ release the new server and restart the old one."""
4064
4148
  )
4065
4149
 
4066
4150
  def get_parser(self, prog_name):
4067
- parser = super(ResizeServer, self).get_parser(prog_name)
4068
- phase_group = parser.add_mutually_exclusive_group()
4151
+ parser = super().get_parser(prog_name)
4069
4152
  parser.add_argument(
4070
4153
  'server',
4071
4154
  metavar='<server>',
4072
4155
  help=_('Server (name or ID)'),
4073
4156
  )
4157
+ phase_group = parser.add_mutually_exclusive_group()
4074
4158
  phase_group.add_argument(
4075
4159
  '--flavor',
4076
4160
  metavar='<flavor>',
@@ -4107,16 +4191,11 @@ release the new server and restart the old one."""
4107
4191
  self.app.stdout.write('\rProgress: %s' % progress)
4108
4192
  self.app.stdout.flush()
4109
4193
 
4110
- compute_client = self.app.client_manager.compute
4111
- server = utils.find_resource(
4112
- compute_client.servers,
4113
- parsed_args.server,
4194
+ compute_client = self.app.client_manager.sdk_connection.compute
4195
+ server = compute_client.find_server(
4196
+ parsed_args.server, ignore_missing=False
4114
4197
  )
4115
4198
  if parsed_args.flavor:
4116
- flavor = utils.find_resource(
4117
- compute_client.flavors,
4118
- parsed_args.flavor,
4119
- )
4120
4199
  if not server.image:
4121
4200
  self.log.warning(
4122
4201
  _(
@@ -4124,18 +4203,21 @@ release the new server and restart the old one."""
4124
4203
  "while booting from a persistent volume."
4125
4204
  )
4126
4205
  )
4127
- compute_client.servers.resize(server, flavor)
4206
+ flavor = compute_client.find_flavor(
4207
+ parsed_args.flavor, ignore_missing=False
4208
+ )
4209
+ compute_client.resize_server(server, flavor)
4128
4210
  if parsed_args.wait:
4129
- if utils.wait_for_status(
4130
- compute_client.servers.get,
4211
+ if not utils.wait_for_status(
4212
+ compute_client.get_server,
4131
4213
  server.id,
4132
- success_status=['active', 'verify_resize'],
4214
+ success_status=('active', 'verify_resize'),
4133
4215
  callback=_show_progress,
4134
4216
  ):
4135
- self.app.stdout.write(_('Complete\n'))
4136
- else:
4137
4217
  msg = _('Error resizing server: %s') % server.id
4138
4218
  raise exceptions.CommandError(msg)
4219
+
4220
+ self.app.stdout.write(_('Complete\n'))
4139
4221
  elif parsed_args.confirm:
4140
4222
  self.log.warning(
4141
4223
  _(
@@ -4143,7 +4225,7 @@ release the new server and restart the old one."""
4143
4225
  "'openstack server resize confirm' command instead."
4144
4226
  )
4145
4227
  )
4146
- compute_client.servers.confirm_resize(server)
4228
+ compute_client.confirm_server_resize(server)
4147
4229
  elif parsed_args.revert:
4148
4230
  self.log.warning(
4149
4231
  _(
@@ -4151,7 +4233,7 @@ release the new server and restart the old one."""
4151
4233
  "'openstack server resize revert' command instead."
4152
4234
  )
4153
4235
  )
4154
- compute_client.servers.revert_resize(server)
4236
+ compute_client.revert_server_resize(server)
4155
4237
 
4156
4238
 
4157
4239
  class ResizeConfirm(command.Command):
@@ -4162,7 +4244,7 @@ Confirm (verify) success of resize operation and release the old server."""
4162
4244
  )
4163
4245
 
4164
4246
  def get_parser(self, prog_name):
4165
- parser = super(ResizeConfirm, self).get_parser(prog_name)
4247
+ parser = super().get_parser(prog_name)
4166
4248
  parser.add_argument(
4167
4249
  'server',
4168
4250
  metavar='<server>',
@@ -4171,12 +4253,11 @@ Confirm (verify) success of resize operation and release the old server."""
4171
4253
  return parser
4172
4254
 
4173
4255
  def take_action(self, parsed_args):
4174
- compute_client = self.app.client_manager.compute
4175
- server = utils.find_resource(
4176
- compute_client.servers,
4177
- parsed_args.server,
4256
+ compute_client = self.app.client_manager.sdk_connection.compute
4257
+ server = compute_client.find_server(
4258
+ parsed_args.server, ignore_missing=False
4178
4259
  )
4179
- server.confirm_resize()
4260
+ compute_client.confirm_server_resize(server)
4180
4261
 
4181
4262
 
4182
4263
  # TODO(stephenfin): Remove in OSC 7.0
@@ -4211,7 +4292,7 @@ one."""
4211
4292
  )
4212
4293
 
4213
4294
  def get_parser(self, prog_name):
4214
- parser = super(ResizeRevert, self).get_parser(prog_name)
4295
+ parser = super().get_parser(prog_name)
4215
4296
  parser.add_argument(
4216
4297
  'server',
4217
4298
  metavar='<server>',
@@ -4220,12 +4301,11 @@ one."""
4220
4301
  return parser
4221
4302
 
4222
4303
  def take_action(self, parsed_args):
4223
- compute_client = self.app.client_manager.compute
4224
- server = utils.find_resource(
4225
- compute_client.servers,
4226
- parsed_args.server,
4304
+ compute_client = self.app.client_manager.sdk_connection.compute
4305
+ server = compute_client.find_server(
4306
+ parsed_args.server, ignore_missing=False
4227
4307
  )
4228
- server.revert_resize()
4308
+ compute_client.revert_server_resize(server)
4229
4309
 
4230
4310
 
4231
4311
  # TODO(stephenfin): Remove in OSC 7.0
@@ -4255,7 +4335,7 @@ class RestoreServer(command.Command):
4255
4335
  _description = _("Restore server(s)")
4256
4336
 
4257
4337
  def get_parser(self, prog_name):
4258
- parser = super(RestoreServer, self).get_parser(prog_name)
4338
+ parser = super().get_parser(prog_name)
4259
4339
  parser.add_argument(
4260
4340
  'server',
4261
4341
  metavar='<server>',
@@ -4278,7 +4358,7 @@ class ResumeServer(command.Command):
4278
4358
  _description = _("Resume server(s)")
4279
4359
 
4280
4360
  def get_parser(self, prog_name):
4281
- parser = super(ResumeServer, self).get_parser(prog_name)
4361
+ parser = super().get_parser(prog_name)
4282
4362
  parser.add_argument(
4283
4363
  'server',
4284
4364
  metavar='<server>',
@@ -4301,7 +4381,7 @@ class SetServer(command.Command):
4301
4381
  _description = _("Set server properties")
4302
4382
 
4303
4383
  def get_parser(self, prog_name):
4304
- parser = super(SetServer, self).get_parser(prog_name)
4384
+ parser = super().get_parser(prog_name)
4305
4385
  parser.add_argument(
4306
4386
  'server',
4307
4387
  metavar='<server>',
@@ -4389,14 +4469,13 @@ class SetServer(command.Command):
4389
4469
  return parser
4390
4470
 
4391
4471
  def take_action(self, parsed_args):
4392
- compute_client = self.app.client_manager.compute
4393
- server = utils.find_resource(
4394
- compute_client.servers,
4395
- parsed_args.server,
4472
+ compute_client = self.app.client_manager.sdk_connection.compute
4473
+ server = compute_client.find_server(
4474
+ parsed_args.server, ignore_missing=False
4396
4475
  )
4397
4476
 
4398
4477
  if parsed_args.description:
4399
- if server.api_version < api_versions.APIVersion("2.19"):
4478
+ if not sdk_utils.supports_microversion(compute_client, '2.19'):
4400
4479
  msg = _(
4401
4480
  '--os-compute-api-version 2.19 or greater is required to '
4402
4481
  'support the --description option'
@@ -4404,7 +4483,7 @@ class SetServer(command.Command):
4404
4483
  raise exceptions.CommandError(msg)
4405
4484
 
4406
4485
  if parsed_args.tags:
4407
- if server.api_version < api_versions.APIVersion('2.26'):
4486
+ if not sdk_utils.supports_microversion(compute_client, '2.26'):
4408
4487
  msg = _(
4409
4488
  '--os-compute-api-version 2.26 or greater is required to '
4410
4489
  'support the --tag option'
@@ -4412,7 +4491,7 @@ class SetServer(command.Command):
4412
4491
  raise exceptions.CommandError(msg)
4413
4492
 
4414
4493
  if parsed_args.hostname:
4415
- if server.api_version < api_versions.APIVersion('2.90'):
4494
+ if not sdk_utils.supports_microversion(compute_client, '2.90'):
4416
4495
  msg = _(
4417
4496
  '--os-compute-api-version 2.90 or greater is required to '
4418
4497
  'support the --hostname option'
@@ -4431,30 +4510,32 @@ class SetServer(command.Command):
4431
4510
  update_kwargs['hostname'] = parsed_args.hostname
4432
4511
 
4433
4512
  if update_kwargs:
4434
- server.update(**update_kwargs)
4513
+ compute_client.update_server(server, **update_kwargs)
4435
4514
 
4436
4515
  if parsed_args.properties:
4437
- compute_client.servers.set_meta(server, parsed_args.properties)
4516
+ compute_client.set_server_metadata(
4517
+ server, **parsed_args.properties
4518
+ )
4438
4519
 
4439
4520
  if parsed_args.state:
4440
- server.reset_state(state=parsed_args.state)
4521
+ compute_client.reset_server_state(server, state=parsed_args.state)
4441
4522
 
4442
4523
  if parsed_args.root_password:
4443
4524
  p1 = getpass.getpass(_('New password: '))
4444
4525
  p2 = getpass.getpass(_('Retype new password: '))
4445
4526
  if p1 == p2:
4446
- server.change_password(p1)
4527
+ compute_client.change_server_password(server, p1)
4447
4528
  else:
4448
4529
  msg = _("Passwords do not match, password unchanged")
4449
4530
  raise exceptions.CommandError(msg)
4450
4531
  elif parsed_args.password:
4451
- server.change_password(parsed_args.password)
4532
+ compute_client.change_server_password(server, parsed_args.password)
4452
4533
  elif parsed_args.no_password:
4453
- server.clear_password()
4534
+ compute_client.clear_server_password(server)
4454
4535
 
4455
4536
  if parsed_args.tags:
4456
4537
  for tag in parsed_args.tags:
4457
- server.add_tag(tag=tag)
4538
+ compute_client.add_tag_to_server(server, tag=tag)
4458
4539
 
4459
4540
 
4460
4541
  class ShelveServer(command.Command):
@@ -4575,7 +4656,7 @@ information for the server."""
4575
4656
  )
4576
4657
 
4577
4658
  def get_parser(self, prog_name):
4578
- parser = super(ShowServer, self).get_parser(prog_name)
4659
+ parser = super().get_parser(prog_name)
4579
4660
  parser.add_argument(
4580
4661
  'server',
4581
4662
  metavar='<server>',
@@ -4602,12 +4683,13 @@ information for the server."""
4602
4683
 
4603
4684
  def take_action(self, parsed_args):
4604
4685
  compute_client = self.app.client_manager.sdk_connection.compute
4686
+ image_client = self.app.client_manager.image
4605
4687
 
4606
- # Find by name or ID, then get the full details of the server
4607
4688
  server = compute_client.find_server(
4608
- parsed_args.server, ignore_missing=False
4689
+ parsed_args.server,
4690
+ ignore_missing=False,
4691
+ details=True,
4609
4692
  )
4610
- server = compute_client.get_server(server)
4611
4693
 
4612
4694
  if parsed_args.diagnostics:
4613
4695
  data = compute_client.get_server_diagnostics(server)
@@ -4625,17 +4707,10 @@ information for the server."""
4625
4707
  topology = server.fetch_topology(compute_client)
4626
4708
 
4627
4709
  data = _prep_server_detail(
4628
- # TODO(dannosliwcd): Replace these clients with SDK clients after
4629
- # all callers of _prep_server_detail() are using the SDK.
4630
- self.app.client_manager.compute,
4631
- self.app.client_manager.image,
4632
- server,
4633
- refresh=False,
4710
+ compute_client, image_client, server, refresh=False
4634
4711
  )
4635
-
4636
4712
  if topology:
4637
4713
  data['topology'] = format_columns.DictColumn(topology)
4638
-
4639
4714
  return zip(*sorted(data.items()))
4640
4715
 
4641
4716
 
@@ -4643,7 +4718,7 @@ class SshServer(command.Command):
4643
4718
  _description = _("SSH to server")
4644
4719
 
4645
4720
  def get_parser(self, prog_name):
4646
- parser = super(SshServer, self).get_parser(prog_name)
4721
+ parser = super().get_parser(prog_name)
4647
4722
  parser.add_argument(
4648
4723
  'server',
4649
4724
  metavar='<server>',
@@ -4737,11 +4812,10 @@ class SshServer(command.Command):
4737
4812
  return parser
4738
4813
 
4739
4814
  def take_action(self, parsed_args):
4740
- compute_client = self.app.client_manager.compute
4815
+ compute_client = self.app.client_manager.sdk_connection.compute
4741
4816
 
4742
- server = utils.find_resource(
4743
- compute_client.servers,
4744
- parsed_args.server,
4817
+ server = compute_client.find_server(
4818
+ parsed_args.server, ignore_missing=False
4745
4819
  )
4746
4820
 
4747
4821
  # first, handle the deprecated options
@@ -4795,8 +4869,10 @@ class SshServer(command.Command):
4795
4869
  )
4796
4870
 
4797
4871
  cmd = ' '.join(['ssh', ip_address] + args)
4798
- LOG.debug("ssh command: {cmd}".format(cmd=cmd))
4799
- os.system(cmd)
4872
+ LOG.debug(f"ssh command: {cmd}")
4873
+ # we intentionally pass through user-provided arguments and run this in
4874
+ # the user's shell
4875
+ os.system(cmd) # nosec: B605
4800
4876
 
4801
4877
 
4802
4878
  class StartServer(command.Command):
@@ -4815,7 +4891,7 @@ class StartServer(command.Command):
4815
4891
  action='store_true',
4816
4892
  default=boolenv('ALL_PROJECTS'),
4817
4893
  help=_(
4818
- 'Start server(s) in another project by name (admin only)'
4894
+ 'Start server(s) in another project by name (admin only) '
4819
4895
  '(can be specified using the ALL_PROJECTS envvar)'
4820
4896
  ),
4821
4897
  )
@@ -4824,17 +4900,12 @@ class StartServer(command.Command):
4824
4900
  def take_action(self, parsed_args):
4825
4901
  compute_client = self.app.client_manager.sdk_connection.compute
4826
4902
  for server in parsed_args.server:
4827
- try:
4828
- server_id = compute_client.find_server(
4829
- server,
4830
- ignore_missing=False,
4831
- details=False,
4832
- all_projects=parsed_args.all_projects,
4833
- ).id
4834
- except sdk_exceptions.HttpException as exc:
4835
- if exc.status_code == 403:
4836
- msg = _("Policy doesn't allow passing all-projects")
4837
- raise exceptions.Forbidden(msg)
4903
+ server_id = compute_client.find_server(
4904
+ server,
4905
+ ignore_missing=False,
4906
+ details=False,
4907
+ all_projects=parsed_args.all_projects,
4908
+ ).id
4838
4909
 
4839
4910
  compute_client.start_server(server_id)
4840
4911
 
@@ -4864,18 +4935,12 @@ class StopServer(command.Command):
4864
4935
  def take_action(self, parsed_args):
4865
4936
  compute_client = self.app.client_manager.sdk_connection.compute
4866
4937
  for server in parsed_args.server:
4867
- try:
4868
- server_id = compute_client.find_server(
4869
- server,
4870
- ignore_missing=False,
4871
- details=False,
4872
- all_projects=parsed_args.all_projects,
4873
- ).id
4874
- except sdk_exceptions.HttpException as exc:
4875
- if exc.status_code == 403:
4876
- msg = _("Policy doesn't allow passing all-projects")
4877
- raise exceptions.Forbidden(msg)
4878
-
4938
+ server_id = compute_client.find_server(
4939
+ server,
4940
+ ignore_missing=False,
4941
+ details=False,
4942
+ all_projects=parsed_args.all_projects,
4943
+ ).id
4879
4944
  compute_client.stop_server(server_id)
4880
4945
 
4881
4946
 
@@ -4883,7 +4948,7 @@ class SuspendServer(command.Command):
4883
4948
  _description = _("Suspend server(s)")
4884
4949
 
4885
4950
  def get_parser(self, prog_name):
4886
- parser = super(SuspendServer, self).get_parser(prog_name)
4951
+ parser = super().get_parser(prog_name)
4887
4952
  parser.add_argument(
4888
4953
  'server',
4889
4954
  metavar='<server>',
@@ -4929,7 +4994,7 @@ class UnpauseServer(command.Command):
4929
4994
  _description = _("Unpause server(s)")
4930
4995
 
4931
4996
  def get_parser(self, prog_name):
4932
- parser = super(UnpauseServer, self).get_parser(prog_name)
4997
+ parser = super().get_parser(prog_name)
4933
4998
  parser.add_argument(
4934
4999
  'server',
4935
5000
  metavar='<server>',
@@ -4952,7 +5017,7 @@ class UnrescueServer(command.Command):
4952
5017
  _description = _("Restore server from rescue mode")
4953
5018
 
4954
5019
  def get_parser(self, prog_name):
4955
- parser = super(UnrescueServer, self).get_parser(prog_name)
5020
+ parser = super().get_parser(prog_name)
4956
5021
  parser.add_argument(
4957
5022
  'server',
4958
5023
  metavar='<server>',
@@ -4961,24 +5026,25 @@ class UnrescueServer(command.Command):
4961
5026
  return parser
4962
5027
 
4963
5028
  def take_action(self, parsed_args):
4964
- compute_client = self.app.client_manager.compute
4965
- utils.find_resource(
4966
- compute_client.servers,
4967
- parsed_args.server,
4968
- ).unrescue()
5029
+ compute_client = self.app.client_manager.sdk_connection.compute
5030
+ server = compute_client.find_server(
5031
+ parsed_args.server, ignore_missing=False
5032
+ )
5033
+ compute_client.unrescue_server(server)
4969
5034
 
4970
5035
 
4971
5036
  class UnsetServer(command.Command):
4972
5037
  _description = _("Unset server properties and tags")
4973
5038
 
4974
5039
  def get_parser(self, prog_name):
4975
- parser = super(UnsetServer, self).get_parser(prog_name)
5040
+ parser = super().get_parser(prog_name)
4976
5041
  parser.add_argument(
4977
5042
  'server',
4978
5043
  metavar='<server>',
4979
5044
  help=_('Server (name or ID)'),
4980
5045
  )
4981
- parser.add_argument(
5046
+ property_group = parser.add_mutually_exclusive_group()
5047
+ property_group.add_argument(
4982
5048
  '--property',
4983
5049
  metavar='<key>',
4984
5050
  action='append',
@@ -4989,16 +5055,22 @@ class UnsetServer(command.Command):
4989
5055
  '(repeat option to remove multiple values)'
4990
5056
  ),
4991
5057
  )
5058
+ property_group.add_argument(
5059
+ '--all-properties',
5060
+ action='store_true',
5061
+ help=_('Remove all properties'),
5062
+ )
4992
5063
  parser.add_argument(
4993
5064
  '--description',
4994
5065
  dest='description',
4995
5066
  action='store_true',
4996
5067
  help=_(
4997
- 'Unset server description (supported by '
4998
- '--os-compute-api-version 2.19 or above)'
5068
+ 'Unset server description '
5069
+ '(supported by --os-compute-api-version 2.19 or above)'
4999
5070
  ),
5000
5071
  )
5001
- parser.add_argument(
5072
+ tag_group = parser.add_mutually_exclusive_group()
5073
+ tag_group.add_argument(
5002
5074
  '--tag',
5003
5075
  metavar='<tag>',
5004
5076
  action='append',
@@ -5010,32 +5082,40 @@ class UnsetServer(command.Command):
5010
5082
  '(supported by --os-compute-api-version 2.26 or above)'
5011
5083
  ),
5012
5084
  )
5085
+ tag_group.add_argument(
5086
+ '--all-tags',
5087
+ action='store_true',
5088
+ help=_(
5089
+ 'Remove all tags '
5090
+ '(supported by --os-compute-api-version 2.26 or above)'
5091
+ ),
5092
+ )
5013
5093
  return parser
5014
5094
 
5015
5095
  def take_action(self, parsed_args):
5016
- compute_client = self.app.client_manager.compute
5017
- server = utils.find_resource(
5018
- compute_client.servers,
5019
- parsed_args.server,
5096
+ compute_client = self.app.client_manager.sdk_connection.compute
5097
+
5098
+ server = compute_client.find_server(
5099
+ parsed_args.server, ignore_missing=False
5020
5100
  )
5021
5101
 
5022
- if parsed_args.properties:
5023
- compute_client.servers.delete_meta(server, parsed_args.properties)
5102
+ if parsed_args.properties or parsed_args.all_properties:
5103
+ compute_client.delete_server_metadata(
5104
+ server, parsed_args.properties or None
5105
+ )
5024
5106
 
5025
5107
  if parsed_args.description:
5026
- if compute_client.api_version < api_versions.APIVersion("2.19"):
5108
+ if not sdk_utils.supports_microversion(compute_client, '2.19'):
5027
5109
  msg = _(
5028
- '--os-compute-api-version 2.19 or greater is '
5029
- 'required to support the --description option'
5110
+ '--os-compute-api-version 2.19 or greater is required to '
5111
+ 'support the --description option'
5030
5112
  )
5031
5113
  raise exceptions.CommandError(msg)
5032
- compute_client.servers.update(
5033
- server,
5034
- description="",
5035
- )
5036
5114
 
5037
- if parsed_args.tags:
5038
- if compute_client.api_version < api_versions.APIVersion('2.26'):
5115
+ compute_client.update_server(server, description="")
5116
+
5117
+ if parsed_args.tags or parsed_args.all_tags:
5118
+ if not sdk_utils.supports_microversion(compute_client, '2.26'):
5039
5119
  msg = _(
5040
5120
  '--os-compute-api-version 2.26 or greater is required to '
5041
5121
  'support the --tag option'
@@ -5043,7 +5123,10 @@ class UnsetServer(command.Command):
5043
5123
  raise exceptions.CommandError(msg)
5044
5124
 
5045
5125
  for tag in parsed_args.tags:
5046
- compute_client.servers.delete_tag(server, tag=tag)
5126
+ compute_client.remove_tag_from_server(server, tag)
5127
+
5128
+ if parsed_args.all_tags:
5129
+ compute_client.remove_tags_from_server(server)
5047
5130
 
5048
5131
 
5049
5132
  class UnshelveServer(command.Command):