python-openstackclient 6.6.1__py3-none-any.whl → 7.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (336) hide show
  1. openstackclient/api/api.py +4 -4
  2. openstackclient/api/compute_v2.py +352 -638
  3. openstackclient/api/image_v1.py +1 -1
  4. openstackclient/api/object_store_v1.py +3 -4
  5. openstackclient/common/availability_zone.py +1 -1
  6. openstackclient/common/clientmanager.py +24 -20
  7. openstackclient/common/configuration.py +1 -1
  8. openstackclient/common/extension.py +1 -1
  9. openstackclient/common/limits.py +67 -34
  10. openstackclient/common/module.py +3 -3
  11. openstackclient/common/progressbar.py +2 -2
  12. openstackclient/common/project_cleanup.py +5 -2
  13. openstackclient/common/quota.py +299 -423
  14. openstackclient/common/versions.py +1 -1
  15. openstackclient/compute/client.py +7 -116
  16. openstackclient/compute/v2/agent.py +75 -49
  17. openstackclient/compute/v2/aggregate.py +38 -32
  18. openstackclient/compute/v2/console.py +2 -2
  19. openstackclient/compute/v2/flavor.py +6 -6
  20. openstackclient/compute/v2/host.py +38 -33
  21. openstackclient/compute/v2/hypervisor.py +9 -6
  22. openstackclient/compute/v2/keypair.py +7 -8
  23. openstackclient/compute/v2/server.py +479 -396
  24. openstackclient/compute/v2/server_backup.py +1 -1
  25. openstackclient/compute/v2/server_group.py +4 -4
  26. openstackclient/compute/v2/server_image.py +1 -1
  27. openstackclient/compute/v2/server_migration.py +3 -4
  28. openstackclient/compute/v2/service.py +4 -4
  29. openstackclient/compute/v2/usage.py +3 -3
  30. openstackclient/identity/common.py +34 -0
  31. openstackclient/identity/v2_0/catalog.py +2 -2
  32. openstackclient/identity/v2_0/ec2creds.py +4 -4
  33. openstackclient/identity/v2_0/endpoint.py +4 -4
  34. openstackclient/identity/v2_0/project.py +6 -6
  35. openstackclient/identity/v2_0/role.py +5 -5
  36. openstackclient/identity/v2_0/role_assignment.py +1 -1
  37. openstackclient/identity/v2_0/service.py +4 -4
  38. openstackclient/identity/v2_0/token.py +2 -2
  39. openstackclient/identity/v2_0/user.py +7 -7
  40. openstackclient/identity/v3/access_rule.py +3 -3
  41. openstackclient/identity/v3/application_credential.py +125 -43
  42. openstackclient/identity/v3/catalog.py +2 -2
  43. openstackclient/identity/v3/consumer.py +4 -4
  44. openstackclient/identity/v3/credential.py +5 -5
  45. openstackclient/identity/v3/domain.py +5 -5
  46. openstackclient/identity/v3/ec2creds.py +4 -4
  47. openstackclient/identity/v3/endpoint.py +7 -7
  48. openstackclient/identity/v3/endpoint_group.py +8 -10
  49. openstackclient/identity/v3/federation_protocol.py +5 -5
  50. openstackclient/identity/v3/group.py +8 -8
  51. openstackclient/identity/v3/identity_provider.py +5 -5
  52. openstackclient/identity/v3/implied_role.py +3 -3
  53. openstackclient/identity/v3/limit.py +5 -5
  54. openstackclient/identity/v3/mapping.py +5 -5
  55. openstackclient/identity/v3/policy.py +5 -5
  56. openstackclient/identity/v3/project.py +5 -5
  57. openstackclient/identity/v3/region.py +5 -5
  58. openstackclient/identity/v3/registered_limit.py +5 -5
  59. openstackclient/identity/v3/role.py +7 -7
  60. openstackclient/identity/v3/role_assignment.py +92 -140
  61. openstackclient/identity/v3/service.py +64 -34
  62. openstackclient/identity/v3/service_provider.py +4 -4
  63. openstackclient/identity/v3/tag.py +2 -2
  64. openstackclient/identity/v3/token.py +5 -5
  65. openstackclient/identity/v3/trust.py +3 -3
  66. openstackclient/identity/v3/user.py +144 -80
  67. openstackclient/image/client.py +4 -4
  68. openstackclient/image/v1/image.py +8 -9
  69. openstackclient/image/v2/cache.py +12 -10
  70. openstackclient/image/v2/metadef_objects.py +44 -0
  71. openstackclient/image/v2/metadef_resource_type_association.py +189 -0
  72. openstackclient/image/v2/task.py +1 -1
  73. openstackclient/network/common.py +6 -5
  74. openstackclient/network/utils.py +2 -2
  75. openstackclient/network/v2/address_group.py +6 -6
  76. openstackclient/network/v2/address_scope.py +5 -5
  77. openstackclient/network/v2/default_security_group_rule.py +1 -1
  78. openstackclient/network/v2/floating_ip.py +8 -10
  79. openstackclient/network/v2/floating_ip_pool.py +6 -15
  80. openstackclient/network/v2/floating_ip_port_forwarding.py +5 -13
  81. openstackclient/network/v2/ip_availability.py +2 -2
  82. openstackclient/network/v2/l3_conntrack_helper.py +5 -5
  83. openstackclient/network/v2/network.py +8 -8
  84. openstackclient/network/v2/network_agent.py +8 -8
  85. openstackclient/network/v2/network_auto_allocated_topology.py +2 -2
  86. openstackclient/network/v2/network_flavor.py +6 -8
  87. openstackclient/network/v2/network_flavor_profile.py +4 -4
  88. openstackclient/network/v2/network_meter.py +3 -3
  89. openstackclient/network/v2/network_meter_rule.py +3 -3
  90. openstackclient/network/v2/network_qos_policy.py +5 -5
  91. openstackclient/network/v2/network_qos_rule.py +9 -9
  92. openstackclient/network/v2/network_qos_rule_type.py +1 -1
  93. openstackclient/network/v2/network_rbac.py +5 -5
  94. openstackclient/network/v2/network_segment.py +5 -5
  95. openstackclient/network/v2/network_segment_range.py +7 -7
  96. openstackclient/network/v2/network_trunk.py +7 -7
  97. openstackclient/network/v2/port.py +26 -12
  98. openstackclient/network/v2/router.py +403 -54
  99. openstackclient/network/v2/security_group.py +18 -14
  100. openstackclient/network/v2/security_group_rule.py +18 -15
  101. openstackclient/network/v2/subnet.py +15 -8
  102. openstackclient/network/v2/subnet_pool.py +6 -6
  103. openstackclient/object/v1/account.py +2 -2
  104. openstackclient/object/v1/container.py +7 -7
  105. openstackclient/object/v1/object.py +7 -7
  106. openstackclient/releasenotes/notes/volume-backup-created-at-list-b49ec893ae1f6b0d.yaml +4 -0
  107. openstackclient/shell.py +4 -6
  108. openstackclient/tests/functional/base.py +1 -1
  109. openstackclient/tests/functional/common/test_extension.py +1 -1
  110. openstackclient/tests/functional/common/test_help.py +2 -2
  111. openstackclient/tests/functional/common/test_module.py +1 -1
  112. openstackclient/tests/functional/common/test_quota.py +43 -61
  113. openstackclient/tests/functional/compute/v2/common.py +2 -2
  114. openstackclient/tests/functional/compute/v2/test_flavor.py +2 -2
  115. openstackclient/tests/functional/compute/v2/test_keypair.py +1 -1
  116. openstackclient/tests/functional/compute/v2/test_server.py +5 -5
  117. openstackclient/tests/functional/compute/v2/test_server_event.py +1 -1
  118. openstackclient/tests/functional/identity/v2/common.py +3 -3
  119. openstackclient/tests/functional/identity/v3/common.py +12 -4
  120. openstackclient/tests/functional/identity/v3/test_application_credential.py +6 -12
  121. openstackclient/tests/functional/identity/v3/test_domain.py +1 -3
  122. openstackclient/tests/functional/identity/v3/test_endpoint.py +1 -1
  123. openstackclient/tests/functional/identity/v3/test_idp.py +1 -1
  124. openstackclient/tests/functional/identity/v3/test_region.py +1 -3
  125. openstackclient/tests/functional/identity/v3/test_role.py +2 -2
  126. openstackclient/tests/functional/identity/v3/test_role_assignment.py +210 -0
  127. openstackclient/tests/functional/identity/v3/test_service.py +1 -3
  128. openstackclient/tests/functional/identity/v3/test_service_provider.py +1 -3
  129. openstackclient/tests/functional/image/base.py +1 -1
  130. openstackclient/tests/functional/image/v2/test_image.py +1 -1
  131. openstackclient/tests/functional/image/v2/test_info.py +1 -1
  132. openstackclient/tests/functional/network/v2/common.py +4 -6
  133. openstackclient/tests/functional/network/v2/test_network.py +5 -3
  134. openstackclient/tests/functional/network/v2/test_network_agent.py +7 -5
  135. openstackclient/tests/functional/network/v2/test_network_qos_rule.py +4 -4
  136. openstackclient/tests/functional/network/v2/test_port.py +11 -7
  137. openstackclient/tests/functional/network/v2/test_router.py +2 -2
  138. openstackclient/tests/functional/object/v1/common.py +1 -1
  139. openstackclient/tests/functional/object/v1/test_container.py +3 -3
  140. openstackclient/tests/functional/object/v1/test_object.py +9 -13
  141. openstackclient/tests/functional/volume/base.py +1 -1
  142. openstackclient/tests/functional/volume/v1/test_service.py +1 -1
  143. openstackclient/tests/functional/volume/v1/test_snapshot.py +2 -2
  144. openstackclient/tests/functional/volume/v1/test_transfer_request.py +2 -2
  145. openstackclient/tests/functional/volume/v1/test_volume_type.py +1 -1
  146. openstackclient/tests/functional/volume/v2/test_service.py +2 -2
  147. openstackclient/tests/functional/volume/v2/test_volume_backup.py +2 -2
  148. openstackclient/tests/functional/volume/v2/test_volume_snapshot.py +2 -2
  149. openstackclient/tests/functional/volume/v2/test_volume_type.py +1 -1
  150. openstackclient/tests/functional/volume/v3/test_volume_snapshot.py +2 -2
  151. openstackclient/tests/functional/volume/v3/test_volume_type.py +1 -1
  152. openstackclient/tests/unit/api/fakes.py +1 -1
  153. openstackclient/tests/unit/api/test_api.py +2 -2
  154. openstackclient/tests/unit/api/test_compute_v2.py +522 -707
  155. openstackclient/tests/unit/api/test_image_v1.py +1 -1
  156. openstackclient/tests/unit/api/test_image_v2.py +1 -1
  157. openstackclient/tests/unit/api/test_object_store_v1.py +4 -4
  158. openstackclient/tests/unit/common/test_limits.py +73 -35
  159. openstackclient/tests/unit/common/test_logs.py +2 -2
  160. openstackclient/tests/unit/common/test_module.py +4 -2
  161. openstackclient/tests/unit/common/test_project_cleanup.py +31 -6
  162. openstackclient/tests/unit/common/test_quota.py +490 -630
  163. openstackclient/tests/unit/compute/v2/fakes.py +37 -286
  164. openstackclient/tests/unit/compute/v2/test_agent.py +189 -147
  165. openstackclient/tests/unit/compute/v2/test_aggregate.py +87 -57
  166. openstackclient/tests/unit/compute/v2/test_console.py +4 -5
  167. openstackclient/tests/unit/compute/v2/test_flavor.py +59 -68
  168. openstackclient/tests/unit/compute/v2/test_host.py +83 -54
  169. openstackclient/tests/unit/compute/v2/test_hypervisor.py +57 -34
  170. openstackclient/tests/unit/compute/v2/test_hypervisor_stats.py +2 -2
  171. openstackclient/tests/unit/compute/v2/test_keypair.py +65 -50
  172. openstackclient/tests/unit/compute/v2/test_server.py +2850 -2453
  173. openstackclient/tests/unit/compute/v2/test_server_backup.py +1 -1
  174. openstackclient/tests/unit/compute/v2/test_server_event.py +14 -39
  175. openstackclient/tests/unit/compute/v2/test_server_group.py +28 -29
  176. openstackclient/tests/unit/compute/v2/test_server_migration.py +43 -68
  177. openstackclient/tests/unit/compute/v2/test_server_volume.py +17 -34
  178. openstackclient/tests/unit/compute/v2/test_service.py +34 -52
  179. openstackclient/tests/unit/compute/v2/test_usage.py +4 -4
  180. openstackclient/tests/unit/fakes.py +12 -12
  181. openstackclient/tests/unit/identity/v2_0/fakes.py +27 -10
  182. openstackclient/tests/unit/identity/v2_0/test_catalog.py +3 -3
  183. openstackclient/tests/unit/identity/v2_0/test_endpoint.py +7 -7
  184. openstackclient/tests/unit/identity/v2_0/test_project.py +8 -8
  185. openstackclient/tests/unit/identity/v2_0/test_role.py +10 -10
  186. openstackclient/tests/unit/identity/v2_0/test_role_assignment.py +4 -4
  187. openstackclient/tests/unit/identity/v2_0/test_service.py +6 -6
  188. openstackclient/tests/unit/identity/v2_0/test_token.py +4 -4
  189. openstackclient/tests/unit/identity/v2_0/test_user.py +8 -8
  190. openstackclient/tests/unit/identity/v3/fakes.py +59 -20
  191. openstackclient/tests/unit/identity/v3/test_access_rule.py +5 -5
  192. openstackclient/tests/unit/identity/v3/test_application_credential.py +207 -230
  193. openstackclient/tests/unit/identity/v3/test_catalog.py +3 -3
  194. openstackclient/tests/unit/identity/v3/test_consumer.py +7 -8
  195. openstackclient/tests/unit/identity/v3/test_credential.py +9 -9
  196. openstackclient/tests/unit/identity/v3/test_domain.py +8 -8
  197. openstackclient/tests/unit/identity/v3/test_endpoint.py +13 -13
  198. openstackclient/tests/unit/identity/v3/test_endpoint_group.py +12 -14
  199. openstackclient/tests/unit/identity/v3/test_group.py +12 -12
  200. openstackclient/tests/unit/identity/v3/test_identity_provider.py +8 -8
  201. openstackclient/tests/unit/identity/v3/test_implied_role.py +5 -5
  202. openstackclient/tests/unit/identity/v3/test_limit.py +7 -7
  203. openstackclient/tests/unit/identity/v3/test_mappings.py +7 -7
  204. openstackclient/tests/unit/identity/v3/test_oauth.py +5 -5
  205. openstackclient/tests/unit/identity/v3/test_project.py +16 -16
  206. openstackclient/tests/unit/identity/v3/test_protocol.py +7 -7
  207. openstackclient/tests/unit/identity/v3/test_region.py +7 -7
  208. openstackclient/tests/unit/identity/v3/test_registered_limit.py +12 -13
  209. openstackclient/tests/unit/identity/v3/test_role.py +13 -13
  210. openstackclient/tests/unit/identity/v3/test_role_assignment.py +410 -331
  211. openstackclient/tests/unit/identity/v3/test_service.py +90 -94
  212. openstackclient/tests/unit/identity/v3/test_service_provider.py +7 -7
  213. openstackclient/tests/unit/identity/v3/test_token.py +4 -4
  214. openstackclient/tests/unit/identity/v3/test_trust.py +9 -9
  215. openstackclient/tests/unit/identity/v3/test_unscoped_saml.py +4 -4
  216. openstackclient/tests/unit/identity/v3/test_user.py +299 -327
  217. openstackclient/tests/unit/image/v1/test_image.py +6 -6
  218. openstackclient/tests/unit/image/v2/fakes.py +46 -9
  219. openstackclient/tests/unit/image/v2/test_cache.py +2 -2
  220. openstackclient/tests/unit/image/v2/test_image.py +3 -3
  221. openstackclient/tests/unit/image/v2/test_metadef_objects.py +62 -0
  222. openstackclient/tests/unit/image/v2/test_metadef_resource_type_association.py +131 -0
  223. openstackclient/tests/unit/integ/base.py +1 -1
  224. openstackclient/tests/unit/integ/cli/test_project.py +4 -4
  225. openstackclient/tests/unit/integ/cli/test_shell.py +7 -7
  226. openstackclient/tests/unit/network/test_common.py +12 -21
  227. openstackclient/tests/unit/network/v2/fakes.py +64 -130
  228. openstackclient/tests/unit/network/v2/test_address_group.py +15 -15
  229. openstackclient/tests/unit/network/v2/test_address_scope.py +13 -13
  230. openstackclient/tests/unit/network/v2/test_default_security_group_rule.py +49 -27
  231. openstackclient/tests/unit/network/v2/test_floating_ip_compute.py +40 -38
  232. openstackclient/tests/unit/network/v2/test_floating_ip_network.py +15 -15
  233. openstackclient/tests/unit/network/v2/test_floating_ip_pool_compute.py +4 -7
  234. openstackclient/tests/unit/network/v2/test_floating_ip_pool_network.py +3 -5
  235. openstackclient/tests/unit/network/v2/test_floating_ip_port_forwarding.py +11 -11
  236. openstackclient/tests/unit/network/v2/test_ip_availability.py +6 -6
  237. openstackclient/tests/unit/network/v2/test_l3_conntrack_helper.py +11 -21
  238. openstackclient/tests/unit/network/v2/test_local_ip.py +7 -7
  239. openstackclient/tests/unit/network/v2/test_local_ip_association.py +3 -5
  240. openstackclient/tests/unit/network/v2/test_ndp_proxy.py +13 -13
  241. openstackclient/tests/unit/network/v2/test_network.py +23 -28
  242. openstackclient/tests/unit/network/v2/test_network_agent.py +17 -21
  243. openstackclient/tests/unit/network/v2/test_network_auto_allocated_topology.py +8 -8
  244. openstackclient/tests/unit/network/v2/test_network_compute.py +66 -65
  245. openstackclient/tests/unit/network/v2/test_network_flavor.py +17 -19
  246. openstackclient/tests/unit/network/v2/test_network_flavor_profile.py +13 -13
  247. openstackclient/tests/unit/network/v2/test_network_meter.py +11 -11
  248. openstackclient/tests/unit/network/v2/test_network_meter_rule.py +11 -11
  249. openstackclient/tests/unit/network/v2/test_network_qos_policy.py +11 -21
  250. openstackclient/tests/unit/network/v2/test_network_qos_rule.py +51 -77
  251. openstackclient/tests/unit/network/v2/test_network_qos_rule_type.py +5 -9
  252. openstackclient/tests/unit/network/v2/test_network_rbac.py +12 -12
  253. openstackclient/tests/unit/network/v2/test_network_segment.py +11 -15
  254. openstackclient/tests/unit/network/v2/test_network_segment_range.py +11 -13
  255. openstackclient/tests/unit/network/v2/test_network_service_provider.py +3 -5
  256. openstackclient/tests/unit/network/v2/test_network_trunk.py +11 -11
  257. openstackclient/tests/unit/network/v2/test_port.py +22 -25
  258. openstackclient/tests/unit/network/v2/test_router.py +721 -51
  259. openstackclient/tests/unit/network/v2/test_security_group_compute.py +65 -49
  260. openstackclient/tests/unit/network/v2/test_security_group_network.py +15 -15
  261. openstackclient/tests/unit/network/v2/test_security_group_rule_compute.py +57 -45
  262. openstackclient/tests/unit/network/v2/test_security_group_rule_network.py +11 -19
  263. openstackclient/tests/unit/network/v2/test_subnet.py +29 -25
  264. openstackclient/tests/unit/network/v2/test_subnet_pool.py +15 -15
  265. openstackclient/tests/unit/object/v1/fakes.py +1 -1
  266. openstackclient/tests/unit/object/v1/test_container.py +5 -5
  267. openstackclient/tests/unit/object/v1/test_container_all.py +6 -6
  268. openstackclient/tests/unit/object/v1/test_object.py +3 -3
  269. openstackclient/tests/unit/object/v1/test_object_all.py +5 -5
  270. openstackclient/tests/unit/test_shell.py +5 -5
  271. openstackclient/tests/unit/utils.py +4 -1
  272. openstackclient/tests/unit/volume/test_find_resource.py +2 -2
  273. openstackclient/tests/unit/volume/v1/fakes.py +5 -6
  274. openstackclient/tests/unit/volume/v1/test_volume.py +5 -4
  275. openstackclient/tests/unit/volume/v2/fakes.py +39 -259
  276. openstackclient/tests/unit/volume/v2/test_consistency_group_snapshot.py +5 -5
  277. openstackclient/tests/unit/volume/v2/test_qos_specs.py +9 -9
  278. openstackclient/tests/unit/volume/v2/test_volume.py +21 -87
  279. openstackclient/tests/unit/volume/v2/test_volume_backup.py +10 -368
  280. openstackclient/tests/unit/volume/v2/test_volume_snapshot.py +1 -1
  281. openstackclient/tests/unit/volume/v2/test_volume_transfer_request.py +0 -44
  282. openstackclient/tests/unit/volume/v2/test_volume_type.py +6 -87
  283. openstackclient/tests/unit/volume/v3/fakes.py +505 -22
  284. openstackclient/tests/unit/volume/v3/test_block_storage_cleanup.py +2 -3
  285. openstackclient/tests/unit/volume/v3/test_block_storage_cluster.py +10 -11
  286. openstackclient/tests/unit/volume/v3/test_block_storage_log_level.py +10 -6
  287. openstackclient/tests/unit/volume/v3/test_block_storage_manage.py +25 -17
  288. openstackclient/tests/unit/volume/v3/test_block_storage_resource_filter.py +6 -32
  289. openstackclient/tests/unit/volume/v3/test_service.py +271 -0
  290. openstackclient/tests/unit/volume/v3/test_volume.py +2177 -33
  291. openstackclient/tests/unit/volume/v3/test_volume_attachment.py +48 -52
  292. openstackclient/tests/unit/volume/v3/test_volume_backup.py +892 -0
  293. openstackclient/tests/unit/volume/v3/test_volume_group.py +19 -20
  294. openstackclient/tests/unit/volume/v3/test_volume_group_snapshot.py +14 -34
  295. openstackclient/tests/unit/volume/v3/test_volume_group_type.py +13 -16
  296. openstackclient/tests/unit/volume/v3/test_volume_message.py +10 -11
  297. openstackclient/tests/unit/volume/v3/test_volume_snapshot.py +161 -0
  298. openstackclient/tests/unit/volume/v3/test_volume_transfer_request.py +425 -0
  299. openstackclient/tests/unit/volume/v3/test_volume_type.py +1109 -0
  300. openstackclient/volume/v1/qos_specs.py +7 -7
  301. openstackclient/volume/v1/service.py +2 -2
  302. openstackclient/volume/v1/volume.py +12 -12
  303. openstackclient/volume/v1/volume_backup.py +7 -7
  304. openstackclient/volume/v1/volume_snapshot.py +8 -8
  305. openstackclient/volume/v1/volume_transfer_request.py +5 -5
  306. openstackclient/volume/v1/volume_type.py +7 -7
  307. openstackclient/volume/v2/backup_record.py +2 -2
  308. openstackclient/volume/v2/consistency_group.py +7 -9
  309. openstackclient/volume/v2/consistency_group_snapshot.py +4 -12
  310. openstackclient/volume/v2/qos_specs.py +7 -7
  311. openstackclient/volume/v2/service.py +2 -2
  312. openstackclient/volume/v2/volume.py +80 -80
  313. openstackclient/volume/v2/volume_backend.py +2 -2
  314. openstackclient/volume/v2/volume_backup.py +9 -217
  315. openstackclient/volume/v2/volume_host.py +2 -2
  316. openstackclient/volume/v2/volume_snapshot.py +8 -8
  317. openstackclient/volume/v2/volume_transfer_request.py +5 -37
  318. openstackclient/volume/v2/volume_type.py +7 -89
  319. openstackclient/volume/v3/service.py +56 -0
  320. openstackclient/volume/v3/volume.py +971 -0
  321. openstackclient/volume/v3/volume_attachment.py +31 -29
  322. openstackclient/volume/v3/volume_backup.py +670 -0
  323. openstackclient/volume/v3/volume_message.py +1 -1
  324. openstackclient/volume/v3/volume_snapshot.py +97 -0
  325. openstackclient/volume/v3/volume_transfer_request.py +233 -0
  326. openstackclient/volume/v3/volume_type.py +967 -0
  327. {python_openstackclient-6.6.1.dist-info → python_openstackclient-7.1.0.dist-info}/AUTHORS +6 -0
  328. {python_openstackclient-6.6.1.dist-info → python_openstackclient-7.1.0.dist-info}/METADATA +4 -4
  329. python_openstackclient-7.1.0.dist-info/RECORD +503 -0
  330. {python_openstackclient-6.6.1.dist-info → python_openstackclient-7.1.0.dist-info}/entry_points.txt +33 -27
  331. python_openstackclient-7.1.0.dist-info/pbr.json +1 -0
  332. python_openstackclient-6.6.1.dist-info/RECORD +0 -489
  333. python_openstackclient-6.6.1.dist-info/pbr.json +0 -1
  334. {python_openstackclient-6.6.1.dist-info → python_openstackclient-7.1.0.dist-info}/LICENSE +0 -0
  335. {python_openstackclient-6.6.1.dist-info → python_openstackclient-7.1.0.dist-info}/WHEEL +0 -0
  336. {python_openstackclient-6.6.1.dist-info → python_openstackclient-7.1.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,967 @@
1
+ #
2
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may
3
+ # not use this file except in compliance with the License. You may obtain
4
+ # a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11
+ # License for the specific language governing permissions and limitations
12
+ # under the License.
13
+ #
14
+
15
+ """Volume v3 Type action implementations"""
16
+
17
+ import functools
18
+ import logging
19
+
20
+ from cinderclient import api_versions
21
+ from cliff import columns as cliff_columns
22
+ from osc_lib.cli import format_columns
23
+ from osc_lib.cli import parseractions
24
+ from osc_lib.command import command
25
+ from osc_lib import exceptions
26
+ from osc_lib import utils
27
+
28
+ from openstackclient.i18n import _
29
+ from openstackclient.identity import common as identity_common
30
+
31
+
32
+ LOG = logging.getLogger(__name__)
33
+
34
+
35
+ class EncryptionInfoColumn(cliff_columns.FormattableColumn):
36
+ """Formattable column for encryption info column.
37
+
38
+ Unlike the parent FormattableColumn class, the initializer of the
39
+ class takes encryption_data as the second argument.
40
+ osc_lib.utils.get_item_properties instantiate cliff FormattableColumn
41
+ object with a single parameter "column value", so you need to pass
42
+ a partially initialized class like
43
+ ``functools.partial(EncryptionInfoColumn encryption_data)``.
44
+ """
45
+
46
+ def __init__(self, value, encryption_data=None):
47
+ super().__init__(value)
48
+ self._encryption_data = encryption_data or {}
49
+
50
+ def _get_encryption_info(self):
51
+ type_id = self._value
52
+ return self._encryption_data.get(type_id)
53
+
54
+ def human_readable(self):
55
+ encryption_info = self._get_encryption_info()
56
+ if encryption_info:
57
+ return utils.format_dict(encryption_info)
58
+ else:
59
+ return '-'
60
+
61
+ def machine_readable(self):
62
+ return self._get_encryption_info()
63
+
64
+
65
+ def _create_encryption_type(volume_client, volume_type, parsed_args):
66
+ if not parsed_args.encryption_provider:
67
+ msg = _(
68
+ "'--encryption-provider' should be specified while "
69
+ "creating a new encryption type"
70
+ )
71
+ raise exceptions.CommandError(msg)
72
+ # set the default of control location while creating
73
+ control_location = 'front-end'
74
+ if parsed_args.encryption_control_location:
75
+ control_location = parsed_args.encryption_control_location
76
+ body = {
77
+ 'provider': parsed_args.encryption_provider,
78
+ 'cipher': parsed_args.encryption_cipher,
79
+ 'key_size': parsed_args.encryption_key_size,
80
+ 'control_location': control_location,
81
+ }
82
+ encryption = volume_client.volume_encryption_types.create(
83
+ volume_type, body
84
+ )
85
+ return encryption
86
+
87
+
88
+ def _set_encryption_type(volume_client, volume_type, parsed_args):
89
+ # update the existing encryption type
90
+ body = {}
91
+ for attr in ['provider', 'cipher', 'key_size', 'control_location']:
92
+ info = getattr(parsed_args, 'encryption_' + attr, None)
93
+ if info is not None:
94
+ body[attr] = info
95
+ try:
96
+ volume_client.volume_encryption_types.update(volume_type, body)
97
+ except Exception as e:
98
+ if type(e).__name__ == 'NotFound':
99
+ # create new encryption type
100
+ LOG.warning(
101
+ _(
102
+ "No existing encryption type found, creating "
103
+ "new encryption type for this volume type ..."
104
+ )
105
+ )
106
+ _create_encryption_type(volume_client, volume_type, parsed_args)
107
+
108
+
109
+ class CreateVolumeType(command.ShowOne):
110
+ _description = _("Create new volume type")
111
+
112
+ def get_parser(self, prog_name):
113
+ parser = super().get_parser(prog_name)
114
+ parser.add_argument(
115
+ "name",
116
+ metavar="<name>",
117
+ help=_("Volume type name"),
118
+ )
119
+ parser.add_argument(
120
+ "--description",
121
+ metavar="<description>",
122
+ help=_("Volume type description"),
123
+ )
124
+ public_group = parser.add_mutually_exclusive_group()
125
+ public_group.add_argument(
126
+ "--public",
127
+ action="store_true",
128
+ dest="is_public",
129
+ default=None,
130
+ help=_("Volume type is accessible to the public"),
131
+ )
132
+ public_group.add_argument(
133
+ "--private",
134
+ action="store_false",
135
+ dest="is_public",
136
+ default=None,
137
+ help=_("Volume type is not accessible to the public"),
138
+ )
139
+ parser.add_argument(
140
+ '--property',
141
+ metavar='<key=value>',
142
+ action=parseractions.KeyValueAction,
143
+ dest='properties',
144
+ help=_(
145
+ 'Set a property on this volume type '
146
+ '(repeat option to set multiple properties)'
147
+ ),
148
+ )
149
+ parser.add_argument(
150
+ '--multiattach',
151
+ action='store_true',
152
+ default=False,
153
+ help=_(
154
+ "Enable multi-attach for this volume type "
155
+ "(this is an alias for '--property multiattach=<is> True') "
156
+ "(requires driver support)"
157
+ ),
158
+ )
159
+ parser.add_argument(
160
+ '--cacheable',
161
+ action='store_true',
162
+ default=False,
163
+ help=_(
164
+ "Enable caching for this volume type "
165
+ "(this is an alias for '--property cacheable=<is> True') "
166
+ "(requires driver support)"
167
+ ),
168
+ )
169
+ parser.add_argument(
170
+ '--replicated',
171
+ action='store_true',
172
+ default=False,
173
+ help=_(
174
+ "Enabled replication for this volume type "
175
+ "(this is an alias for '--property replication_enabled=<is> True') " # noqa: E501
176
+ "(requires driver support)"
177
+ ),
178
+ )
179
+ parser.add_argument(
180
+ '--availability-zone',
181
+ action='append',
182
+ dest='availability_zones',
183
+ help=_(
184
+ "Set an availability zone for this volume type "
185
+ "(this is an alias for '--property RESKEY:availability_zones:<az>') " # noqa: E501
186
+ "(repeat option to set multiple availability zones)"
187
+ ),
188
+ )
189
+ parser.add_argument(
190
+ '--project',
191
+ metavar='<project>',
192
+ help=_(
193
+ "Allow <project> to access private type (name or ID) "
194
+ "(must be used with --private option)"
195
+ ),
196
+ )
197
+ identity_common.add_project_domain_option_to_parser(parser)
198
+ # TODO(Huanxuan Ao): Add choices for each "--encryption-*" option.
199
+ parser.add_argument(
200
+ '--encryption-provider',
201
+ metavar='<provider>',
202
+ help=_(
203
+ 'Set the encryption provider format for '
204
+ 'this volume type (e.g "luks" or "plain") (admin only) '
205
+ '(this option is required when setting encryption type '
206
+ 'of a volume; consider using other encryption options '
207
+ 'such as: "--encryption-cipher", "--encryption-key-size" '
208
+ 'and "--encryption-control-location")'
209
+ ),
210
+ )
211
+ parser.add_argument(
212
+ '--encryption-cipher',
213
+ metavar='<cipher>',
214
+ help=_(
215
+ 'Set the encryption algorithm or mode for this '
216
+ 'volume type (e.g "aes-xts-plain64") (admin only)'
217
+ ),
218
+ )
219
+ parser.add_argument(
220
+ '--encryption-key-size',
221
+ metavar='<key-size>',
222
+ type=int,
223
+ help=_(
224
+ 'Set the size of the encryption key of this '
225
+ 'volume type (e.g "128" or "256") (admin only)'
226
+ ),
227
+ )
228
+ parser.add_argument(
229
+ '--encryption-control-location',
230
+ metavar='<control-location>',
231
+ choices=['front-end', 'back-end'],
232
+ help=_(
233
+ 'Set the notional service where the encryption is '
234
+ 'performed ("front-end" or "back-end") (admin only) '
235
+ '(The default value for this option is "front-end" '
236
+ 'when setting encryption type of a volume. Consider '
237
+ 'using other encryption options such as: '
238
+ '"--encryption-cipher", "--encryption-key-size" and '
239
+ '"--encryption-provider")'
240
+ ),
241
+ )
242
+ return parser
243
+
244
+ def take_action(self, parsed_args):
245
+ identity_client = self.app.client_manager.identity
246
+ volume_client = self.app.client_manager.volume
247
+
248
+ if parsed_args.project and parsed_args.is_public is not False:
249
+ msg = _("--project is only allowed with --private")
250
+ raise exceptions.CommandError(msg)
251
+
252
+ kwargs = {}
253
+
254
+ if parsed_args.is_public is not None:
255
+ kwargs['is_public'] = parsed_args.is_public
256
+
257
+ volume_type = volume_client.volume_types.create(
258
+ parsed_args.name,
259
+ description=parsed_args.description,
260
+ **kwargs,
261
+ )
262
+ volume_type._info.pop('extra_specs')
263
+
264
+ if parsed_args.project:
265
+ try:
266
+ project_id = identity_common.find_project(
267
+ identity_client,
268
+ parsed_args.project,
269
+ parsed_args.project_domain,
270
+ ).id
271
+ volume_client.volume_type_access.add_project_access(
272
+ volume_type.id, project_id
273
+ )
274
+ except Exception as e:
275
+ msg = _(
276
+ "Failed to add project %(project)s access to "
277
+ "type: %(e)s"
278
+ )
279
+ LOG.error(msg % {'project': parsed_args.project, 'e': e})
280
+
281
+ properties = {}
282
+ if parsed_args.properties:
283
+ properties.update(parsed_args.properties)
284
+ if parsed_args.multiattach:
285
+ properties['multiattach'] = '<is> True'
286
+ if parsed_args.cacheable:
287
+ properties['cacheable'] = '<is> True'
288
+ if parsed_args.replicated:
289
+ properties['replication_enabled'] = '<is> True'
290
+ if parsed_args.availability_zones:
291
+ properties['RESKEY:availability_zones'] = ','.join(
292
+ parsed_args.availability_zones
293
+ )
294
+ if properties:
295
+ result = volume_type.set_keys(properties)
296
+ volume_type._info.update(
297
+ {'properties': format_columns.DictColumn(result)}
298
+ )
299
+
300
+ if (
301
+ parsed_args.encryption_provider
302
+ or parsed_args.encryption_cipher
303
+ or parsed_args.encryption_key_size
304
+ or parsed_args.encryption_control_location
305
+ ):
306
+ try:
307
+ # create new encryption
308
+ encryption = _create_encryption_type(
309
+ volume_client, volume_type, parsed_args
310
+ )
311
+ except Exception as e:
312
+ LOG.error(
313
+ _(
314
+ "Failed to set encryption information for this "
315
+ "volume type: %s"
316
+ ),
317
+ e,
318
+ )
319
+ # add encryption info in result
320
+ encryption._info.pop("volume_type_id", None)
321
+ volume_type._info.update(
322
+ {'encryption': format_columns.DictColumn(encryption._info)}
323
+ )
324
+
325
+ volume_type._info.pop("os-volume-type-access:is_public", None)
326
+
327
+ return zip(*sorted(volume_type._info.items()))
328
+
329
+
330
+ class DeleteVolumeType(command.Command):
331
+ _description = _("Delete volume type(s)")
332
+
333
+ def get_parser(self, prog_name):
334
+ parser = super().get_parser(prog_name)
335
+ parser.add_argument(
336
+ "volume_types",
337
+ metavar="<volume-type>",
338
+ nargs="+",
339
+ help=_("Volume type(s) to delete (name or ID)"),
340
+ )
341
+ return parser
342
+
343
+ def take_action(self, parsed_args):
344
+ volume_client = self.app.client_manager.volume
345
+ result = 0
346
+
347
+ for volume_type in parsed_args.volume_types:
348
+ try:
349
+ vol_type = utils.find_resource(
350
+ volume_client.volume_types, volume_type
351
+ )
352
+
353
+ volume_client.volume_types.delete(vol_type)
354
+ except Exception as e:
355
+ result += 1
356
+ LOG.error(
357
+ _(
358
+ "Failed to delete volume type with "
359
+ "name or ID '%(volume_type)s': %(e)s"
360
+ )
361
+ % {'volume_type': volume_type, 'e': e}
362
+ )
363
+
364
+ if result > 0:
365
+ total = len(parsed_args.volume_types)
366
+ msg = _(
367
+ "%(result)s of %(total)s volume types failed " "to delete."
368
+ ) % {'result': result, 'total': total}
369
+ raise exceptions.CommandError(msg)
370
+
371
+
372
+ class ListVolumeType(command.Lister):
373
+ _description = _("List volume types")
374
+
375
+ def get_parser(self, prog_name):
376
+ parser = super().get_parser(prog_name)
377
+ parser.add_argument(
378
+ '--long',
379
+ action='store_true',
380
+ default=False,
381
+ help=_('List additional fields in output'),
382
+ )
383
+ public_group = parser.add_mutually_exclusive_group()
384
+ public_group.add_argument(
385
+ "--default",
386
+ action='store_true',
387
+ default=False,
388
+ help=_('List the default volume type'),
389
+ )
390
+ public_group.add_argument(
391
+ "--public",
392
+ action="store_true",
393
+ dest="is_public",
394
+ default=None,
395
+ help=_("List only public types"),
396
+ )
397
+ public_group.add_argument(
398
+ "--private",
399
+ action="store_false",
400
+ dest="is_public",
401
+ default=None,
402
+ help=_("List only private types (admin only)"),
403
+ )
404
+ parser.add_argument(
405
+ "--encryption-type",
406
+ action="store_true",
407
+ help=_(
408
+ "Display encryption information for each volume type "
409
+ "(admin only)"
410
+ ),
411
+ )
412
+ parser.add_argument(
413
+ '--property',
414
+ metavar='<key=value>',
415
+ action=parseractions.KeyValueAction,
416
+ dest='properties',
417
+ help=_(
418
+ 'Filter by a property on the volume types '
419
+ '(repeat option to filter by multiple properties) '
420
+ '(admin only except for user-visible extra specs) '
421
+ '(supported by --os-volume-api-version 3.52 or above)'
422
+ ),
423
+ )
424
+ parser.add_argument(
425
+ '--multiattach',
426
+ action='store_true',
427
+ default=False,
428
+ help=_(
429
+ "List only volume types with multi-attach enabled "
430
+ "(this is an alias for '--property multiattach=<is> True') "
431
+ "(supported by --os-volume-api-version 3.52 or above)"
432
+ ),
433
+ )
434
+ parser.add_argument(
435
+ '--cacheable',
436
+ action='store_true',
437
+ default=False,
438
+ help=_(
439
+ "List only volume types with caching enabled "
440
+ "(this is an alias for '--property cacheable=<is> True') "
441
+ "(admin only) "
442
+ "(supported by --os-volume-api-version 3.52 or above)"
443
+ ),
444
+ )
445
+ parser.add_argument(
446
+ '--replicated',
447
+ action='store_true',
448
+ default=False,
449
+ help=_(
450
+ "List only volume types with replication enabled "
451
+ "(this is an alias for '--property replication_enabled=<is> True') " # noqa: E501
452
+ "(supported by --os-volume-api-version 3.52 or above)"
453
+ ),
454
+ )
455
+ parser.add_argument(
456
+ '--availability-zone',
457
+ action='append',
458
+ dest='availability_zones',
459
+ help=_(
460
+ "List only volume types with this availability configured "
461
+ "(this is an alias for '--property RESKEY:availability_zones:<az>') " # noqa: E501
462
+ "(repeat option to filter on multiple availability zones)"
463
+ ),
464
+ )
465
+ return parser
466
+
467
+ def take_action(self, parsed_args):
468
+ volume_client = self.app.client_manager.volume
469
+
470
+ if parsed_args.long:
471
+ columns = [
472
+ 'ID',
473
+ 'Name',
474
+ 'Is Public',
475
+ 'Description',
476
+ 'Extra Specs',
477
+ ]
478
+ column_headers = [
479
+ 'ID',
480
+ 'Name',
481
+ 'Is Public',
482
+ 'Description',
483
+ 'Properties',
484
+ ]
485
+ else:
486
+ columns = ['ID', 'Name', 'Is Public']
487
+ column_headers = ['ID', 'Name', 'Is Public']
488
+
489
+ if parsed_args.default:
490
+ data = [volume_client.volume_types.default()]
491
+ else:
492
+ search_opts = {}
493
+ properties = {}
494
+ if parsed_args.properties:
495
+ properties.update(parsed_args.properties)
496
+ if parsed_args.multiattach:
497
+ properties['multiattach'] = '<is> True'
498
+ if parsed_args.cacheable:
499
+ properties['cacheable'] = '<is> True'
500
+ if parsed_args.replicated:
501
+ properties['replication_enabled'] = '<is> True'
502
+ if parsed_args.availability_zones:
503
+ properties['RESKEY:availability_zones'] = ','.join(
504
+ parsed_args.availability_zones
505
+ )
506
+ if properties:
507
+ if volume_client.api_version < api_versions.APIVersion('3.52'):
508
+ msg = _(
509
+ "--os-volume-api-version 3.52 or greater is required "
510
+ "to use the '--property' option or any of the alias "
511
+ "options"
512
+ )
513
+ raise exceptions.CommandError(msg)
514
+
515
+ search_opts['extra_specs'] = properties
516
+
517
+ data = volume_client.volume_types.list(
518
+ search_opts=search_opts,
519
+ is_public=parsed_args.is_public,
520
+ )
521
+
522
+ formatters = {'Extra Specs': format_columns.DictColumn}
523
+
524
+ if parsed_args.encryption_type:
525
+ encryption = {}
526
+ for d in volume_client.volume_encryption_types.list():
527
+ volume_type_id = d._info['volume_type_id']
528
+ # remove some redundant information
529
+ del_key = [
530
+ 'deleted',
531
+ 'created_at',
532
+ 'updated_at',
533
+ 'deleted_at',
534
+ 'volume_type_id',
535
+ ]
536
+ for key in del_key:
537
+ d._info.pop(key, None)
538
+ # save the encryption information with their volume type ID
539
+ encryption[volume_type_id] = d._info
540
+ # We need to get volume type ID, then show encryption
541
+ # information according to the ID, so use "id" to keep
542
+ # difference to the real "ID" column.
543
+ columns += ['id']
544
+ column_headers += ['Encryption']
545
+
546
+ _EncryptionInfoColumn = functools.partial(
547
+ EncryptionInfoColumn, encryption_data=encryption
548
+ )
549
+ formatters['id'] = _EncryptionInfoColumn
550
+
551
+ return (
552
+ column_headers,
553
+ (
554
+ utils.get_item_properties(
555
+ s,
556
+ columns,
557
+ formatters=formatters,
558
+ )
559
+ for s in data
560
+ ),
561
+ )
562
+
563
+
564
+ class SetVolumeType(command.Command):
565
+ _description = _("Set volume type properties")
566
+
567
+ def get_parser(self, prog_name):
568
+ parser = super().get_parser(prog_name)
569
+ parser.add_argument(
570
+ 'volume_type',
571
+ metavar='<volume-type>',
572
+ help=_('Volume type to modify (name or ID)'),
573
+ )
574
+ parser.add_argument(
575
+ '--name',
576
+ metavar='<name>',
577
+ help=_('Set volume type name'),
578
+ )
579
+ parser.add_argument(
580
+ '--description',
581
+ metavar='<description>',
582
+ help=_('Set volume type description'),
583
+ )
584
+ parser.add_argument(
585
+ '--property',
586
+ metavar='<key=value>',
587
+ action=parseractions.KeyValueAction,
588
+ dest='properties',
589
+ help=_(
590
+ 'Set a property on this volume type '
591
+ '(repeat option to set multiple properties)'
592
+ ),
593
+ )
594
+ parser.add_argument(
595
+ '--multiattach',
596
+ action='store_true',
597
+ default=False,
598
+ help=_(
599
+ "Enable multi-attach for this volume type "
600
+ "(this is an alias for '--property multiattach=<is> True') "
601
+ "(requires driver support)"
602
+ ),
603
+ )
604
+ parser.add_argument(
605
+ '--cacheable',
606
+ action='store_true',
607
+ default=False,
608
+ help=_(
609
+ "Enable caching for this volume type "
610
+ "(this is an alias for '--property cacheable=<is> True') "
611
+ "(requires driver support)"
612
+ ),
613
+ )
614
+ parser.add_argument(
615
+ '--replicated',
616
+ action='store_true',
617
+ default=False,
618
+ help=_(
619
+ "Enabled replication for this volume type "
620
+ "(this is an alias for '--property replication_enabled=<is> True') " # noqa: E501
621
+ "(requires driver support)"
622
+ ),
623
+ )
624
+ parser.add_argument(
625
+ '--availability-zone',
626
+ action='append',
627
+ dest='availability_zones',
628
+ help=_(
629
+ "Set an availability zone for this volume type "
630
+ "(this is an alias for '--property RESKEY:availability_zones:<az>') " # noqa: E501
631
+ "(repeat option to set multiple availability zones)"
632
+ ),
633
+ )
634
+ parser.add_argument(
635
+ '--project',
636
+ metavar='<project>',
637
+ help=_(
638
+ 'Set volume type access to project (name or ID) '
639
+ '(admin only)'
640
+ ),
641
+ )
642
+ public_group = parser.add_mutually_exclusive_group()
643
+ public_group.add_argument(
644
+ '--public',
645
+ action='store_true',
646
+ dest='is_public',
647
+ default=None,
648
+ help=_('Volume type is accessible to the public'),
649
+ )
650
+ public_group.add_argument(
651
+ '--private',
652
+ action='store_false',
653
+ dest='is_public',
654
+ default=None,
655
+ help=_("Volume type is not accessible to the public"),
656
+ )
657
+ identity_common.add_project_domain_option_to_parser(parser)
658
+ # TODO(Huanxuan Ao): Add choices for each "--encryption-*" option.
659
+ parser.add_argument(
660
+ '--encryption-provider',
661
+ metavar='<provider>',
662
+ help=_(
663
+ 'Set the encryption provider format for '
664
+ 'this volume type (e.g "luks" or "plain") (admin only) '
665
+ '(This option is required when setting encryption type '
666
+ 'of a volume for the first time. Consider using other '
667
+ 'encryption options such as: "--encryption-cipher", '
668
+ '"--encryption-key-size" and '
669
+ '"--encryption-control-location")'
670
+ ),
671
+ )
672
+ parser.add_argument(
673
+ '--encryption-cipher',
674
+ metavar='<cipher>',
675
+ help=_(
676
+ 'Set the encryption algorithm or mode for this '
677
+ 'volume type (e.g "aes-xts-plain64") (admin only)'
678
+ ),
679
+ )
680
+ parser.add_argument(
681
+ '--encryption-key-size',
682
+ metavar='<key-size>',
683
+ type=int,
684
+ help=_(
685
+ 'Set the size of the encryption key of this '
686
+ 'volume type (e.g "128" or "256") (admin only)'
687
+ ),
688
+ )
689
+ parser.add_argument(
690
+ '--encryption-control-location',
691
+ metavar='<control-location>',
692
+ choices=['front-end', 'back-end'],
693
+ help=_(
694
+ 'Set the notional service where the encryption is '
695
+ 'performed ("front-end" or "back-end") (admin only) '
696
+ '(The default value for this option is "front-end" '
697
+ 'when setting encryption type of a volume for the '
698
+ 'first time. Consider using other encryption options '
699
+ 'such as: "--encryption-cipher", "--encryption-key-size" '
700
+ 'and "--encryption-provider")'
701
+ ),
702
+ )
703
+ return parser
704
+
705
+ def take_action(self, parsed_args):
706
+ volume_client = self.app.client_manager.volume
707
+ identity_client = self.app.client_manager.identity
708
+
709
+ volume_type = utils.find_resource(
710
+ volume_client.volume_types,
711
+ parsed_args.volume_type,
712
+ )
713
+
714
+ result = 0
715
+ kwargs = {}
716
+
717
+ if parsed_args.name:
718
+ kwargs['name'] = parsed_args.name
719
+
720
+ if parsed_args.description:
721
+ kwargs['description'] = parsed_args.description
722
+
723
+ if parsed_args.is_public is not None:
724
+ kwargs['is_public'] = parsed_args.is_public
725
+
726
+ if kwargs:
727
+ try:
728
+ volume_client.volume_types.update(volume_type.id, **kwargs)
729
+ except Exception as e:
730
+ LOG.error(
731
+ _(
732
+ "Failed to update volume type name or"
733
+ " description: %s"
734
+ ),
735
+ e,
736
+ )
737
+ result += 1
738
+
739
+ properties = {}
740
+
741
+ properties = {}
742
+ if parsed_args.properties:
743
+ properties.update(parsed_args.properties)
744
+ if parsed_args.multiattach:
745
+ properties['multiattach'] = '<is> True'
746
+ if parsed_args.cacheable:
747
+ properties['cacheable'] = '<is> True'
748
+ if parsed_args.replicated:
749
+ properties['replication_enabled'] = '<is> True'
750
+ if parsed_args.availability_zones:
751
+ properties['RESKEY:availability_zones'] = ','.join(
752
+ parsed_args.availability_zones
753
+ )
754
+ if properties:
755
+ try:
756
+ volume_type.set_keys(properties)
757
+ except Exception as e:
758
+ LOG.error(_("Failed to set volume type properties: %s"), e)
759
+ result += 1
760
+
761
+ if parsed_args.project:
762
+ project_info = None
763
+ try:
764
+ project_info = identity_common.find_project(
765
+ identity_client,
766
+ parsed_args.project,
767
+ parsed_args.project_domain,
768
+ )
769
+
770
+ volume_client.volume_type_access.add_project_access(
771
+ volume_type.id, project_info.id
772
+ )
773
+ except Exception as e:
774
+ LOG.error(
775
+ _("Failed to set volume type access to " "project: %s"), e
776
+ )
777
+ result += 1
778
+
779
+ if (
780
+ parsed_args.encryption_provider
781
+ or parsed_args.encryption_cipher
782
+ or parsed_args.encryption_key_size
783
+ or parsed_args.encryption_control_location
784
+ ):
785
+ try:
786
+ _set_encryption_type(volume_client, volume_type, parsed_args)
787
+ except Exception as e:
788
+ LOG.error(
789
+ _(
790
+ "Failed to set encryption information for this "
791
+ "volume type: %s"
792
+ ),
793
+ e,
794
+ )
795
+ result += 1
796
+
797
+ if result > 0:
798
+ raise exceptions.CommandError(
799
+ _("Command Failed: One or more of" " the operations failed")
800
+ )
801
+
802
+
803
+ class ShowVolumeType(command.ShowOne):
804
+ _description = _("Display volume type details")
805
+
806
+ def get_parser(self, prog_name):
807
+ parser = super().get_parser(prog_name)
808
+ parser.add_argument(
809
+ "volume_type",
810
+ metavar="<volume-type>",
811
+ help=_("Volume type to display (name or ID)"),
812
+ )
813
+ parser.add_argument(
814
+ "--encryption-type",
815
+ action="store_true",
816
+ help=_(
817
+ "Display encryption information of this volume type "
818
+ "(admin only)"
819
+ ),
820
+ )
821
+ return parser
822
+
823
+ def take_action(self, parsed_args):
824
+ volume_client = self.app.client_manager.volume
825
+ volume_type = utils.find_resource(
826
+ volume_client.volume_types, parsed_args.volume_type
827
+ )
828
+ properties = format_columns.DictColumn(
829
+ volume_type._info.pop('extra_specs', {})
830
+ )
831
+ volume_type._info.update({'properties': properties})
832
+ access_project_ids = None
833
+ if not volume_type.is_public:
834
+ try:
835
+ volume_type_access = volume_client.volume_type_access.list(
836
+ volume_type.id
837
+ )
838
+ project_ids = [
839
+ utils.get_field(item, 'project_id')
840
+ for item in volume_type_access
841
+ ]
842
+ # TODO(Rui Chen): This format list case can be removed after
843
+ # patch https://review.opendev.org/#/c/330223/ merged.
844
+ access_project_ids = format_columns.ListColumn(project_ids)
845
+ except Exception as e:
846
+ msg = _(
847
+ 'Failed to get access project list for volume type '
848
+ '%(type)s: %(e)s'
849
+ )
850
+ LOG.error(msg % {'type': volume_type.id, 'e': e})
851
+ volume_type._info.update({'access_project_ids': access_project_ids})
852
+ if parsed_args.encryption_type:
853
+ # show encryption type information for this volume type
854
+ try:
855
+ encryption = volume_client.volume_encryption_types.get(
856
+ volume_type.id
857
+ )
858
+ encryption._info.pop("volume_type_id", None)
859
+ volume_type._info.update(
860
+ {'encryption': format_columns.DictColumn(encryption._info)}
861
+ )
862
+ except Exception as e:
863
+ LOG.error(
864
+ _(
865
+ "Failed to display the encryption information "
866
+ "of this volume type: %s"
867
+ ),
868
+ e,
869
+ )
870
+ volume_type._info.pop("os-volume-type-access:is_public", None)
871
+ return zip(*sorted(volume_type._info.items()))
872
+
873
+
874
+ class UnsetVolumeType(command.Command):
875
+ _description = _("Unset volume type properties")
876
+
877
+ def get_parser(self, prog_name):
878
+ parser = super().get_parser(prog_name)
879
+ parser.add_argument(
880
+ 'volume_type',
881
+ metavar='<volume-type>',
882
+ help=_('Volume type to modify (name or ID)'),
883
+ )
884
+ parser.add_argument(
885
+ '--property',
886
+ metavar='<key>',
887
+ action='append',
888
+ dest='properties',
889
+ help=_(
890
+ 'Remove a property from this volume type '
891
+ '(repeat option to remove multiple properties)'
892
+ ),
893
+ )
894
+ parser.add_argument(
895
+ '--project',
896
+ metavar='<project>',
897
+ help=_(
898
+ 'Removes volume type access to project (name or ID) '
899
+ '(admin only)'
900
+ ),
901
+ )
902
+ identity_common.add_project_domain_option_to_parser(parser)
903
+ parser.add_argument(
904
+ "--encryption-type",
905
+ action="store_true",
906
+ help=_(
907
+ "Remove the encryption type for this volume type "
908
+ "(admin only)"
909
+ ),
910
+ )
911
+ return parser
912
+
913
+ def take_action(self, parsed_args):
914
+ volume_client = self.app.client_manager.volume
915
+ identity_client = self.app.client_manager.identity
916
+
917
+ volume_type = utils.find_resource(
918
+ volume_client.volume_types,
919
+ parsed_args.volume_type,
920
+ )
921
+
922
+ result = 0
923
+ if parsed_args.properties:
924
+ try:
925
+ volume_type.unset_keys(parsed_args.properties)
926
+ except Exception as e:
927
+ LOG.error(_("Failed to unset volume type properties: %s"), e)
928
+ result += 1
929
+
930
+ if parsed_args.project:
931
+ project_info = None
932
+ try:
933
+ project_info = identity_common.find_project(
934
+ identity_client,
935
+ parsed_args.project,
936
+ parsed_args.project_domain,
937
+ )
938
+
939
+ volume_client.volume_type_access.remove_project_access(
940
+ volume_type.id, project_info.id
941
+ )
942
+ except Exception as e:
943
+ LOG.error(
944
+ _(
945
+ "Failed to remove volume type access from "
946
+ "project: %s"
947
+ ),
948
+ e,
949
+ )
950
+ result += 1
951
+ if parsed_args.encryption_type:
952
+ try:
953
+ volume_client.volume_encryption_types.delete(volume_type)
954
+ except Exception as e:
955
+ LOG.error(
956
+ _(
957
+ "Failed to remove the encryption type for this "
958
+ "volume type: %s"
959
+ ),
960
+ e,
961
+ )
962
+ result += 1
963
+
964
+ if result > 0:
965
+ raise exceptions.CommandError(
966
+ _("Command Failed: One or more of" " the operations failed")
967
+ )