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,1109 @@
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
+ from unittest import mock
15
+ from unittest.mock import call
16
+
17
+ from osc_lib.cli import format_columns
18
+ from osc_lib import exceptions
19
+ from osc_lib import utils
20
+
21
+ from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
22
+ from openstackclient.tests.unit import utils as tests_utils
23
+ from openstackclient.tests.unit.volume.v3 import fakes as volume_fakes
24
+ from openstackclient.volume.v3 import volume_type
25
+
26
+
27
+ class TestType(volume_fakes.TestVolume):
28
+ def setUp(self):
29
+ super().setUp()
30
+
31
+ self.volume_types_mock = self.volume_client.volume_types
32
+ self.volume_types_mock.reset_mock()
33
+
34
+ self.volume_type_access_mock = self.volume_client.volume_type_access
35
+ self.volume_type_access_mock.reset_mock()
36
+
37
+ self.volume_encryption_types_mock = (
38
+ self.volume_client.volume_encryption_types
39
+ )
40
+ self.volume_encryption_types_mock.reset_mock()
41
+
42
+ self.projects_mock = self.identity_client.projects
43
+ self.projects_mock.reset_mock()
44
+
45
+
46
+ class TestTypeCreate(TestType):
47
+ def setUp(self):
48
+ super().setUp()
49
+
50
+ self.new_volume_type = volume_fakes.create_one_volume_type(
51
+ methods={'set_keys': None},
52
+ )
53
+ self.project = identity_fakes.FakeProject.create_one_project()
54
+ self.columns = (
55
+ 'description',
56
+ 'id',
57
+ 'is_public',
58
+ 'name',
59
+ )
60
+ self.data = (
61
+ self.new_volume_type.description,
62
+ self.new_volume_type.id,
63
+ True,
64
+ self.new_volume_type.name,
65
+ )
66
+
67
+ self.volume_types_mock.create.return_value = self.new_volume_type
68
+ self.projects_mock.get.return_value = self.project
69
+ # Get the command object to test
70
+ self.cmd = volume_type.CreateVolumeType(self.app, None)
71
+
72
+ def test_type_create_public(self):
73
+ arglist = [
74
+ "--description",
75
+ self.new_volume_type.description,
76
+ "--public",
77
+ self.new_volume_type.name,
78
+ ]
79
+ verifylist = [
80
+ ("description", self.new_volume_type.description),
81
+ ("is_public", True),
82
+ ("name", self.new_volume_type.name),
83
+ ]
84
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
85
+
86
+ columns, data = self.cmd.take_action(parsed_args)
87
+ self.volume_types_mock.create.assert_called_with(
88
+ self.new_volume_type.name,
89
+ description=self.new_volume_type.description,
90
+ is_public=True,
91
+ )
92
+
93
+ self.assertEqual(self.columns, columns)
94
+ self.assertCountEqual(self.data, data)
95
+
96
+ def test_type_create_private(self):
97
+ arglist = [
98
+ "--description",
99
+ self.new_volume_type.description,
100
+ "--private",
101
+ "--project",
102
+ self.project.id,
103
+ self.new_volume_type.name,
104
+ ]
105
+ verifylist = [
106
+ ("description", self.new_volume_type.description),
107
+ ("is_public", False),
108
+ ("project", self.project.id),
109
+ ("name", self.new_volume_type.name),
110
+ ]
111
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
112
+
113
+ columns, data = self.cmd.take_action(parsed_args)
114
+ self.volume_types_mock.create.assert_called_with(
115
+ self.new_volume_type.name,
116
+ description=self.new_volume_type.description,
117
+ is_public=False,
118
+ )
119
+
120
+ self.assertEqual(self.columns, columns)
121
+ self.assertCountEqual(self.data, data)
122
+
123
+ def test_type_create_with_properties(self):
124
+ arglist = [
125
+ '--property',
126
+ 'myprop=myvalue',
127
+ # this combination isn't viable server-side but is okay for testing
128
+ '--multiattach',
129
+ '--cacheable',
130
+ '--replicated',
131
+ '--availability-zone',
132
+ 'az1',
133
+ self.new_volume_type.name,
134
+ ]
135
+ verifylist = [
136
+ ('properties', {'myprop': 'myvalue'}),
137
+ ('multiattach', True),
138
+ ('cacheable', True),
139
+ ('replicated', True),
140
+ ('availability_zones', ['az1']),
141
+ ('name', self.new_volume_type.name),
142
+ ]
143
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
144
+
145
+ columns, data = self.cmd.take_action(parsed_args)
146
+ self.volume_types_mock.create.assert_called_with(
147
+ self.new_volume_type.name, description=None
148
+ )
149
+ self.new_volume_type.set_keys.assert_called_once_with(
150
+ {
151
+ 'myprop': 'myvalue',
152
+ 'multiattach': '<is> True',
153
+ 'cacheable': '<is> True',
154
+ 'replication_enabled': '<is> True',
155
+ 'RESKEY:availability_zones': 'az1',
156
+ }
157
+ )
158
+
159
+ self.columns += ('properties',)
160
+ self.data += (format_columns.DictColumn(None),)
161
+
162
+ self.assertEqual(self.columns, columns)
163
+ self.assertCountEqual(self.data, data)
164
+
165
+ def test_public_type_create_with_project_public(self):
166
+ arglist = [
167
+ '--project',
168
+ self.project.id,
169
+ self.new_volume_type.name,
170
+ ]
171
+ verifylist = [
172
+ ('is_public', None),
173
+ ('project', self.project.id),
174
+ ('name', self.new_volume_type.name),
175
+ ]
176
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
177
+
178
+ self.assertRaises(
179
+ exceptions.CommandError,
180
+ self.cmd.take_action,
181
+ parsed_args,
182
+ )
183
+
184
+ def test_type_create_with_encryption(self):
185
+ encryption_info = {
186
+ 'provider': 'LuksEncryptor',
187
+ 'cipher': 'aes-xts-plain64',
188
+ 'key_size': '128',
189
+ 'control_location': 'front-end',
190
+ }
191
+ encryption_type = volume_fakes.create_one_encryption_volume_type(
192
+ attrs=encryption_info,
193
+ )
194
+ self.new_volume_type = volume_fakes.create_one_volume_type(
195
+ attrs={'encryption': encryption_info},
196
+ )
197
+ self.volume_types_mock.create.return_value = self.new_volume_type
198
+ self.volume_encryption_types_mock.create.return_value = encryption_type
199
+ encryption_columns = (
200
+ 'description',
201
+ 'encryption',
202
+ 'id',
203
+ 'is_public',
204
+ 'name',
205
+ )
206
+ encryption_data = (
207
+ self.new_volume_type.description,
208
+ format_columns.DictColumn(encryption_info),
209
+ self.new_volume_type.id,
210
+ True,
211
+ self.new_volume_type.name,
212
+ )
213
+ arglist = [
214
+ '--encryption-provider',
215
+ 'LuksEncryptor',
216
+ '--encryption-cipher',
217
+ 'aes-xts-plain64',
218
+ '--encryption-key-size',
219
+ '128',
220
+ '--encryption-control-location',
221
+ 'front-end',
222
+ self.new_volume_type.name,
223
+ ]
224
+ verifylist = [
225
+ ('encryption_provider', 'LuksEncryptor'),
226
+ ('encryption_cipher', 'aes-xts-plain64'),
227
+ ('encryption_key_size', 128),
228
+ ('encryption_control_location', 'front-end'),
229
+ ('name', self.new_volume_type.name),
230
+ ]
231
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
232
+
233
+ columns, data = self.cmd.take_action(parsed_args)
234
+ self.volume_types_mock.create.assert_called_with(
235
+ self.new_volume_type.name,
236
+ description=None,
237
+ )
238
+ body = {
239
+ 'provider': 'LuksEncryptor',
240
+ 'cipher': 'aes-xts-plain64',
241
+ 'key_size': 128,
242
+ 'control_location': 'front-end',
243
+ }
244
+ self.volume_encryption_types_mock.create.assert_called_with(
245
+ self.new_volume_type,
246
+ body,
247
+ )
248
+ self.assertEqual(encryption_columns, columns)
249
+ self.assertCountEqual(encryption_data, data)
250
+
251
+
252
+ class TestTypeDelete(TestType):
253
+ volume_types = volume_fakes.create_volume_types(count=2)
254
+
255
+ def setUp(self):
256
+ super().setUp()
257
+
258
+ self.volume_types_mock.get = volume_fakes.get_volume_types(
259
+ self.volume_types,
260
+ )
261
+ self.volume_types_mock.delete.return_value = None
262
+
263
+ # Get the command object to mock
264
+ self.cmd = volume_type.DeleteVolumeType(self.app, None)
265
+
266
+ def test_type_delete(self):
267
+ arglist = [self.volume_types[0].id]
268
+ verifylist = [("volume_types", [self.volume_types[0].id])]
269
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
270
+
271
+ result = self.cmd.take_action(parsed_args)
272
+
273
+ self.volume_types_mock.delete.assert_called_with(self.volume_types[0])
274
+ self.assertIsNone(result)
275
+
276
+ def test_delete_multiple_types(self):
277
+ arglist = []
278
+ for t in self.volume_types:
279
+ arglist.append(t.id)
280
+ verifylist = [
281
+ ('volume_types', arglist),
282
+ ]
283
+
284
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
285
+ result = self.cmd.take_action(parsed_args)
286
+
287
+ calls = []
288
+ for t in self.volume_types:
289
+ calls.append(call(t))
290
+ self.volume_types_mock.delete.assert_has_calls(calls)
291
+ self.assertIsNone(result)
292
+
293
+ def test_delete_multiple_types_with_exception(self):
294
+ arglist = [
295
+ self.volume_types[0].id,
296
+ 'unexist_type',
297
+ ]
298
+ verifylist = [
299
+ ('volume_types', arglist),
300
+ ]
301
+
302
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
303
+
304
+ find_mock_result = [self.volume_types[0], exceptions.CommandError]
305
+ with mock.patch.object(
306
+ utils, 'find_resource', side_effect=find_mock_result
307
+ ) as find_mock:
308
+ try:
309
+ self.cmd.take_action(parsed_args)
310
+ self.fail('CommandError should be raised.')
311
+ except exceptions.CommandError as e:
312
+ self.assertEqual(
313
+ '1 of 2 volume types failed to delete.', str(e)
314
+ )
315
+ find_mock.assert_any_call(
316
+ self.volume_types_mock, self.volume_types[0].id
317
+ )
318
+ find_mock.assert_any_call(self.volume_types_mock, 'unexist_type')
319
+
320
+ self.assertEqual(2, find_mock.call_count)
321
+ self.volume_types_mock.delete.assert_called_once_with(
322
+ self.volume_types[0]
323
+ )
324
+
325
+
326
+ class TestTypeList(TestType):
327
+ volume_types = volume_fakes.create_volume_types()
328
+
329
+ columns = [
330
+ "ID",
331
+ "Name",
332
+ "Is Public",
333
+ ]
334
+ columns_long = columns + ["Description", "Properties"]
335
+ data_with_default_type = [(volume_types[0].id, volume_types[0].name, True)]
336
+ data = []
337
+ for t in volume_types:
338
+ data.append(
339
+ (
340
+ t.id,
341
+ t.name,
342
+ t.is_public,
343
+ )
344
+ )
345
+ data_long = []
346
+ for t in volume_types:
347
+ data_long.append(
348
+ (
349
+ t.id,
350
+ t.name,
351
+ t.is_public,
352
+ t.description,
353
+ format_columns.DictColumn(t.extra_specs),
354
+ )
355
+ )
356
+
357
+ def setUp(self):
358
+ super().setUp()
359
+
360
+ self.volume_types_mock.list.return_value = self.volume_types
361
+ self.volume_types_mock.default.return_value = self.volume_types[0]
362
+ # get the command to test
363
+ self.cmd = volume_type.ListVolumeType(self.app, None)
364
+
365
+ def test_type_list_without_options(self):
366
+ arglist = []
367
+ verifylist = [
368
+ ("long", False),
369
+ ("is_public", None),
370
+ ("default", False),
371
+ ]
372
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
373
+
374
+ columns, data = self.cmd.take_action(parsed_args)
375
+ self.volume_types_mock.list.assert_called_once_with(
376
+ search_opts={}, is_public=None
377
+ )
378
+ self.assertEqual(self.columns, columns)
379
+ self.assertCountEqual(self.data, list(data))
380
+
381
+ def test_type_list_with_options(self):
382
+ arglist = [
383
+ "--long",
384
+ "--public",
385
+ ]
386
+ verifylist = [
387
+ ("long", True),
388
+ ("is_public", True),
389
+ ("default", False),
390
+ ]
391
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
392
+
393
+ columns, data = self.cmd.take_action(parsed_args)
394
+ self.volume_types_mock.list.assert_called_once_with(
395
+ search_opts={}, is_public=True
396
+ )
397
+ self.assertEqual(self.columns_long, columns)
398
+ self.assertCountEqual(self.data_long, list(data))
399
+
400
+ def test_type_list_with_private_option(self):
401
+ arglist = [
402
+ "--private",
403
+ ]
404
+ verifylist = [
405
+ ("long", False),
406
+ ("is_public", False),
407
+ ("default", False),
408
+ ]
409
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
410
+
411
+ columns, data = self.cmd.take_action(parsed_args)
412
+ self.volume_types_mock.list.assert_called_once_with(
413
+ search_opts={}, is_public=False
414
+ )
415
+ self.assertEqual(self.columns, columns)
416
+ self.assertCountEqual(self.data, list(data))
417
+
418
+ def test_type_list_with_default_option(self):
419
+ arglist = [
420
+ "--default",
421
+ ]
422
+ verifylist = [
423
+ ("encryption_type", False),
424
+ ("long", False),
425
+ ("is_public", None),
426
+ ("default", True),
427
+ ]
428
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
429
+
430
+ columns, data = self.cmd.take_action(parsed_args)
431
+ self.volume_types_mock.default.assert_called_once_with()
432
+ self.assertEqual(self.columns, columns)
433
+ self.assertCountEqual(self.data_with_default_type, list(data))
434
+
435
+ def test_type_list_with_properties(self):
436
+ self.set_volume_api_version('3.52')
437
+
438
+ arglist = [
439
+ "--property",
440
+ "foo=bar",
441
+ "--multiattach",
442
+ "--cacheable",
443
+ "--replicated",
444
+ "--availability-zone",
445
+ "az1",
446
+ ]
447
+ verifylist = [
448
+ ("encryption_type", False),
449
+ ("long", False),
450
+ ("is_public", None),
451
+ ("default", False),
452
+ ("properties", {"foo": "bar"}),
453
+ ("multiattach", True),
454
+ ("cacheable", True),
455
+ ("replicated", True),
456
+ ("availability_zones", ["az1"]),
457
+ ]
458
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
459
+
460
+ columns, data = self.cmd.take_action(parsed_args)
461
+ self.volume_types_mock.list.assert_called_once_with(
462
+ search_opts={
463
+ "extra_specs": {
464
+ "foo": "bar",
465
+ "multiattach": "<is> True",
466
+ "cacheable": "<is> True",
467
+ "replication_enabled": "<is> True",
468
+ "RESKEY:availability_zones": "az1",
469
+ }
470
+ },
471
+ is_public=None,
472
+ )
473
+ self.assertEqual(self.columns, columns)
474
+ self.assertCountEqual(self.data, list(data))
475
+
476
+ def test_type_list_with_properties_pre_v352(self):
477
+ self.set_volume_api_version('3.51')
478
+
479
+ arglist = [
480
+ "--property",
481
+ "foo=bar",
482
+ ]
483
+ verifylist = [
484
+ ("encryption_type", False),
485
+ ("long", False),
486
+ ("is_public", None),
487
+ ("default", False),
488
+ ("properties", {"foo": "bar"}),
489
+ ]
490
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
491
+
492
+ exc = self.assertRaises(
493
+ exceptions.CommandError,
494
+ self.cmd.take_action,
495
+ parsed_args,
496
+ )
497
+ self.assertIn(
498
+ '--os-volume-api-version 3.52 or greater is required',
499
+ str(exc),
500
+ )
501
+
502
+ def test_type_list_with_encryption(self):
503
+ encryption_type = volume_fakes.create_one_encryption_volume_type(
504
+ attrs={'volume_type_id': self.volume_types[0].id},
505
+ )
506
+ encryption_info = {
507
+ 'provider': 'LuksEncryptor',
508
+ 'cipher': None,
509
+ 'key_size': None,
510
+ 'control_location': 'front-end',
511
+ }
512
+ encryption_columns = self.columns + [
513
+ "Encryption",
514
+ ]
515
+ encryption_data = []
516
+ encryption_data.append(
517
+ (
518
+ self.volume_types[0].id,
519
+ self.volume_types[0].name,
520
+ self.volume_types[0].is_public,
521
+ volume_type.EncryptionInfoColumn(
522
+ self.volume_types[0].id,
523
+ {self.volume_types[0].id: encryption_info},
524
+ ),
525
+ )
526
+ )
527
+ encryption_data.append(
528
+ (
529
+ self.volume_types[1].id,
530
+ self.volume_types[1].name,
531
+ self.volume_types[1].is_public,
532
+ volume_type.EncryptionInfoColumn(self.volume_types[1].id, {}),
533
+ )
534
+ )
535
+
536
+ self.volume_encryption_types_mock.list.return_value = [encryption_type]
537
+ arglist = [
538
+ "--encryption-type",
539
+ ]
540
+ verifylist = [
541
+ ("encryption_type", True),
542
+ ]
543
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
544
+
545
+ columns, data = self.cmd.take_action(parsed_args)
546
+ self.volume_encryption_types_mock.list.assert_called_once_with()
547
+ self.volume_types_mock.list.assert_called_once_with(
548
+ search_opts={}, is_public=None
549
+ )
550
+ self.assertEqual(encryption_columns, columns)
551
+ self.assertCountEqual(encryption_data, list(data))
552
+
553
+
554
+ class TestTypeSet(TestType):
555
+ def setUp(self):
556
+ super().setUp()
557
+
558
+ self.project = identity_fakes.FakeProject.create_one_project()
559
+ self.projects_mock.get.return_value = self.project
560
+
561
+ self.volume_type = volume_fakes.create_one_volume_type(
562
+ methods={'set_keys': None},
563
+ )
564
+ self.volume_types_mock.get.return_value = self.volume_type
565
+ self.volume_encryption_types_mock.create.return_value = None
566
+ self.volume_encryption_types_mock.update.return_value = None
567
+
568
+ self.cmd = volume_type.SetVolumeType(self.app, None)
569
+
570
+ def test_type_set(self):
571
+ arglist = [
572
+ '--name',
573
+ 'new_name',
574
+ '--description',
575
+ 'new_description',
576
+ '--private',
577
+ self.volume_type.id,
578
+ ]
579
+ verifylist = [
580
+ ('name', 'new_name'),
581
+ ('description', 'new_description'),
582
+ ('properties', None),
583
+ ('volume_type', self.volume_type.id),
584
+ ]
585
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
586
+
587
+ result = self.cmd.take_action(parsed_args)
588
+
589
+ kwargs = {
590
+ 'name': 'new_name',
591
+ 'description': 'new_description',
592
+ 'is_public': False,
593
+ }
594
+ self.volume_types_mock.update.assert_called_with(
595
+ self.volume_type.id, **kwargs
596
+ )
597
+ self.assertIsNone(result)
598
+
599
+ self.volume_type_access_mock.add_project_access.assert_not_called()
600
+ self.volume_encryption_types_mock.update.assert_not_called()
601
+ self.volume_encryption_types_mock.create.assert_not_called()
602
+
603
+ def test_type_set_property(self):
604
+ arglist = [
605
+ '--property',
606
+ 'myprop=myvalue',
607
+ # this combination isn't viable server-side but is okay for testing
608
+ '--multiattach',
609
+ '--cacheable',
610
+ '--replicated',
611
+ '--availability-zone',
612
+ 'az1',
613
+ self.volume_type.id,
614
+ ]
615
+ verifylist = [
616
+ ('name', None),
617
+ ('description', None),
618
+ ('properties', {'myprop': 'myvalue'}),
619
+ ('multiattach', True),
620
+ ('cacheable', True),
621
+ ('replicated', True),
622
+ ('availability_zones', ['az1']),
623
+ ('volume_type', self.volume_type.id),
624
+ ]
625
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
626
+
627
+ result = self.cmd.take_action(parsed_args)
628
+ self.assertIsNone(result)
629
+
630
+ self.volume_type.set_keys.assert_called_once_with(
631
+ {
632
+ 'myprop': 'myvalue',
633
+ 'multiattach': '<is> True',
634
+ 'cacheable': '<is> True',
635
+ 'replication_enabled': '<is> True',
636
+ 'RESKEY:availability_zones': 'az1',
637
+ }
638
+ )
639
+ self.volume_type_access_mock.add_project_access.assert_not_called()
640
+ self.volume_encryption_types_mock.update.assert_not_called()
641
+ self.volume_encryption_types_mock.create.assert_not_called()
642
+
643
+ def test_type_set_with_empty_project(self):
644
+ arglist = [
645
+ '--project',
646
+ '',
647
+ self.volume_type.id,
648
+ ]
649
+ verifylist = [
650
+ ('project', ''),
651
+ ('volume_type', self.volume_type.id),
652
+ ]
653
+
654
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
655
+
656
+ result = self.cmd.take_action(parsed_args)
657
+ self.assertIsNone(result)
658
+
659
+ self.volume_type.set_keys.assert_not_called()
660
+ self.volume_type_access_mock.add_project_access.assert_not_called()
661
+ self.volume_encryption_types_mock.update.assert_not_called()
662
+ self.volume_encryption_types_mock.create.assert_not_called()
663
+
664
+ def test_type_set_with_project(self):
665
+ arglist = [
666
+ '--project',
667
+ self.project.id,
668
+ self.volume_type.id,
669
+ ]
670
+ verifylist = [
671
+ ('project', self.project.id),
672
+ ('volume_type', self.volume_type.id),
673
+ ]
674
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
675
+
676
+ result = self.cmd.take_action(parsed_args)
677
+ self.assertIsNone(result)
678
+
679
+ self.volume_type.set_keys.assert_not_called()
680
+ self.volume_type_access_mock.add_project_access.assert_called_with(
681
+ self.volume_type.id,
682
+ self.project.id,
683
+ )
684
+ self.volume_encryption_types_mock.update.assert_not_called()
685
+ self.volume_encryption_types_mock.create.assert_not_called()
686
+
687
+ def test_type_set_with_new_encryption(self):
688
+ self.volume_encryption_types_mock.update.side_effect = (
689
+ exceptions.NotFound('NotFound')
690
+ )
691
+ arglist = [
692
+ '--encryption-provider',
693
+ 'LuksEncryptor',
694
+ '--encryption-cipher',
695
+ 'aes-xts-plain64',
696
+ '--encryption-key-size',
697
+ '128',
698
+ '--encryption-control-location',
699
+ 'front-end',
700
+ self.volume_type.id,
701
+ ]
702
+ verifylist = [
703
+ ('encryption_provider', 'LuksEncryptor'),
704
+ ('encryption_cipher', 'aes-xts-plain64'),
705
+ ('encryption_key_size', 128),
706
+ ('encryption_control_location', 'front-end'),
707
+ ('volume_type', self.volume_type.id),
708
+ ]
709
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
710
+
711
+ result = self.cmd.take_action(parsed_args)
712
+ self.assertIsNone(result)
713
+
714
+ body = {
715
+ 'provider': 'LuksEncryptor',
716
+ 'cipher': 'aes-xts-plain64',
717
+ 'key_size': 128,
718
+ 'control_location': 'front-end',
719
+ }
720
+ self.volume_encryption_types_mock.update.assert_called_with(
721
+ self.volume_type,
722
+ body,
723
+ )
724
+ self.volume_encryption_types_mock.create.assert_called_with(
725
+ self.volume_type,
726
+ body,
727
+ )
728
+
729
+ @mock.patch.object(utils, 'find_resource')
730
+ def test_type_set_with_existing_encryption(self, mock_find):
731
+ mock_find.side_effect = [self.volume_type, "existing_encryption_type"]
732
+ arglist = [
733
+ '--encryption-provider',
734
+ 'LuksEncryptor',
735
+ '--encryption-cipher',
736
+ 'aes-xts-plain64',
737
+ '--encryption-control-location',
738
+ 'front-end',
739
+ self.volume_type.id,
740
+ ]
741
+ verifylist = [
742
+ ('encryption_provider', 'LuksEncryptor'),
743
+ ('encryption_cipher', 'aes-xts-plain64'),
744
+ ('encryption_control_location', 'front-end'),
745
+ ('volume_type', self.volume_type.id),
746
+ ]
747
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
748
+
749
+ result = self.cmd.take_action(parsed_args)
750
+ self.assertIsNone(result)
751
+
752
+ self.volume_type.set_keys.assert_not_called()
753
+ self.volume_type_access_mock.add_project_access.assert_not_called()
754
+ body = {
755
+ 'provider': 'LuksEncryptor',
756
+ 'cipher': 'aes-xts-plain64',
757
+ 'control_location': 'front-end',
758
+ }
759
+ self.volume_encryption_types_mock.update.assert_called_with(
760
+ self.volume_type,
761
+ body,
762
+ )
763
+ self.volume_encryption_types_mock.create.assert_not_called()
764
+
765
+ def test_type_set_new_encryption_without_provider(self):
766
+ self.volume_encryption_types_mock.update.side_effect = (
767
+ exceptions.NotFound('NotFound')
768
+ )
769
+ arglist = [
770
+ '--encryption-cipher',
771
+ 'aes-xts-plain64',
772
+ '--encryption-key-size',
773
+ '128',
774
+ '--encryption-control-location',
775
+ 'front-end',
776
+ self.volume_type.id,
777
+ ]
778
+ verifylist = [
779
+ ('encryption_cipher', 'aes-xts-plain64'),
780
+ ('encryption_key_size', 128),
781
+ ('encryption_control_location', 'front-end'),
782
+ ('volume_type', self.volume_type.id),
783
+ ]
784
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
785
+
786
+ exc = self.assertRaises(
787
+ exceptions.CommandError,
788
+ self.cmd.take_action,
789
+ parsed_args,
790
+ )
791
+ self.assertEqual(
792
+ "Command Failed: One or more of the operations failed",
793
+ str(exc),
794
+ )
795
+
796
+ self.volume_type.set_keys.assert_not_called()
797
+ self.volume_type_access_mock.add_project_access.assert_not_called()
798
+ body = {
799
+ 'cipher': 'aes-xts-plain64',
800
+ 'key_size': 128,
801
+ 'control_location': 'front-end',
802
+ }
803
+ self.volume_encryption_types_mock.update.assert_called_with(
804
+ self.volume_type,
805
+ body,
806
+ )
807
+ self.volume_encryption_types_mock.create.assert_not_called()
808
+
809
+
810
+ class TestTypeShow(TestType):
811
+ columns = (
812
+ 'access_project_ids',
813
+ 'description',
814
+ 'id',
815
+ 'is_public',
816
+ 'name',
817
+ 'properties',
818
+ )
819
+
820
+ def setUp(self):
821
+ super().setUp()
822
+
823
+ self.volume_type = volume_fakes.create_one_volume_type()
824
+ self.data = (
825
+ None,
826
+ self.volume_type.description,
827
+ self.volume_type.id,
828
+ True,
829
+ self.volume_type.name,
830
+ format_columns.DictColumn(self.volume_type.extra_specs),
831
+ )
832
+
833
+ self.volume_types_mock.get.return_value = self.volume_type
834
+
835
+ # Get the command object to test
836
+ self.cmd = volume_type.ShowVolumeType(self.app, None)
837
+
838
+ def test_type_show(self):
839
+ arglist = [self.volume_type.id]
840
+ verifylist = [
841
+ ("encryption_type", False),
842
+ ("volume_type", self.volume_type.id),
843
+ ]
844
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
845
+
846
+ columns, data = self.cmd.take_action(parsed_args)
847
+ self.volume_types_mock.get.assert_called_with(self.volume_type.id)
848
+
849
+ self.assertEqual(self.columns, columns)
850
+ self.assertCountEqual(self.data, data)
851
+
852
+ def test_type_show_with_access(self):
853
+ arglist = [self.volume_type.id]
854
+ verifylist = [("volume_type", self.volume_type.id)]
855
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
856
+
857
+ private_type = volume_fakes.create_one_volume_type(
858
+ attrs={'is_public': False},
859
+ )
860
+ type_access_list = volume_fakes.create_one_type_access()
861
+ with mock.patch.object(
862
+ self.volume_types_mock,
863
+ 'get',
864
+ return_value=private_type,
865
+ ):
866
+ with mock.patch.object(
867
+ self.volume_type_access_mock,
868
+ 'list',
869
+ return_value=[type_access_list],
870
+ ):
871
+ columns, data = self.cmd.take_action(parsed_args)
872
+ self.volume_types_mock.get.assert_called_once_with(
873
+ self.volume_type.id
874
+ )
875
+ self.volume_type_access_mock.list.assert_called_once_with(
876
+ private_type.id
877
+ )
878
+
879
+ self.assertEqual(self.columns, columns)
880
+ private_type_data = (
881
+ format_columns.ListColumn([type_access_list.project_id]),
882
+ private_type.description,
883
+ private_type.id,
884
+ private_type.is_public,
885
+ private_type.name,
886
+ format_columns.DictColumn(private_type.extra_specs),
887
+ )
888
+ self.assertCountEqual(private_type_data, data)
889
+
890
+ def test_type_show_with_list_access_exec(self):
891
+ arglist = [self.volume_type.id]
892
+ verifylist = [("volume_type", self.volume_type.id)]
893
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
894
+
895
+ private_type = volume_fakes.create_one_volume_type(
896
+ attrs={'is_public': False},
897
+ )
898
+ with mock.patch.object(
899
+ self.volume_types_mock, 'get', return_value=private_type
900
+ ):
901
+ with mock.patch.object(
902
+ self.volume_type_access_mock, 'list', side_effect=Exception()
903
+ ):
904
+ columns, data = self.cmd.take_action(parsed_args)
905
+ self.volume_types_mock.get.assert_called_once_with(
906
+ self.volume_type.id
907
+ )
908
+ self.volume_type_access_mock.list.assert_called_once_with(
909
+ private_type.id
910
+ )
911
+
912
+ self.assertEqual(self.columns, columns)
913
+ private_type_data = (
914
+ None,
915
+ private_type.description,
916
+ private_type.id,
917
+ private_type.is_public,
918
+ private_type.name,
919
+ format_columns.DictColumn(private_type.extra_specs),
920
+ )
921
+ self.assertCountEqual(private_type_data, data)
922
+
923
+ def test_type_show_with_encryption(self):
924
+ encryption_type = volume_fakes.create_one_encryption_volume_type()
925
+ encryption_info = {
926
+ 'provider': 'LuksEncryptor',
927
+ 'cipher': None,
928
+ 'key_size': None,
929
+ 'control_location': 'front-end',
930
+ }
931
+ self.volume_type = volume_fakes.create_one_volume_type(
932
+ attrs={'encryption': encryption_info},
933
+ )
934
+ self.volume_types_mock.get.return_value = self.volume_type
935
+ self.volume_encryption_types_mock.get.return_value = encryption_type
936
+ encryption_columns = (
937
+ 'access_project_ids',
938
+ 'description',
939
+ 'encryption',
940
+ 'id',
941
+ 'is_public',
942
+ 'name',
943
+ 'properties',
944
+ )
945
+ encryption_data = (
946
+ None,
947
+ self.volume_type.description,
948
+ format_columns.DictColumn(encryption_info),
949
+ self.volume_type.id,
950
+ True,
951
+ self.volume_type.name,
952
+ format_columns.DictColumn(self.volume_type.extra_specs),
953
+ )
954
+ arglist = ['--encryption-type', self.volume_type.id]
955
+ verifylist = [
956
+ ('encryption_type', True),
957
+ ("volume_type", self.volume_type.id),
958
+ ]
959
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
960
+
961
+ columns, data = self.cmd.take_action(parsed_args)
962
+ self.volume_types_mock.get.assert_called_with(self.volume_type.id)
963
+ self.volume_encryption_types_mock.get.assert_called_with(
964
+ self.volume_type.id
965
+ )
966
+ self.assertEqual(encryption_columns, columns)
967
+ self.assertCountEqual(encryption_data, data)
968
+
969
+
970
+ class TestTypeUnset(TestType):
971
+ project = identity_fakes.FakeProject.create_one_project()
972
+ volume_type = volume_fakes.create_one_volume_type(
973
+ methods={'unset_keys': None},
974
+ )
975
+
976
+ def setUp(self):
977
+ super().setUp()
978
+
979
+ self.volume_types_mock.get.return_value = self.volume_type
980
+
981
+ # Return a project
982
+ self.projects_mock.get.return_value = self.project
983
+
984
+ # Get the command object to test
985
+ self.cmd = volume_type.UnsetVolumeType(self.app, None)
986
+
987
+ def test_type_unset(self):
988
+ arglist = [
989
+ '--property',
990
+ 'property',
991
+ '--property',
992
+ 'multi_property',
993
+ self.volume_type.id,
994
+ ]
995
+ verifylist = [
996
+ ('properties', ['property', 'multi_property']),
997
+ ('volume_type', self.volume_type.id),
998
+ ]
999
+
1000
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
1001
+
1002
+ result = self.cmd.take_action(parsed_args)
1003
+ self.volume_type.unset_keys.assert_called_once_with(
1004
+ ['property', 'multi_property']
1005
+ )
1006
+ self.assertIsNone(result)
1007
+
1008
+ def test_type_unset_project_access(self):
1009
+ arglist = [
1010
+ '--project',
1011
+ self.project.id,
1012
+ self.volume_type.id,
1013
+ ]
1014
+ verifylist = [
1015
+ ('project', self.project.id),
1016
+ ('volume_type', self.volume_type.id),
1017
+ ]
1018
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
1019
+
1020
+ result = self.cmd.take_action(parsed_args)
1021
+ self.assertIsNone(result)
1022
+
1023
+ self.volume_type_access_mock.remove_project_access.assert_called_with(
1024
+ self.volume_type.id,
1025
+ self.project.id,
1026
+ )
1027
+
1028
+ def test_type_unset_not_called_without_project_argument(self):
1029
+ arglist = [
1030
+ '--project',
1031
+ '',
1032
+ self.volume_type.id,
1033
+ ]
1034
+ verifylist = [
1035
+ ('encryption_type', False),
1036
+ ('project', ''),
1037
+ ('volume_type', self.volume_type.id),
1038
+ ]
1039
+
1040
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
1041
+
1042
+ result = self.cmd.take_action(parsed_args)
1043
+ self.assertIsNone(result)
1044
+ self.volume_encryption_types_mock.delete.assert_not_called()
1045
+ self.assertFalse(
1046
+ self.volume_type_access_mock.remove_project_access.called
1047
+ )
1048
+
1049
+ def test_type_unset_failed_with_missing_volume_type_argument(self):
1050
+ arglist = [
1051
+ '--project',
1052
+ 'identity_fakes.project_id',
1053
+ ]
1054
+ verifylist = [
1055
+ ('project', 'identity_fakes.project_id'),
1056
+ ]
1057
+
1058
+ self.assertRaises(
1059
+ tests_utils.ParserException,
1060
+ self.check_parser,
1061
+ self.cmd,
1062
+ arglist,
1063
+ verifylist,
1064
+ )
1065
+
1066
+ def test_type_unset_encryption_type(self):
1067
+ arglist = [
1068
+ '--encryption-type',
1069
+ self.volume_type.id,
1070
+ ]
1071
+ verifylist = [
1072
+ ('encryption_type', True),
1073
+ ('volume_type', self.volume_type.id),
1074
+ ]
1075
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
1076
+
1077
+ result = self.cmd.take_action(parsed_args)
1078
+ self.volume_encryption_types_mock.delete.assert_called_with(
1079
+ self.volume_type
1080
+ )
1081
+ self.assertIsNone(result)
1082
+
1083
+
1084
+ class TestColumns(TestType):
1085
+ def test_encryption_info_column_with_info(self):
1086
+ fake_volume_type = volume_fakes.create_one_volume_type()
1087
+ type_id = fake_volume_type.id
1088
+
1089
+ encryption_info = {
1090
+ 'provider': 'LuksEncryptor',
1091
+ 'cipher': None,
1092
+ 'key_size': None,
1093
+ 'control_location': 'front-end',
1094
+ }
1095
+ col = volume_type.EncryptionInfoColumn(
1096
+ type_id, {type_id: encryption_info}
1097
+ )
1098
+ self.assertEqual(
1099
+ utils.format_dict(encryption_info), col.human_readable()
1100
+ )
1101
+ self.assertEqual(encryption_info, col.machine_readable())
1102
+
1103
+ def test_encryption_info_column_without_info(self):
1104
+ fake_volume_type = volume_fakes.create_one_volume_type()
1105
+ type_id = fake_volume_type.id
1106
+
1107
+ col = volume_type.EncryptionInfoColumn(type_id, {})
1108
+ self.assertEqual('-', col.human_readable())
1109
+ self.assertIsNone(col.machine_readable())