python-openstackclient 6.6.0__py3-none-any.whl → 7.0.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 (337) hide show
  1. openstackclient/api/api.py +7 -8
  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 +16 -4
  7. openstackclient/common/configuration.py +1 -1
  8. openstackclient/common/extension.py +1 -1
  9. openstackclient/common/limits.py +66 -32
  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 +281 -410
  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 +9 -9
  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 +4 -3
  22. openstackclient/compute/v2/keypair.py +7 -8
  23. openstackclient/compute/v2/server.py +478 -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 +127 -45
  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/shell.py +4 -6
  107. openstackclient/tests/functional/base.py +1 -1
  108. openstackclient/tests/functional/common/test_extension.py +1 -1
  109. openstackclient/tests/functional/common/test_help.py +2 -2
  110. openstackclient/tests/functional/common/test_module.py +1 -1
  111. openstackclient/tests/functional/common/test_quota.py +43 -61
  112. openstackclient/tests/functional/compute/v2/common.py +2 -2
  113. openstackclient/tests/functional/compute/v2/test_flavor.py +2 -2
  114. openstackclient/tests/functional/compute/v2/test_keypair.py +1 -1
  115. openstackclient/tests/functional/compute/v2/test_server.py +5 -5
  116. openstackclient/tests/functional/compute/v2/test_server_event.py +1 -1
  117. openstackclient/tests/functional/identity/v2/common.py +3 -3
  118. openstackclient/tests/functional/identity/v3/common.py +14 -6
  119. openstackclient/tests/functional/identity/v3/test_application_credential.py +13 -19
  120. openstackclient/tests/functional/identity/v3/test_domain.py +1 -3
  121. openstackclient/tests/functional/identity/v3/test_endpoint.py +1 -1
  122. openstackclient/tests/functional/identity/v3/test_idp.py +1 -1
  123. openstackclient/tests/functional/identity/v3/test_limit.py +2 -2
  124. openstackclient/tests/functional/identity/v3/test_region.py +1 -3
  125. openstackclient/tests/functional/identity/v3/test_registered_limit.py +1 -1
  126. openstackclient/tests/functional/identity/v3/test_role.py +2 -2
  127. openstackclient/tests/functional/identity/v3/test_role_assignment.py +210 -0
  128. openstackclient/tests/functional/identity/v3/test_service.py +4 -6
  129. openstackclient/tests/functional/identity/v3/test_service_provider.py +1 -3
  130. openstackclient/tests/functional/image/base.py +1 -1
  131. openstackclient/tests/functional/image/v2/test_image.py +1 -1
  132. openstackclient/tests/functional/image/v2/test_info.py +1 -1
  133. openstackclient/tests/functional/network/v2/common.py +4 -6
  134. openstackclient/tests/functional/network/v2/test_network.py +5 -3
  135. openstackclient/tests/functional/network/v2/test_network_agent.py +7 -5
  136. openstackclient/tests/functional/network/v2/test_network_qos_rule.py +4 -4
  137. openstackclient/tests/functional/network/v2/test_port.py +11 -7
  138. openstackclient/tests/functional/network/v2/test_router.py +2 -2
  139. openstackclient/tests/functional/object/v1/common.py +1 -1
  140. openstackclient/tests/functional/object/v1/test_container.py +3 -3
  141. openstackclient/tests/functional/object/v1/test_object.py +9 -13
  142. openstackclient/tests/functional/volume/base.py +1 -1
  143. openstackclient/tests/functional/volume/v1/test_service.py +1 -1
  144. openstackclient/tests/functional/volume/v1/test_snapshot.py +2 -2
  145. openstackclient/tests/functional/volume/v1/test_transfer_request.py +2 -2
  146. openstackclient/tests/functional/volume/v1/test_volume_type.py +1 -1
  147. openstackclient/tests/functional/volume/v2/test_service.py +2 -2
  148. openstackclient/tests/functional/volume/v2/test_volume_backup.py +2 -2
  149. openstackclient/tests/functional/volume/v2/test_volume_snapshot.py +2 -2
  150. openstackclient/tests/functional/volume/v2/test_volume_type.py +1 -1
  151. openstackclient/tests/functional/volume/v3/test_volume_snapshot.py +2 -2
  152. openstackclient/tests/functional/volume/v3/test_volume_type.py +1 -1
  153. openstackclient/tests/unit/api/fakes.py +1 -1
  154. openstackclient/tests/unit/api/test_api.py +2 -2
  155. openstackclient/tests/unit/api/test_compute_v2.py +522 -707
  156. openstackclient/tests/unit/api/test_image_v1.py +1 -1
  157. openstackclient/tests/unit/api/test_image_v2.py +1 -1
  158. openstackclient/tests/unit/api/test_object_store_v1.py +4 -4
  159. openstackclient/tests/unit/common/test_limits.py +73 -35
  160. openstackclient/tests/unit/common/test_logs.py +2 -2
  161. openstackclient/tests/unit/common/test_module.py +4 -2
  162. openstackclient/tests/unit/common/test_project_cleanup.py +31 -6
  163. openstackclient/tests/unit/common/test_quota.py +490 -630
  164. openstackclient/tests/unit/compute/v2/fakes.py +37 -286
  165. openstackclient/tests/unit/compute/v2/test_agent.py +189 -147
  166. openstackclient/tests/unit/compute/v2/test_aggregate.py +18 -16
  167. openstackclient/tests/unit/compute/v2/test_console.py +4 -5
  168. openstackclient/tests/unit/compute/v2/test_flavor.py +59 -68
  169. openstackclient/tests/unit/compute/v2/test_host.py +83 -54
  170. openstackclient/tests/unit/compute/v2/test_hypervisor.py +28 -31
  171. openstackclient/tests/unit/compute/v2/test_hypervisor_stats.py +2 -2
  172. openstackclient/tests/unit/compute/v2/test_keypair.py +65 -50
  173. openstackclient/tests/unit/compute/v2/test_server.py +2895 -2459
  174. openstackclient/tests/unit/compute/v2/test_server_backup.py +1 -1
  175. openstackclient/tests/unit/compute/v2/test_server_event.py +14 -39
  176. openstackclient/tests/unit/compute/v2/test_server_group.py +28 -29
  177. openstackclient/tests/unit/compute/v2/test_server_migration.py +43 -68
  178. openstackclient/tests/unit/compute/v2/test_server_volume.py +17 -34
  179. openstackclient/tests/unit/compute/v2/test_service.py +34 -52
  180. openstackclient/tests/unit/compute/v2/test_usage.py +4 -4
  181. openstackclient/tests/unit/fakes.py +11 -11
  182. openstackclient/tests/unit/identity/v2_0/fakes.py +27 -10
  183. openstackclient/tests/unit/identity/v2_0/test_catalog.py +3 -3
  184. openstackclient/tests/unit/identity/v2_0/test_endpoint.py +7 -7
  185. openstackclient/tests/unit/identity/v2_0/test_project.py +8 -8
  186. openstackclient/tests/unit/identity/v2_0/test_role.py +10 -10
  187. openstackclient/tests/unit/identity/v2_0/test_role_assignment.py +4 -4
  188. openstackclient/tests/unit/identity/v2_0/test_service.py +6 -6
  189. openstackclient/tests/unit/identity/v2_0/test_token.py +4 -4
  190. openstackclient/tests/unit/identity/v2_0/test_user.py +8 -8
  191. openstackclient/tests/unit/identity/v3/fakes.py +59 -20
  192. openstackclient/tests/unit/identity/v3/test_access_rule.py +5 -5
  193. openstackclient/tests/unit/identity/v3/test_application_credential.py +212 -235
  194. openstackclient/tests/unit/identity/v3/test_catalog.py +3 -3
  195. openstackclient/tests/unit/identity/v3/test_consumer.py +7 -8
  196. openstackclient/tests/unit/identity/v3/test_credential.py +9 -9
  197. openstackclient/tests/unit/identity/v3/test_domain.py +8 -8
  198. openstackclient/tests/unit/identity/v3/test_endpoint.py +13 -13
  199. openstackclient/tests/unit/identity/v3/test_endpoint_group.py +12 -14
  200. openstackclient/tests/unit/identity/v3/test_group.py +12 -12
  201. openstackclient/tests/unit/identity/v3/test_identity_provider.py +8 -8
  202. openstackclient/tests/unit/identity/v3/test_implied_role.py +5 -5
  203. openstackclient/tests/unit/identity/v3/test_limit.py +7 -7
  204. openstackclient/tests/unit/identity/v3/test_mappings.py +7 -7
  205. openstackclient/tests/unit/identity/v3/test_oauth.py +5 -5
  206. openstackclient/tests/unit/identity/v3/test_project.py +16 -16
  207. openstackclient/tests/unit/identity/v3/test_protocol.py +7 -7
  208. openstackclient/tests/unit/identity/v3/test_region.py +7 -7
  209. openstackclient/tests/unit/identity/v3/test_registered_limit.py +12 -13
  210. openstackclient/tests/unit/identity/v3/test_role.py +13 -13
  211. openstackclient/tests/unit/identity/v3/test_role_assignment.py +410 -331
  212. openstackclient/tests/unit/identity/v3/test_service.py +93 -97
  213. openstackclient/tests/unit/identity/v3/test_service_provider.py +7 -7
  214. openstackclient/tests/unit/identity/v3/test_token.py +4 -4
  215. openstackclient/tests/unit/identity/v3/test_trust.py +9 -9
  216. openstackclient/tests/unit/identity/v3/test_unscoped_saml.py +4 -4
  217. openstackclient/tests/unit/identity/v3/test_user.py +299 -327
  218. openstackclient/tests/unit/image/v1/test_image.py +6 -6
  219. openstackclient/tests/unit/image/v2/fakes.py +46 -9
  220. openstackclient/tests/unit/image/v2/test_cache.py +2 -2
  221. openstackclient/tests/unit/image/v2/test_image.py +3 -3
  222. openstackclient/tests/unit/image/v2/test_metadef_objects.py +62 -0
  223. openstackclient/tests/unit/image/v2/test_metadef_resource_type_association.py +131 -0
  224. openstackclient/tests/unit/integ/base.py +1 -1
  225. openstackclient/tests/unit/integ/cli/test_project.py +4 -4
  226. openstackclient/tests/unit/integ/cli/test_shell.py +7 -7
  227. openstackclient/tests/unit/network/test_common.py +12 -21
  228. openstackclient/tests/unit/network/v2/fakes.py +64 -130
  229. openstackclient/tests/unit/network/v2/test_address_group.py +15 -15
  230. openstackclient/tests/unit/network/v2/test_address_scope.py +13 -13
  231. openstackclient/tests/unit/network/v2/test_default_security_group_rule.py +49 -27
  232. openstackclient/tests/unit/network/v2/test_floating_ip_compute.py +40 -38
  233. openstackclient/tests/unit/network/v2/test_floating_ip_network.py +15 -15
  234. openstackclient/tests/unit/network/v2/test_floating_ip_pool_compute.py +4 -7
  235. openstackclient/tests/unit/network/v2/test_floating_ip_pool_network.py +3 -5
  236. openstackclient/tests/unit/network/v2/test_floating_ip_port_forwarding.py +11 -11
  237. openstackclient/tests/unit/network/v2/test_ip_availability.py +6 -6
  238. openstackclient/tests/unit/network/v2/test_l3_conntrack_helper.py +11 -21
  239. openstackclient/tests/unit/network/v2/test_local_ip.py +7 -7
  240. openstackclient/tests/unit/network/v2/test_local_ip_association.py +3 -5
  241. openstackclient/tests/unit/network/v2/test_ndp_proxy.py +13 -13
  242. openstackclient/tests/unit/network/v2/test_network.py +23 -28
  243. openstackclient/tests/unit/network/v2/test_network_agent.py +17 -21
  244. openstackclient/tests/unit/network/v2/test_network_auto_allocated_topology.py +8 -8
  245. openstackclient/tests/unit/network/v2/test_network_compute.py +66 -65
  246. openstackclient/tests/unit/network/v2/test_network_flavor.py +17 -19
  247. openstackclient/tests/unit/network/v2/test_network_flavor_profile.py +13 -13
  248. openstackclient/tests/unit/network/v2/test_network_meter.py +11 -11
  249. openstackclient/tests/unit/network/v2/test_network_meter_rule.py +11 -11
  250. openstackclient/tests/unit/network/v2/test_network_qos_policy.py +11 -21
  251. openstackclient/tests/unit/network/v2/test_network_qos_rule.py +51 -77
  252. openstackclient/tests/unit/network/v2/test_network_qos_rule_type.py +5 -9
  253. openstackclient/tests/unit/network/v2/test_network_rbac.py +12 -12
  254. openstackclient/tests/unit/network/v2/test_network_segment.py +11 -15
  255. openstackclient/tests/unit/network/v2/test_network_segment_range.py +11 -13
  256. openstackclient/tests/unit/network/v2/test_network_service_provider.py +3 -5
  257. openstackclient/tests/unit/network/v2/test_network_trunk.py +11 -11
  258. openstackclient/tests/unit/network/v2/test_port.py +22 -25
  259. openstackclient/tests/unit/network/v2/test_router.py +721 -51
  260. openstackclient/tests/unit/network/v2/test_security_group_compute.py +65 -49
  261. openstackclient/tests/unit/network/v2/test_security_group_network.py +15 -15
  262. openstackclient/tests/unit/network/v2/test_security_group_rule_compute.py +57 -45
  263. openstackclient/tests/unit/network/v2/test_security_group_rule_network.py +11 -19
  264. openstackclient/tests/unit/network/v2/test_subnet.py +29 -25
  265. openstackclient/tests/unit/network/v2/test_subnet_pool.py +15 -15
  266. openstackclient/tests/unit/object/v1/fakes.py +1 -1
  267. openstackclient/tests/unit/object/v1/test_container.py +5 -5
  268. openstackclient/tests/unit/object/v1/test_container_all.py +6 -6
  269. openstackclient/tests/unit/object/v1/test_object.py +3 -3
  270. openstackclient/tests/unit/object/v1/test_object_all.py +5 -5
  271. openstackclient/tests/unit/test_shell.py +5 -5
  272. openstackclient/tests/unit/utils.py +4 -1
  273. openstackclient/tests/unit/volume/test_find_resource.py +2 -2
  274. openstackclient/tests/unit/volume/v1/fakes.py +5 -6
  275. openstackclient/tests/unit/volume/v1/test_volume.py +5 -4
  276. openstackclient/tests/unit/volume/v2/fakes.py +39 -259
  277. openstackclient/tests/unit/volume/v2/test_consistency_group_snapshot.py +5 -5
  278. openstackclient/tests/unit/volume/v2/test_qos_specs.py +9 -9
  279. openstackclient/tests/unit/volume/v2/test_volume.py +21 -87
  280. openstackclient/tests/unit/volume/v2/test_volume_backup.py +7 -368
  281. openstackclient/tests/unit/volume/v2/test_volume_snapshot.py +1 -1
  282. openstackclient/tests/unit/volume/v2/test_volume_transfer_request.py +0 -44
  283. openstackclient/tests/unit/volume/v2/test_volume_type.py +6 -87
  284. openstackclient/tests/unit/volume/v3/fakes.py +505 -22
  285. openstackclient/tests/unit/volume/v3/test_block_storage_cleanup.py +2 -3
  286. openstackclient/tests/unit/volume/v3/test_block_storage_cluster.py +10 -11
  287. openstackclient/tests/unit/volume/v3/test_block_storage_log_level.py +10 -6
  288. openstackclient/tests/unit/volume/v3/test_block_storage_manage.py +25 -17
  289. openstackclient/tests/unit/volume/v3/test_block_storage_resource_filter.py +6 -32
  290. openstackclient/tests/unit/volume/v3/test_service.py +271 -0
  291. openstackclient/tests/unit/volume/v3/test_volume.py +2177 -33
  292. openstackclient/tests/unit/volume/v3/test_volume_attachment.py +48 -52
  293. openstackclient/tests/unit/volume/v3/test_volume_backup.py +892 -0
  294. openstackclient/tests/unit/volume/v3/test_volume_group.py +19 -20
  295. openstackclient/tests/unit/volume/v3/test_volume_group_snapshot.py +14 -34
  296. openstackclient/tests/unit/volume/v3/test_volume_group_type.py +13 -16
  297. openstackclient/tests/unit/volume/v3/test_volume_message.py +10 -11
  298. openstackclient/tests/unit/volume/v3/test_volume_snapshot.py +161 -0
  299. openstackclient/tests/unit/volume/v3/test_volume_transfer_request.py +425 -0
  300. openstackclient/tests/unit/volume/v3/test_volume_type.py +1109 -0
  301. openstackclient/volume/v1/qos_specs.py +7 -7
  302. openstackclient/volume/v1/service.py +2 -2
  303. openstackclient/volume/v1/volume.py +12 -12
  304. openstackclient/volume/v1/volume_backup.py +7 -7
  305. openstackclient/volume/v1/volume_snapshot.py +8 -8
  306. openstackclient/volume/v1/volume_transfer_request.py +5 -5
  307. openstackclient/volume/v1/volume_type.py +7 -7
  308. openstackclient/volume/v2/backup_record.py +2 -2
  309. openstackclient/volume/v2/consistency_group.py +7 -9
  310. openstackclient/volume/v2/consistency_group_snapshot.py +4 -12
  311. openstackclient/volume/v2/qos_specs.py +7 -7
  312. openstackclient/volume/v2/service.py +2 -2
  313. openstackclient/volume/v2/volume.py +80 -80
  314. openstackclient/volume/v2/volume_backend.py +2 -2
  315. openstackclient/volume/v2/volume_backup.py +7 -217
  316. openstackclient/volume/v2/volume_host.py +2 -2
  317. openstackclient/volume/v2/volume_snapshot.py +8 -8
  318. openstackclient/volume/v2/volume_transfer_request.py +5 -37
  319. openstackclient/volume/v2/volume_type.py +7 -89
  320. openstackclient/volume/v3/service.py +56 -0
  321. openstackclient/volume/v3/volume.py +971 -0
  322. openstackclient/volume/v3/volume_attachment.py +31 -29
  323. openstackclient/volume/v3/volume_backup.py +670 -0
  324. openstackclient/volume/v3/volume_message.py +1 -1
  325. openstackclient/volume/v3/volume_snapshot.py +97 -0
  326. openstackclient/volume/v3/volume_transfer_request.py +233 -0
  327. openstackclient/volume/v3/volume_type.py +967 -0
  328. {python_openstackclient-6.6.0.dist-info → python_openstackclient-7.0.0.dist-info}/AUTHORS +4 -0
  329. {python_openstackclient-6.6.0.dist-info → python_openstackclient-7.0.0.dist-info}/METADATA +3 -3
  330. python_openstackclient-7.0.0.dist-info/RECORD +502 -0
  331. {python_openstackclient-6.6.0.dist-info → python_openstackclient-7.0.0.dist-info}/entry_points.txt +33 -27
  332. python_openstackclient-7.0.0.dist-info/pbr.json +1 -0
  333. python_openstackclient-6.6.0.dist-info/RECORD +0 -489
  334. python_openstackclient-6.6.0.dist-info/pbr.json +0 -1
  335. {python_openstackclient-6.6.0.dist-info → python_openstackclient-7.0.0.dist-info}/LICENSE +0 -0
  336. {python_openstackclient-6.6.0.dist-info → python_openstackclient-7.0.0.dist-info}/WHEEL +0 -0
  337. {python_openstackclient-6.6.0.dist-info → python_openstackclient-7.0.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'
@@ -3509,10 +3591,10 @@ class RebuildServer(command.ShowOne):
3509
3591
  kwargs['preserve_ephemeral'] = parsed_args.preserve_ephemeral
3510
3592
 
3511
3593
  if parsed_args.properties:
3512
- kwargs['meta'] = parsed_args.properties
3594
+ kwargs['metadata'] = parsed_args.properties
3513
3595
 
3514
3596
  if parsed_args.description:
3515
- if compute_client.api_version < api_versions.APIVersion('2.19'):
3597
+ if not sdk_utils.supports_microversion(compute_client, '2.19'):
3516
3598
  msg = _(
3517
3599
  '--os-compute-api-version 2.19 or greater is required to '
3518
3600
  'support the --description option'
@@ -3522,7 +3604,7 @@ class RebuildServer(command.ShowOne):
3522
3604
  kwargs['description'] = parsed_args.description
3523
3605
 
3524
3606
  if parsed_args.key_name:
3525
- if compute_client.api_version < api_versions.APIVersion('2.54'):
3607
+ if not sdk_utils.supports_microversion(compute_client, '2.54'):
3526
3608
  msg = _(
3527
3609
  '--os-compute-api-version 2.54 or greater is required to '
3528
3610
  'support the --key-name option'
@@ -3531,7 +3613,7 @@ class RebuildServer(command.ShowOne):
3531
3613
 
3532
3614
  kwargs['key_name'] = parsed_args.key_name
3533
3615
  elif parsed_args.no_key_name:
3534
- if compute_client.api_version < api_versions.APIVersion('2.54'):
3616
+ if not sdk_utils.supports_microversion(compute_client, '2.54'):
3535
3617
  msg = _(
3536
3618
  '--os-compute-api-version 2.54 or greater is required to '
3537
3619
  'support the --no-key-name option'
@@ -3540,9 +3622,8 @@ class RebuildServer(command.ShowOne):
3540
3622
 
3541
3623
  kwargs['key_name'] = None
3542
3624
 
3543
- userdata = None
3544
3625
  if parsed_args.user_data:
3545
- if compute_client.api_version < api_versions.APIVersion('2.54'):
3626
+ if not sdk_utils.supports_microversion(compute_client, '2.54'):
3546
3627
  msg = _(
3547
3628
  '--os-compute-api-version 2.54 or greater is required to '
3548
3629
  'support the --user-data option'
@@ -3550,27 +3631,29 @@ class RebuildServer(command.ShowOne):
3550
3631
  raise exceptions.CommandError(msg)
3551
3632
 
3552
3633
  try:
3553
- userdata = io.open(parsed_args.user_data)
3554
- except IOError as e:
3634
+ with open(parsed_args.user_data, 'rb') as fh:
3635
+ # TODO(stephenfin): SDK should do this for us
3636
+ user_data = base64.b64encode(fh.read()).decode('utf-8')
3637
+ except OSError as e:
3555
3638
  msg = _("Can't open '%(data)s': %(exception)s")
3556
3639
  raise exceptions.CommandError(
3557
3640
  msg % {'data': parsed_args.user_data, 'exception': e}
3558
3641
  )
3559
3642
 
3560
- kwargs['userdata'] = userdata
3643
+ kwargs['user_data'] = user_data
3561
3644
  elif parsed_args.no_user_data:
3562
- if compute_client.api_version < api_versions.APIVersion('2.54'):
3645
+ if not sdk_utils.supports_microversion(compute_client, '2.54'):
3563
3646
  msg = _(
3564
3647
  '--os-compute-api-version 2.54 or greater is required to '
3565
3648
  'support the --no-user-data option'
3566
3649
  )
3567
3650
  raise exceptions.CommandError(msg)
3568
3651
 
3569
- kwargs['userdata'] = None
3652
+ kwargs['user_data'] = None
3570
3653
 
3571
3654
  # TODO(stephenfin): Handle OS_TRUSTED_IMAGE_CERTIFICATE_IDS
3572
3655
  if parsed_args.trusted_image_certs:
3573
- if compute_client.api_version < api_versions.APIVersion('2.63'):
3656
+ if not sdk_utils.supports_microversion(compute_client, '2.63'):
3574
3657
  msg = _(
3575
3658
  '--os-compute-api-version 2.63 or greater is required to '
3576
3659
  'support the --trusted-certs option'
@@ -3580,7 +3663,7 @@ class RebuildServer(command.ShowOne):
3580
3663
  certs = parsed_args.trusted_image_certs
3581
3664
  kwargs['trusted_image_certificates'] = certs
3582
3665
  elif parsed_args.no_trusted_image_certs:
3583
- if compute_client.api_version < api_versions.APIVersion('2.63'):
3666
+ if not sdk_utils.supports_microversion(compute_client, '2.63'):
3584
3667
  msg = _(
3585
3668
  '--os-compute-api-version 2.63 or greater is required to '
3586
3669
  'support the --no-trusted-certs option'
@@ -3590,7 +3673,7 @@ class RebuildServer(command.ShowOne):
3590
3673
  kwargs['trusted_image_certificates'] = None
3591
3674
 
3592
3675
  if parsed_args.hostname:
3593
- if compute_client.api_version < api_versions.APIVersion('2.90'):
3676
+ if not sdk_utils.supports_microversion(compute_client, '2.90'):
3594
3677
  msg = _(
3595
3678
  '--os-compute-api-version 2.90 or greater is required to '
3596
3679
  'support the --hostname option'
@@ -3599,9 +3682,8 @@ class RebuildServer(command.ShowOne):
3599
3682
 
3600
3683
  kwargs['hostname'] = parsed_args.hostname
3601
3684
 
3602
- v2_93 = api_versions.APIVersion('2.93')
3603
3685
  if parsed_args.reimage_boot_volume:
3604
- if compute_client.api_version < v2_93:
3686
+ if not sdk_utils.supports_microversion(compute_client, '2.93'):
3605
3687
  msg = _(
3606
3688
  '--os-compute-api-version 2.93 or greater is required to '
3607
3689
  'support the --reimage-boot-volume option'
@@ -3610,8 +3692,8 @@ class RebuildServer(command.ShowOne):
3610
3692
  else:
3611
3693
  # force user to explicitly request reimaging of volume-backed
3612
3694
  # server
3613
- if not server.image:
3614
- if compute_client.api_version >= v2_93:
3695
+ if not server.image or not server.image.id:
3696
+ if sdk_utils.supports_microversion(compute_client, '2.93'):
3615
3697
  msg = (
3616
3698
  '--reimage-boot-volume is required to rebuild a '
3617
3699
  'volume-backed server'
@@ -3643,15 +3725,13 @@ class RebuildServer(command.ShowOne):
3643
3725
  msg = _("The server status is not ACTIVE, SHUTOFF or ERROR.")
3644
3726
  raise exceptions.CommandError(msg)
3645
3727
 
3646
- try:
3647
- server = server.rebuild(image, parsed_args.password, **kwargs)
3648
- finally:
3649
- if userdata and hasattr(userdata, 'close'):
3650
- userdata.close()
3728
+ server = compute_client.rebuild_server(
3729
+ server, image, admin_password=parsed_args.password, **kwargs
3730
+ )
3651
3731
 
3652
3732
  if parsed_args.wait:
3653
3733
  if utils.wait_for_status(
3654
- compute_client.servers.get,
3734
+ compute_client.get_server,
3655
3735
  server.id,
3656
3736
  callback=_show_progress,
3657
3737
  success_status=success_status,
@@ -3661,10 +3741,10 @@ class RebuildServer(command.ShowOne):
3661
3741
  msg = _('Error rebuilding server: %s') % server.id
3662
3742
  raise exceptions.CommandError(msg)
3663
3743
 
3664
- details = _prep_server_detail(
3744
+ data = _prep_server_detail(
3665
3745
  compute_client, image_client, server, refresh=False
3666
3746
  )
3667
- return zip(*sorted(details.items()))
3747
+ return zip(*sorted(data.items()))
3668
3748
 
3669
3749
 
3670
3750
  class EvacuateServer(command.ShowOne):
@@ -3686,13 +3766,12 @@ host."""
3686
3766
  )
3687
3767
 
3688
3768
  def get_parser(self, prog_name):
3689
- parser = super(EvacuateServer, self).get_parser(prog_name)
3769
+ parser = super().get_parser(prog_name)
3690
3770
  parser.add_argument(
3691
3771
  'server',
3692
3772
  metavar='<server>',
3693
3773
  help=_('Server (name or ID)'),
3694
3774
  )
3695
-
3696
3775
  parser.add_argument(
3697
3776
  '--wait',
3698
3777
  action='store_true',
@@ -3739,11 +3818,11 @@ host."""
3739
3818
  self.app.stdout.write('\rProgress: %s' % progress)
3740
3819
  self.app.stdout.flush()
3741
3820
 
3742
- compute_client = self.app.client_manager.compute
3821
+ compute_client = self.app.client_manager.sdk_connection.compute
3743
3822
  image_client = self.app.client_manager.image
3744
3823
 
3745
3824
  if parsed_args.host:
3746
- if compute_client.api_version < api_versions.APIVersion('2.29'):
3825
+ if not sdk_utils.supports_microversion(compute_client, '2.29'):
3747
3826
  msg = _(
3748
3827
  '--os-compute-api-version 2.29 or later is required '
3749
3828
  'to specify a preferred host.'
@@ -3751,7 +3830,7 @@ host."""
3751
3830
  raise exceptions.CommandError(msg)
3752
3831
 
3753
3832
  if parsed_args.shared_storage:
3754
- if compute_client.api_version > api_versions.APIVersion('2.13'):
3833
+ if sdk_utils.supports_microversion(compute_client, '2.14'):
3755
3834
  msg = _(
3756
3835
  '--os-compute-api-version 2.13 or earlier is required '
3757
3836
  'to specify shared-storage.'
@@ -3763,18 +3842,17 @@ host."""
3763
3842
  'password': parsed_args.password,
3764
3843
  }
3765
3844
 
3766
- if compute_client.api_version <= api_versions.APIVersion('2.13'):
3845
+ if not sdk_utils.supports_microversion(compute_client, '2.14'):
3767
3846
  kwargs['on_shared_storage'] = parsed_args.shared_storage
3768
3847
 
3769
- server = utils.find_resource(
3770
- compute_client.servers, parsed_args.server
3848
+ server = compute_client.find_server(
3849
+ parsed_args.server, ignore_missing=False
3771
3850
  )
3772
-
3773
- server.evacuate(**kwargs)
3851
+ compute_client.evacuate_server(server, **kwargs)
3774
3852
 
3775
3853
  if parsed_args.wait:
3776
3854
  if utils.wait_for_status(
3777
- compute_client.servers.get,
3855
+ compute_client.get_server,
3778
3856
  server.id,
3779
3857
  callback=_show_progress,
3780
3858
  ):
@@ -3783,17 +3861,15 @@ host."""
3783
3861
  msg = _('Error evacuating server: %s') % server.id
3784
3862
  raise exceptions.CommandError(msg)
3785
3863
 
3786
- details = _prep_server_detail(
3787
- compute_client, image_client, server, refresh=True
3788
- )
3789
- return zip(*sorted(details.items()))
3864
+ data = _prep_server_detail(compute_client, image_client, server)
3865
+ return zip(*sorted(data.items()))
3790
3866
 
3791
3867
 
3792
3868
  class RemoveFixedIP(command.Command):
3793
3869
  _description = _("Remove fixed IP address from server")
3794
3870
 
3795
3871
  def get_parser(self, prog_name):
3796
- parser = super(RemoveFixedIP, self).get_parser(prog_name)
3872
+ parser = super().get_parser(prog_name)
3797
3873
  parser.add_argument(
3798
3874
  "server",
3799
3875
  metavar="<server>",
@@ -3807,13 +3883,14 @@ class RemoveFixedIP(command.Command):
3807
3883
  return parser
3808
3884
 
3809
3885
  def take_action(self, parsed_args):
3810
- compute_client = self.app.client_manager.compute
3886
+ compute_client = self.app.client_manager.sdk_connection.compute
3811
3887
 
3812
- server = utils.find_resource(
3813
- compute_client.servers, parsed_args.server
3888
+ server = compute_client.find_server(
3889
+ parsed_args.server, ignore_missing=False
3890
+ )
3891
+ compute_client.remove_fixed_ip_from_server(
3892
+ server, parsed_args.ip_address
3814
3893
  )
3815
-
3816
- server.remove_fixed_ip(parsed_args.ip_address)
3817
3894
 
3818
3895
 
3819
3896
  class RemoveFloatingIP(network_common.NetworkAndComputeCommand):
@@ -3845,17 +3922,15 @@ class RemoveFloatingIP(network_common.NetworkAndComputeCommand):
3845
3922
  client.update_ip(obj, **attrs)
3846
3923
 
3847
3924
  def take_action_compute(self, client, parsed_args):
3848
- client.api.floating_ip_remove(
3849
- parsed_args.server,
3850
- parsed_args.ip_address,
3851
- )
3925
+ server = client.find_server(parsed_args.server, ignore_missing=False)
3926
+ client.remove_floating_ip_from_server(server, parsed_args.ip_address)
3852
3927
 
3853
3928
 
3854
3929
  class RemovePort(command.Command):
3855
3930
  _description = _("Remove port from server")
3856
3931
 
3857
3932
  def get_parser(self, prog_name):
3858
- parser = super(RemovePort, self).get_parser(prog_name)
3933
+ parser = super().get_parser(prog_name)
3859
3934
  parser.add_argument(
3860
3935
  "server",
3861
3936
  metavar="<server>",
@@ -3894,7 +3969,7 @@ class RemoveNetwork(command.Command):
3894
3969
  _description = _("Remove all ports of a network from server")
3895
3970
 
3896
3971
  def get_parser(self, prog_name):
3897
- parser = super(RemoveNetwork, self).get_parser(prog_name)
3972
+ parser = super().get_parser(prog_name)
3898
3973
  parser.add_argument(
3899
3974
  "server",
3900
3975
  metavar="<server>",
@@ -3934,32 +4009,38 @@ class RemoveServerSecurityGroup(command.Command):
3934
4009
  _description = _("Remove security group from server")
3935
4010
 
3936
4011
  def get_parser(self, prog_name):
3937
- parser = super(RemoveServerSecurityGroup, self).get_parser(prog_name)
4012
+ parser = super().get_parser(prog_name)
3938
4013
  parser.add_argument(
3939
4014
  'server',
3940
4015
  metavar='<server>',
3941
- help=_('Name or ID of server to use'),
4016
+ help=_('Server (name or ID)'),
3942
4017
  )
3943
4018
  parser.add_argument(
3944
4019
  'group',
3945
4020
  metavar='<group>',
3946
- help=_('Name or ID of security group to remove from server'),
4021
+ help=_('Security group to remove (name or ID)'),
3947
4022
  )
3948
4023
  return parser
3949
4024
 
3950
4025
  def take_action(self, parsed_args):
3951
- compute_client = self.app.client_manager.compute
4026
+ compute_client = self.app.client_manager.sdk_connection.compute
3952
4027
 
3953
- server = utils.find_resource(
3954
- compute_client.servers,
3955
- parsed_args.server,
4028
+ server = compute_client.find_server(
4029
+ parsed_args.server, ignore_missing=False
3956
4030
  )
3957
- security_group = compute_client.api.security_group_find(
3958
- parsed_args.group,
4031
+ if self.app.client_manager.is_network_endpoint_enabled():
4032
+ # the server handles both names and IDs for neutron SGs, so just
4033
+ # pass things through
4034
+ security_group = parsed_args.group
4035
+ else:
4036
+ # however, if using nova-network then it needs a name, not an ID
4037
+ security_group = compute_v2.find_security_group(
4038
+ compute_client, parsed_args.group
4039
+ )['name']
4040
+ compute_client.remove_security_group_from_server(
4041
+ server, security_group
3959
4042
  )
3960
4043
 
3961
- server.remove_security_group(security_group['id'])
3962
-
3963
4044
 
3964
4045
  class RemoveServerVolume(command.Command):
3965
4046
  _description = _(
@@ -3970,7 +4051,7 @@ volume from a server with status ``SHELVED`` or ``SHELVED_OFFLOADED``."""
3970
4051
  )
3971
4052
 
3972
4053
  def get_parser(self, prog_name):
3973
- parser = super(RemoveServerVolume, self).get_parser(prog_name)
4054
+ parser = super().get_parser(prog_name)
3974
4055
  parser.add_argument(
3975
4056
  'server',
3976
4057
  metavar='<server>',
@@ -4012,7 +4093,7 @@ server booted from a volume."""
4012
4093
  )
4013
4094
 
4014
4095
  def get_parser(self, prog_name):
4015
- parser = super(RescueServer, self).get_parser(prog_name)
4096
+ parser = super().get_parser(prog_name)
4016
4097
  parser.add_argument(
4017
4098
  'server',
4018
4099
  metavar='<server>',
@@ -4022,34 +4103,36 @@ server booted from a volume."""
4022
4103
  '--image',
4023
4104
  metavar='<image>',
4024
4105
  help=_(
4025
- 'Image (name or ID) to use for the rescue mode.'
4026
- ' Defaults to the currently used one.'
4106
+ 'Image (name or ID) to use for the rescue mode '
4107
+ '(defaults to the currently used one)'
4027
4108
  ),
4028
4109
  )
4029
4110
  parser.add_argument(
4030
4111
  '--password',
4031
4112
  metavar='<password>',
4032
4113
  help=_(
4033
- 'Set the password on the rescued instance. '
4034
- 'This option requires cloud support.'
4114
+ 'Set the password on the rescued instance '
4115
+ '(requires cloud support)'
4035
4116
  ),
4036
4117
  )
4037
4118
  return parser
4038
4119
 
4039
4120
  def take_action(self, parsed_args):
4040
- compute_client = self.app.client_manager.compute
4121
+ compute_client = self.app.client_manager.sdk_connection.compute
4041
4122
  image_client = self.app.client_manager.image
4042
4123
 
4043
- image = None
4124
+ image_ref = None
4044
4125
  if parsed_args.image:
4045
- image = image_client.find_image(
4126
+ image_ref = image_client.find_image(
4046
4127
  parsed_args.image, ignore_missing=False
4047
- )
4128
+ ).id
4048
4129
 
4049
- utils.find_resource(
4050
- compute_client.servers,
4051
- parsed_args.server,
4052
- ).rescue(image=image, password=parsed_args.password)
4130
+ server = compute_client.find_server(
4131
+ parsed_args.server, ignore_missing=False
4132
+ )
4133
+ compute_client.rescue_server(
4134
+ server, admin_pass=parsed_args.password, image_ref=image_ref
4135
+ )
4053
4136
 
4054
4137
 
4055
4138
  class ResizeServer(command.Command):
@@ -4064,13 +4147,13 @@ release the new server and restart the old one."""
4064
4147
  )
4065
4148
 
4066
4149
  def get_parser(self, prog_name):
4067
- parser = super(ResizeServer, self).get_parser(prog_name)
4068
- phase_group = parser.add_mutually_exclusive_group()
4150
+ parser = super().get_parser(prog_name)
4069
4151
  parser.add_argument(
4070
4152
  'server',
4071
4153
  metavar='<server>',
4072
4154
  help=_('Server (name or ID)'),
4073
4155
  )
4156
+ phase_group = parser.add_mutually_exclusive_group()
4074
4157
  phase_group.add_argument(
4075
4158
  '--flavor',
4076
4159
  metavar='<flavor>',
@@ -4107,16 +4190,11 @@ release the new server and restart the old one."""
4107
4190
  self.app.stdout.write('\rProgress: %s' % progress)
4108
4191
  self.app.stdout.flush()
4109
4192
 
4110
- compute_client = self.app.client_manager.compute
4111
- server = utils.find_resource(
4112
- compute_client.servers,
4113
- parsed_args.server,
4193
+ compute_client = self.app.client_manager.sdk_connection.compute
4194
+ server = compute_client.find_server(
4195
+ parsed_args.server, ignore_missing=False
4114
4196
  )
4115
4197
  if parsed_args.flavor:
4116
- flavor = utils.find_resource(
4117
- compute_client.flavors,
4118
- parsed_args.flavor,
4119
- )
4120
4198
  if not server.image:
4121
4199
  self.log.warning(
4122
4200
  _(
@@ -4124,18 +4202,21 @@ release the new server and restart the old one."""
4124
4202
  "while booting from a persistent volume."
4125
4203
  )
4126
4204
  )
4127
- compute_client.servers.resize(server, flavor)
4205
+ flavor = compute_client.find_flavor(
4206
+ parsed_args.flavor, ignore_missing=False
4207
+ )
4208
+ compute_client.resize_server(server, flavor)
4128
4209
  if parsed_args.wait:
4129
- if utils.wait_for_status(
4130
- compute_client.servers.get,
4210
+ if not utils.wait_for_status(
4211
+ compute_client.get_server,
4131
4212
  server.id,
4132
- success_status=['active', 'verify_resize'],
4213
+ success_status=('active', 'verify_resize'),
4133
4214
  callback=_show_progress,
4134
4215
  ):
4135
- self.app.stdout.write(_('Complete\n'))
4136
- else:
4137
4216
  msg = _('Error resizing server: %s') % server.id
4138
4217
  raise exceptions.CommandError(msg)
4218
+
4219
+ self.app.stdout.write(_('Complete\n'))
4139
4220
  elif parsed_args.confirm:
4140
4221
  self.log.warning(
4141
4222
  _(
@@ -4143,7 +4224,7 @@ release the new server and restart the old one."""
4143
4224
  "'openstack server resize confirm' command instead."
4144
4225
  )
4145
4226
  )
4146
- compute_client.servers.confirm_resize(server)
4227
+ compute_client.confirm_server_resize(server)
4147
4228
  elif parsed_args.revert:
4148
4229
  self.log.warning(
4149
4230
  _(
@@ -4151,7 +4232,7 @@ release the new server and restart the old one."""
4151
4232
  "'openstack server resize revert' command instead."
4152
4233
  )
4153
4234
  )
4154
- compute_client.servers.revert_resize(server)
4235
+ compute_client.revert_server_resize(server)
4155
4236
 
4156
4237
 
4157
4238
  class ResizeConfirm(command.Command):
@@ -4162,7 +4243,7 @@ Confirm (verify) success of resize operation and release the old server."""
4162
4243
  )
4163
4244
 
4164
4245
  def get_parser(self, prog_name):
4165
- parser = super(ResizeConfirm, self).get_parser(prog_name)
4246
+ parser = super().get_parser(prog_name)
4166
4247
  parser.add_argument(
4167
4248
  'server',
4168
4249
  metavar='<server>',
@@ -4171,12 +4252,11 @@ Confirm (verify) success of resize operation and release the old server."""
4171
4252
  return parser
4172
4253
 
4173
4254
  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,
4255
+ compute_client = self.app.client_manager.sdk_connection.compute
4256
+ server = compute_client.find_server(
4257
+ parsed_args.server, ignore_missing=False
4178
4258
  )
4179
- server.confirm_resize()
4259
+ compute_client.confirm_server_resize(server)
4180
4260
 
4181
4261
 
4182
4262
  # TODO(stephenfin): Remove in OSC 7.0
@@ -4211,7 +4291,7 @@ one."""
4211
4291
  )
4212
4292
 
4213
4293
  def get_parser(self, prog_name):
4214
- parser = super(ResizeRevert, self).get_parser(prog_name)
4294
+ parser = super().get_parser(prog_name)
4215
4295
  parser.add_argument(
4216
4296
  'server',
4217
4297
  metavar='<server>',
@@ -4220,12 +4300,11 @@ one."""
4220
4300
  return parser
4221
4301
 
4222
4302
  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,
4303
+ compute_client = self.app.client_manager.sdk_connection.compute
4304
+ server = compute_client.find_server(
4305
+ parsed_args.server, ignore_missing=False
4227
4306
  )
4228
- server.revert_resize()
4307
+ compute_client.revert_server_resize(server)
4229
4308
 
4230
4309
 
4231
4310
  # TODO(stephenfin): Remove in OSC 7.0
@@ -4255,7 +4334,7 @@ class RestoreServer(command.Command):
4255
4334
  _description = _("Restore server(s)")
4256
4335
 
4257
4336
  def get_parser(self, prog_name):
4258
- parser = super(RestoreServer, self).get_parser(prog_name)
4337
+ parser = super().get_parser(prog_name)
4259
4338
  parser.add_argument(
4260
4339
  'server',
4261
4340
  metavar='<server>',
@@ -4278,7 +4357,7 @@ class ResumeServer(command.Command):
4278
4357
  _description = _("Resume server(s)")
4279
4358
 
4280
4359
  def get_parser(self, prog_name):
4281
- parser = super(ResumeServer, self).get_parser(prog_name)
4360
+ parser = super().get_parser(prog_name)
4282
4361
  parser.add_argument(
4283
4362
  'server',
4284
4363
  metavar='<server>',
@@ -4301,7 +4380,7 @@ class SetServer(command.Command):
4301
4380
  _description = _("Set server properties")
4302
4381
 
4303
4382
  def get_parser(self, prog_name):
4304
- parser = super(SetServer, self).get_parser(prog_name)
4383
+ parser = super().get_parser(prog_name)
4305
4384
  parser.add_argument(
4306
4385
  'server',
4307
4386
  metavar='<server>',
@@ -4389,14 +4468,13 @@ class SetServer(command.Command):
4389
4468
  return parser
4390
4469
 
4391
4470
  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,
4471
+ compute_client = self.app.client_manager.sdk_connection.compute
4472
+ server = compute_client.find_server(
4473
+ parsed_args.server, ignore_missing=False
4396
4474
  )
4397
4475
 
4398
4476
  if parsed_args.description:
4399
- if server.api_version < api_versions.APIVersion("2.19"):
4477
+ if not sdk_utils.supports_microversion(compute_client, '2.19'):
4400
4478
  msg = _(
4401
4479
  '--os-compute-api-version 2.19 or greater is required to '
4402
4480
  'support the --description option'
@@ -4404,7 +4482,7 @@ class SetServer(command.Command):
4404
4482
  raise exceptions.CommandError(msg)
4405
4483
 
4406
4484
  if parsed_args.tags:
4407
- if server.api_version < api_versions.APIVersion('2.26'):
4485
+ if not sdk_utils.supports_microversion(compute_client, '2.26'):
4408
4486
  msg = _(
4409
4487
  '--os-compute-api-version 2.26 or greater is required to '
4410
4488
  'support the --tag option'
@@ -4412,7 +4490,7 @@ class SetServer(command.Command):
4412
4490
  raise exceptions.CommandError(msg)
4413
4491
 
4414
4492
  if parsed_args.hostname:
4415
- if server.api_version < api_versions.APIVersion('2.90'):
4493
+ if not sdk_utils.supports_microversion(compute_client, '2.90'):
4416
4494
  msg = _(
4417
4495
  '--os-compute-api-version 2.90 or greater is required to '
4418
4496
  'support the --hostname option'
@@ -4431,30 +4509,32 @@ class SetServer(command.Command):
4431
4509
  update_kwargs['hostname'] = parsed_args.hostname
4432
4510
 
4433
4511
  if update_kwargs:
4434
- server.update(**update_kwargs)
4512
+ compute_client.update_server(server, **update_kwargs)
4435
4513
 
4436
4514
  if parsed_args.properties:
4437
- compute_client.servers.set_meta(server, parsed_args.properties)
4515
+ compute_client.set_server_metadata(
4516
+ server, **parsed_args.properties
4517
+ )
4438
4518
 
4439
4519
  if parsed_args.state:
4440
- server.reset_state(state=parsed_args.state)
4520
+ compute_client.reset_server_state(server, state=parsed_args.state)
4441
4521
 
4442
4522
  if parsed_args.root_password:
4443
4523
  p1 = getpass.getpass(_('New password: '))
4444
4524
  p2 = getpass.getpass(_('Retype new password: '))
4445
4525
  if p1 == p2:
4446
- server.change_password(p1)
4526
+ compute_client.change_server_password(server, p1)
4447
4527
  else:
4448
4528
  msg = _("Passwords do not match, password unchanged")
4449
4529
  raise exceptions.CommandError(msg)
4450
4530
  elif parsed_args.password:
4451
- server.change_password(parsed_args.password)
4531
+ compute_client.change_server_password(server, parsed_args.password)
4452
4532
  elif parsed_args.no_password:
4453
- server.clear_password()
4533
+ compute_client.clear_server_password(server)
4454
4534
 
4455
4535
  if parsed_args.tags:
4456
4536
  for tag in parsed_args.tags:
4457
- server.add_tag(tag=tag)
4537
+ compute_client.add_tag_to_server(server, tag=tag)
4458
4538
 
4459
4539
 
4460
4540
  class ShelveServer(command.Command):
@@ -4575,7 +4655,7 @@ information for the server."""
4575
4655
  )
4576
4656
 
4577
4657
  def get_parser(self, prog_name):
4578
- parser = super(ShowServer, self).get_parser(prog_name)
4658
+ parser = super().get_parser(prog_name)
4579
4659
  parser.add_argument(
4580
4660
  'server',
4581
4661
  metavar='<server>',
@@ -4602,12 +4682,13 @@ information for the server."""
4602
4682
 
4603
4683
  def take_action(self, parsed_args):
4604
4684
  compute_client = self.app.client_manager.sdk_connection.compute
4685
+ image_client = self.app.client_manager.image
4605
4686
 
4606
- # Find by name or ID, then get the full details of the server
4607
4687
  server = compute_client.find_server(
4608
- parsed_args.server, ignore_missing=False
4688
+ parsed_args.server,
4689
+ ignore_missing=False,
4690
+ details=True,
4609
4691
  )
4610
- server = compute_client.get_server(server)
4611
4692
 
4612
4693
  if parsed_args.diagnostics:
4613
4694
  data = compute_client.get_server_diagnostics(server)
@@ -4625,17 +4706,10 @@ information for the server."""
4625
4706
  topology = server.fetch_topology(compute_client)
4626
4707
 
4627
4708
  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,
4709
+ compute_client, image_client, server, refresh=False
4634
4710
  )
4635
-
4636
4711
  if topology:
4637
4712
  data['topology'] = format_columns.DictColumn(topology)
4638
-
4639
4713
  return zip(*sorted(data.items()))
4640
4714
 
4641
4715
 
@@ -4643,7 +4717,7 @@ class SshServer(command.Command):
4643
4717
  _description = _("SSH to server")
4644
4718
 
4645
4719
  def get_parser(self, prog_name):
4646
- parser = super(SshServer, self).get_parser(prog_name)
4720
+ parser = super().get_parser(prog_name)
4647
4721
  parser.add_argument(
4648
4722
  'server',
4649
4723
  metavar='<server>',
@@ -4737,11 +4811,10 @@ class SshServer(command.Command):
4737
4811
  return parser
4738
4812
 
4739
4813
  def take_action(self, parsed_args):
4740
- compute_client = self.app.client_manager.compute
4814
+ compute_client = self.app.client_manager.sdk_connection.compute
4741
4815
 
4742
- server = utils.find_resource(
4743
- compute_client.servers,
4744
- parsed_args.server,
4816
+ server = compute_client.find_server(
4817
+ parsed_args.server, ignore_missing=False
4745
4818
  )
4746
4819
 
4747
4820
  # first, handle the deprecated options
@@ -4795,8 +4868,10 @@ class SshServer(command.Command):
4795
4868
  )
4796
4869
 
4797
4870
  cmd = ' '.join(['ssh', ip_address] + args)
4798
- LOG.debug("ssh command: {cmd}".format(cmd=cmd))
4799
- os.system(cmd)
4871
+ LOG.debug(f"ssh command: {cmd}")
4872
+ # we intentionally pass through user-provided arguments and run this in
4873
+ # the user's shell
4874
+ os.system(cmd) # nosec: B605
4800
4875
 
4801
4876
 
4802
4877
  class StartServer(command.Command):
@@ -4815,7 +4890,7 @@ class StartServer(command.Command):
4815
4890
  action='store_true',
4816
4891
  default=boolenv('ALL_PROJECTS'),
4817
4892
  help=_(
4818
- 'Start server(s) in another project by name (admin only)'
4893
+ 'Start server(s) in another project by name (admin only) '
4819
4894
  '(can be specified using the ALL_PROJECTS envvar)'
4820
4895
  ),
4821
4896
  )
@@ -4824,17 +4899,12 @@ class StartServer(command.Command):
4824
4899
  def take_action(self, parsed_args):
4825
4900
  compute_client = self.app.client_manager.sdk_connection.compute
4826
4901
  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)
4902
+ server_id = compute_client.find_server(
4903
+ server,
4904
+ ignore_missing=False,
4905
+ details=False,
4906
+ all_projects=parsed_args.all_projects,
4907
+ ).id
4838
4908
 
4839
4909
  compute_client.start_server(server_id)
4840
4910
 
@@ -4864,18 +4934,12 @@ class StopServer(command.Command):
4864
4934
  def take_action(self, parsed_args):
4865
4935
  compute_client = self.app.client_manager.sdk_connection.compute
4866
4936
  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
-
4937
+ server_id = compute_client.find_server(
4938
+ server,
4939
+ ignore_missing=False,
4940
+ details=False,
4941
+ all_projects=parsed_args.all_projects,
4942
+ ).id
4879
4943
  compute_client.stop_server(server_id)
4880
4944
 
4881
4945
 
@@ -4883,7 +4947,7 @@ class SuspendServer(command.Command):
4883
4947
  _description = _("Suspend server(s)")
4884
4948
 
4885
4949
  def get_parser(self, prog_name):
4886
- parser = super(SuspendServer, self).get_parser(prog_name)
4950
+ parser = super().get_parser(prog_name)
4887
4951
  parser.add_argument(
4888
4952
  'server',
4889
4953
  metavar='<server>',
@@ -4929,7 +4993,7 @@ class UnpauseServer(command.Command):
4929
4993
  _description = _("Unpause server(s)")
4930
4994
 
4931
4995
  def get_parser(self, prog_name):
4932
- parser = super(UnpauseServer, self).get_parser(prog_name)
4996
+ parser = super().get_parser(prog_name)
4933
4997
  parser.add_argument(
4934
4998
  'server',
4935
4999
  metavar='<server>',
@@ -4952,7 +5016,7 @@ class UnrescueServer(command.Command):
4952
5016
  _description = _("Restore server from rescue mode")
4953
5017
 
4954
5018
  def get_parser(self, prog_name):
4955
- parser = super(UnrescueServer, self).get_parser(prog_name)
5019
+ parser = super().get_parser(prog_name)
4956
5020
  parser.add_argument(
4957
5021
  'server',
4958
5022
  metavar='<server>',
@@ -4961,24 +5025,25 @@ class UnrescueServer(command.Command):
4961
5025
  return parser
4962
5026
 
4963
5027
  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()
5028
+ compute_client = self.app.client_manager.sdk_connection.compute
5029
+ server = compute_client.find_server(
5030
+ parsed_args.server, ignore_missing=False
5031
+ )
5032
+ compute_client.unrescue_server(server)
4969
5033
 
4970
5034
 
4971
5035
  class UnsetServer(command.Command):
4972
5036
  _description = _("Unset server properties and tags")
4973
5037
 
4974
5038
  def get_parser(self, prog_name):
4975
- parser = super(UnsetServer, self).get_parser(prog_name)
5039
+ parser = super().get_parser(prog_name)
4976
5040
  parser.add_argument(
4977
5041
  'server',
4978
5042
  metavar='<server>',
4979
5043
  help=_('Server (name or ID)'),
4980
5044
  )
4981
- parser.add_argument(
5045
+ property_group = parser.add_mutually_exclusive_group()
5046
+ property_group.add_argument(
4982
5047
  '--property',
4983
5048
  metavar='<key>',
4984
5049
  action='append',
@@ -4989,16 +5054,22 @@ class UnsetServer(command.Command):
4989
5054
  '(repeat option to remove multiple values)'
4990
5055
  ),
4991
5056
  )
5057
+ property_group.add_argument(
5058
+ '--all-properties',
5059
+ action='store_true',
5060
+ help=_('Remove all properties'),
5061
+ )
4992
5062
  parser.add_argument(
4993
5063
  '--description',
4994
5064
  dest='description',
4995
5065
  action='store_true',
4996
5066
  help=_(
4997
- 'Unset server description (supported by '
4998
- '--os-compute-api-version 2.19 or above)'
5067
+ 'Unset server description '
5068
+ '(supported by --os-compute-api-version 2.19 or above)'
4999
5069
  ),
5000
5070
  )
5001
- parser.add_argument(
5071
+ tag_group = parser.add_mutually_exclusive_group()
5072
+ tag_group.add_argument(
5002
5073
  '--tag',
5003
5074
  metavar='<tag>',
5004
5075
  action='append',
@@ -5010,32 +5081,40 @@ class UnsetServer(command.Command):
5010
5081
  '(supported by --os-compute-api-version 2.26 or above)'
5011
5082
  ),
5012
5083
  )
5084
+ tag_group.add_argument(
5085
+ '--all-tags',
5086
+ action='store_true',
5087
+ help=_(
5088
+ 'Remove all tags '
5089
+ '(supported by --os-compute-api-version 2.26 or above)'
5090
+ ),
5091
+ )
5013
5092
  return parser
5014
5093
 
5015
5094
  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,
5095
+ compute_client = self.app.client_manager.sdk_connection.compute
5096
+
5097
+ server = compute_client.find_server(
5098
+ parsed_args.server, ignore_missing=False
5020
5099
  )
5021
5100
 
5022
- if parsed_args.properties:
5023
- compute_client.servers.delete_meta(server, parsed_args.properties)
5101
+ if parsed_args.properties or parsed_args.all_properties:
5102
+ compute_client.delete_server_metadata(
5103
+ server, parsed_args.properties or None
5104
+ )
5024
5105
 
5025
5106
  if parsed_args.description:
5026
- if compute_client.api_version < api_versions.APIVersion("2.19"):
5107
+ if not sdk_utils.supports_microversion(compute_client, '2.19'):
5027
5108
  msg = _(
5028
- '--os-compute-api-version 2.19 or greater is '
5029
- 'required to support the --description option'
5109
+ '--os-compute-api-version 2.19 or greater is required to '
5110
+ 'support the --description option'
5030
5111
  )
5031
5112
  raise exceptions.CommandError(msg)
5032
- compute_client.servers.update(
5033
- server,
5034
- description="",
5035
- )
5036
5113
 
5037
- if parsed_args.tags:
5038
- if compute_client.api_version < api_versions.APIVersion('2.26'):
5114
+ compute_client.update_server(server, description="")
5115
+
5116
+ if parsed_args.tags or parsed_args.all_tags:
5117
+ if not sdk_utils.supports_microversion(compute_client, '2.26'):
5039
5118
  msg = _(
5040
5119
  '--os-compute-api-version 2.26 or greater is required to '
5041
5120
  'support the --tag option'
@@ -5043,7 +5122,10 @@ class UnsetServer(command.Command):
5043
5122
  raise exceptions.CommandError(msg)
5044
5123
 
5045
5124
  for tag in parsed_args.tags:
5046
- compute_client.servers.delete_tag(server, tag=tag)
5125
+ compute_client.remove_tag_from_server(server, tag)
5126
+
5127
+ if parsed_args.all_tags:
5128
+ compute_client.remove_tags_from_server(server)
5047
5129
 
5048
5130
 
5049
5131
  class UnshelveServer(command.Command):