python-openstackclient 8.1.0__py3-none-any.whl → 8.3.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 (241) hide show
  1. openstackclient/api/compute_v2.py +2 -2
  2. openstackclient/api/object_store_v1.py +4 -1
  3. openstackclient/api/volume_v2.py +60 -0
  4. openstackclient/api/volume_v3.py +60 -0
  5. openstackclient/command.py +27 -0
  6. openstackclient/common/availability_zone.py +1 -1
  7. openstackclient/common/clientmanager.py +59 -21
  8. openstackclient/common/configuration.py +1 -1
  9. openstackclient/common/extension.py +1 -1
  10. openstackclient/common/limits.py +1 -1
  11. openstackclient/common/module.py +4 -2
  12. openstackclient/common/project_cleanup.py +10 -8
  13. openstackclient/common/quota.py +23 -6
  14. openstackclient/common/versions.py +1 -2
  15. openstackclient/compute/v2/agent.py +1 -1
  16. openstackclient/compute/v2/aggregate.py +6 -5
  17. openstackclient/compute/v2/console.py +5 -3
  18. openstackclient/compute/v2/console_connection.py +1 -1
  19. openstackclient/compute/v2/flavor.py +15 -2
  20. openstackclient/compute/v2/host.py +1 -1
  21. openstackclient/compute/v2/hypervisor.py +1 -1
  22. openstackclient/compute/v2/hypervisor_stats.py +1 -1
  23. openstackclient/compute/v2/keypair.py +1 -1
  24. openstackclient/compute/v2/server.py +77 -30
  25. openstackclient/compute/v2/server_backup.py +1 -1
  26. openstackclient/compute/v2/server_event.py +1 -1
  27. openstackclient/compute/v2/server_group.py +4 -2
  28. openstackclient/compute/v2/server_image.py +1 -1
  29. openstackclient/compute/v2/server_migration.py +1 -1
  30. openstackclient/compute/v2/server_volume.py +1 -1
  31. openstackclient/compute/v2/service.py +1 -1
  32. openstackclient/compute/v2/usage.py +6 -4
  33. openstackclient/identity/common.py +10 -14
  34. openstackclient/identity/v2_0/catalog.py +3 -2
  35. openstackclient/identity/v2_0/ec2creds.py +1 -1
  36. openstackclient/identity/v2_0/endpoint.py +1 -1
  37. openstackclient/identity/v2_0/project.py +17 -7
  38. openstackclient/identity/v2_0/role.py +1 -1
  39. openstackclient/identity/v2_0/role_assignment.py +3 -3
  40. openstackclient/identity/v2_0/service.py +1 -1
  41. openstackclient/identity/v2_0/token.py +1 -1
  42. openstackclient/identity/v2_0/user.py +2 -2
  43. openstackclient/identity/v3/access_rule.py +16 -4
  44. openstackclient/identity/v3/application_credential.py +116 -95
  45. openstackclient/identity/v3/catalog.py +3 -3
  46. openstackclient/identity/v3/consumer.py +1 -1
  47. openstackclient/identity/v3/credential.py +1 -1
  48. openstackclient/identity/v3/domain.py +15 -10
  49. openstackclient/identity/v3/ec2creds.py +1 -1
  50. openstackclient/identity/v3/endpoint.py +33 -12
  51. openstackclient/identity/v3/endpoint_group.py +1 -1
  52. openstackclient/identity/v3/federation_protocol.py +1 -1
  53. openstackclient/identity/v3/group.py +11 -5
  54. openstackclient/identity/v3/identity_provider.py +12 -10
  55. openstackclient/identity/v3/implied_role.py +1 -1
  56. openstackclient/identity/v3/limit.py +1 -1
  57. openstackclient/identity/v3/mapping.py +1 -1
  58. openstackclient/identity/v3/policy.py +1 -1
  59. openstackclient/identity/v3/project.py +34 -22
  60. openstackclient/identity/v3/region.py +1 -1
  61. openstackclient/identity/v3/registered_limit.py +16 -11
  62. openstackclient/identity/v3/role.py +27 -41
  63. openstackclient/identity/v3/role_assignment.py +12 -23
  64. openstackclient/identity/v3/service.py +1 -1
  65. openstackclient/identity/v3/service_provider.py +1 -1
  66. openstackclient/identity/v3/tag.py +3 -2
  67. openstackclient/identity/v3/token.py +3 -2
  68. openstackclient/identity/v3/trust.py +4 -2
  69. openstackclient/identity/v3/unscoped_saml.py +1 -1
  70. openstackclient/identity/v3/user.py +22 -13
  71. openstackclient/image/v1/image.py +35 -17
  72. openstackclient/image/v2/cache.py +11 -7
  73. openstackclient/image/v2/image.py +62 -12
  74. openstackclient/image/v2/info.py +1 -1
  75. openstackclient/image/v2/metadef_namespaces.py +1 -1
  76. openstackclient/image/v2/metadef_objects.py +9 -3
  77. openstackclient/image/v2/metadef_properties.py +11 -3
  78. openstackclient/image/v2/metadef_resource_type_association.py +1 -1
  79. openstackclient/image/v2/metadef_resource_types.py +1 -1
  80. openstackclient/image/v2/task.py +1 -1
  81. openstackclient/network/common.py +10 -9
  82. openstackclient/network/v2/address_group.py +4 -3
  83. openstackclient/network/v2/address_scope.py +8 -6
  84. openstackclient/network/v2/default_security_group_rule.py +9 -8
  85. openstackclient/network/v2/floating_ip.py +16 -9
  86. openstackclient/network/v2/floating_ip_port_forwarding.py +9 -6
  87. openstackclient/network/v2/ip_availability.py +7 -4
  88. openstackclient/network/v2/l3_conntrack_helper.py +11 -4
  89. openstackclient/network/v2/local_ip.py +13 -7
  90. openstackclient/network/v2/local_ip_association.py +7 -4
  91. openstackclient/network/v2/ndp_proxy.py +13 -6
  92. openstackclient/network/v2/network.py +33 -16
  93. openstackclient/network/v2/network_agent.py +5 -5
  94. openstackclient/network/v2/network_auto_allocated_topology.py +1 -1
  95. openstackclient/network/v2/network_flavor.py +1 -1
  96. openstackclient/network/v2/network_flavor_profile.py +1 -1
  97. openstackclient/network/v2/network_meter.py +1 -1
  98. openstackclient/network/v2/network_meter_rule.py +1 -1
  99. openstackclient/network/v2/network_qos_policy.py +7 -5
  100. openstackclient/network/v2/network_qos_rule.py +1 -1
  101. openstackclient/network/v2/network_qos_rule_type.py +1 -1
  102. openstackclient/network/v2/network_rbac.py +8 -5
  103. openstackclient/network/v2/network_segment.py +2 -2
  104. openstackclient/network/v2/network_segment_range.py +13 -6
  105. openstackclient/network/v2/network_service_provider.py +1 -1
  106. openstackclient/network/v2/network_trunk.py +65 -42
  107. openstackclient/network/v2/port.py +38 -20
  108. openstackclient/network/v2/router.py +19 -8
  109. openstackclient/network/v2/security_group.py +52 -7
  110. openstackclient/network/v2/security_group_rule.py +27 -4
  111. openstackclient/network/v2/subnet.py +17 -18
  112. openstackclient/network/v2/subnet_pool.py +11 -9
  113. openstackclient/network/v2/taas/__init__.py +0 -0
  114. openstackclient/network/v2/taas/tap_flow.py +245 -0
  115. openstackclient/network/v2/taas/tap_mirror.py +237 -0
  116. openstackclient/network/v2/taas/tap_service.py +211 -0
  117. openstackclient/object/v1/account.py +1 -1
  118. openstackclient/object/v1/container.py +1 -1
  119. openstackclient/object/v1/object.py +1 -1
  120. openstackclient/shell.py +18 -8
  121. openstackclient/tests/functional/identity/v3/test_access_rule.py +1 -1
  122. openstackclient/tests/functional/identity/v3/test_application_credential.py +7 -7
  123. openstackclient/tests/functional/identity/v3/test_catalog.py +42 -23
  124. openstackclient/tests/functional/identity/v3/test_role_assignment.py +174 -0
  125. openstackclient/tests/functional/image/v2/test_cache.py +54 -0
  126. openstackclient/tests/functional/image/v2/test_image.py +36 -14
  127. openstackclient/tests/functional/image/v2/test_metadef_resource_type.py +55 -0
  128. openstackclient/tests/functional/volume/v2/test_volume.py +1 -1
  129. openstackclient/tests/functional/volume/v3/test_volume.py +2 -2
  130. openstackclient/tests/unit/api/test_volume_v2.py +124 -0
  131. openstackclient/tests/unit/api/test_volume_v3.py +124 -0
  132. openstackclient/tests/unit/common/test_command.py +1 -1
  133. openstackclient/tests/unit/common/test_extension.py +2 -3
  134. openstackclient/tests/unit/common/test_module.py +14 -7
  135. openstackclient/tests/unit/common/test_quota.py +20 -0
  136. openstackclient/tests/unit/compute/v2/test_aggregate.py +5 -3
  137. openstackclient/tests/unit/compute/v2/test_console.py +1 -4
  138. openstackclient/tests/unit/compute/v2/test_flavor.py +160 -177
  139. openstackclient/tests/unit/compute/v2/test_hypervisor_stats.py +1 -9
  140. openstackclient/tests/unit/compute/v2/test_server.py +406 -81
  141. openstackclient/tests/unit/compute/v2/test_server_backup.py +1 -3
  142. openstackclient/tests/unit/compute/v2/test_service.py +1 -3
  143. openstackclient/tests/unit/fakes.py +35 -134
  144. openstackclient/tests/unit/identity/test_common.py +100 -0
  145. openstackclient/tests/unit/identity/v2_0/test_project.py +4 -4
  146. openstackclient/tests/unit/identity/v3/fakes.py +10 -2
  147. openstackclient/tests/unit/identity/v3/test_application_credential.py +50 -44
  148. openstackclient/tests/unit/identity/v3/test_domain.py +3 -3
  149. openstackclient/tests/unit/identity/v3/test_endpoint.py +1 -1
  150. openstackclient/tests/unit/identity/v3/test_group.py +4 -2
  151. openstackclient/tests/unit/identity/v3/test_identity_provider.py +10 -10
  152. openstackclient/tests/unit/identity/v3/test_oauth.py +1 -1
  153. openstackclient/tests/unit/identity/v3/test_project.py +31 -54
  154. openstackclient/tests/unit/identity/v3/test_registered_limit.py +2 -2
  155. openstackclient/tests/unit/identity/v3/test_role.py +3 -90
  156. openstackclient/tests/unit/identity/v3/test_user.py +7 -51
  157. openstackclient/tests/unit/image/v1/test_image.py +47 -0
  158. openstackclient/tests/unit/image/v2/test_image.py +190 -9
  159. openstackclient/tests/unit/image/v2/test_metadef_objects.py +22 -0
  160. openstackclient/tests/unit/image/v2/test_metadef_properties.py +24 -10
  161. openstackclient/tests/unit/network/test_common.py +9 -13
  162. openstackclient/tests/unit/network/v2/fakes.py +1 -0
  163. openstackclient/tests/unit/network/v2/taas/__init__.py +0 -0
  164. openstackclient/tests/unit/network/v2/taas/test_osc_tap_flow.py +276 -0
  165. openstackclient/tests/unit/network/v2/taas/test_osc_tap_mirror.py +288 -0
  166. openstackclient/tests/unit/network/v2/taas/test_osc_tap_service.py +271 -0
  167. openstackclient/tests/unit/network/v2/test_address_group.py +19 -22
  168. openstackclient/tests/unit/network/v2/test_address_scope.py +10 -15
  169. openstackclient/tests/unit/network/v2/test_default_security_group_rule.py +38 -49
  170. openstackclient/tests/unit/network/v2/test_floating_ip_network.py +21 -27
  171. openstackclient/tests/unit/network/v2/test_floating_ip_port_forwarding.py +21 -18
  172. openstackclient/tests/unit/network/v2/test_ip_availability.py +6 -8
  173. openstackclient/tests/unit/network/v2/test_l3_conntrack_helper.py +6 -15
  174. openstackclient/tests/unit/network/v2/test_local_ip.py +12 -23
  175. openstackclient/tests/unit/network/v2/test_local_ip_association.py +13 -18
  176. openstackclient/tests/unit/network/v2/test_ndp_proxy.py +13 -23
  177. openstackclient/tests/unit/network/v2/test_network.py +41 -37
  178. openstackclient/tests/unit/network/v2/test_network_agent.py +13 -20
  179. openstackclient/tests/unit/network/v2/test_network_auto_allocated_topology.py +5 -8
  180. openstackclient/tests/unit/network/v2/test_network_flavor.py +14 -26
  181. openstackclient/tests/unit/network/v2/test_network_flavor_profile.py +14 -17
  182. openstackclient/tests/unit/network/v2/test_network_meter.py +7 -17
  183. openstackclient/tests/unit/network/v2/test_network_meter_rule.py +10 -20
  184. openstackclient/tests/unit/network/v2/test_network_qos_policy.py +7 -13
  185. openstackclient/tests/unit/network/v2/test_network_qos_rule.py +44 -54
  186. openstackclient/tests/unit/network/v2/test_network_qos_rule_type.py +2 -7
  187. openstackclient/tests/unit/network/v2/test_network_rbac.py +21 -36
  188. openstackclient/tests/unit/network/v2/test_network_segment.py +13 -29
  189. openstackclient/tests/unit/network/v2/test_network_segment_range.py +20 -19
  190. openstackclient/tests/unit/network/v2/test_network_service_provider.py +1 -4
  191. openstackclient/tests/unit/network/v2/test_network_trunk.py +52 -47
  192. openstackclient/tests/unit/network/v2/test_port.py +113 -84
  193. openstackclient/tests/unit/network/v2/test_router.py +104 -126
  194. openstackclient/tests/unit/network/v2/test_security_group_network.py +25 -26
  195. openstackclient/tests/unit/network/v2/test_security_group_rule_network.py +66 -18
  196. openstackclient/tests/unit/network/v2/test_subnet.py +35 -46
  197. openstackclient/tests/unit/network/v2/test_subnet_pool.py +21 -33
  198. openstackclient/tests/unit/volume/test_find_resource.py +4 -13
  199. openstackclient/tests/unit/volume/v2/test_volume.py +358 -305
  200. openstackclient/tests/unit/volume/v2/test_volume_backup.py +3 -1
  201. openstackclient/tests/unit/volume/v3/test_volume.py +443 -415
  202. openstackclient/tests/unit/volume/v3/test_volume_backup.py +9 -0
  203. openstackclient/volume/client.py +7 -17
  204. openstackclient/volume/v2/backup_record.py +1 -1
  205. openstackclient/volume/v2/consistency_group.py +1 -1
  206. openstackclient/volume/v2/consistency_group_snapshot.py +1 -1
  207. openstackclient/volume/v2/qos_specs.py +1 -1
  208. openstackclient/volume/v2/service.py +2 -2
  209. openstackclient/volume/v2/volume.py +80 -54
  210. openstackclient/volume/v2/volume_backend.py +1 -1
  211. openstackclient/volume/v2/volume_backup.py +5 -3
  212. openstackclient/volume/v2/volume_host.py +1 -2
  213. openstackclient/volume/v2/volume_snapshot.py +2 -2
  214. openstackclient/volume/v2/volume_transfer_request.py +1 -1
  215. openstackclient/volume/v2/volume_type.py +11 -6
  216. openstackclient/volume/v3/block_storage_cleanup.py +1 -1
  217. openstackclient/volume/v3/block_storage_cluster.py +1 -1
  218. openstackclient/volume/v3/block_storage_log_level.py +1 -1
  219. openstackclient/volume/v3/block_storage_manage.py +1 -1
  220. openstackclient/volume/v3/block_storage_resource_filter.py +1 -1
  221. openstackclient/volume/v3/service.py +2 -2
  222. openstackclient/volume/v3/volume.py +104 -77
  223. openstackclient/volume/v3/volume_attachment.py +6 -5
  224. openstackclient/volume/v3/volume_backup.py +18 -3
  225. openstackclient/volume/v3/volume_group.py +2 -2
  226. openstackclient/volume/v3/volume_group_snapshot.py +1 -1
  227. openstackclient/volume/v3/volume_group_type.py +1 -1
  228. openstackclient/volume/v3/volume_message.py +1 -1
  229. openstackclient/volume/v3/volume_snapshot.py +2 -2
  230. openstackclient/volume/v3/volume_transfer_request.py +1 -1
  231. openstackclient/volume/v3/volume_type.py +15 -9
  232. {python_openstackclient-8.1.0.dist-info → python_openstackclient-8.3.0.dist-info}/METADATA +19 -17
  233. {python_openstackclient-8.1.0.dist-info → python_openstackclient-8.3.0.dist-info}/RECORD +239 -224
  234. {python_openstackclient-8.1.0.dist-info → python_openstackclient-8.3.0.dist-info}/WHEEL +1 -1
  235. {python_openstackclient-8.1.0.dist-info → python_openstackclient-8.3.0.dist-info}/entry_points.txt +15 -0
  236. {python_openstackclient-8.1.0.dist-info → python_openstackclient-8.3.0.dist-info/licenses}/AUTHORS +15 -0
  237. python_openstackclient-8.3.0.dist-info/pbr.json +1 -0
  238. openstackclient/tests/unit/common/test_logs.py +0 -221
  239. python_openstackclient-8.1.0.dist-info/pbr.json +0 -1
  240. {python_openstackclient-8.1.0.dist-info → python_openstackclient-8.3.0.dist-info/licenses}/LICENSE +0 -0
  241. {python_openstackclient-8.1.0.dist-info → python_openstackclient-8.3.0.dist-info}/top_level.txt +0 -0
@@ -15,10 +15,10 @@
15
15
 
16
16
  import logging
17
17
 
18
- from osc_lib.command import command
19
18
  from osc_lib import exceptions
20
19
  from osc_lib import utils
21
20
 
21
+ from openstackclient import command
22
22
  from openstackclient.i18n import _
23
23
 
24
24
 
@@ -114,6 +114,7 @@ def add_tag_option_to_parser_for_set(parser, resource_name):
114
114
  parser.add_argument(
115
115
  '--remove-tag',
116
116
  action='append',
117
+ dest='remove_tags',
117
118
  metavar='<tag>',
118
119
  default=[],
119
120
  help=_(
@@ -128,8 +129,8 @@ def update_tags_in_args(parsed_args, obj, args):
128
129
  if parsed_args.clear_tags:
129
130
  args['tags'] = []
130
131
  obj.tags = []
131
- if parsed_args.remove_tag:
132
- args['tags'] = sorted(set(obj.tags) - set(parsed_args.remove_tag))
132
+ if parsed_args.remove_tags:
133
+ args['tags'] = sorted(set(obj.tags) - set(parsed_args.remove_tags))
133
134
  return
134
135
  if parsed_args.tags:
135
136
  args['tags'] = sorted(set(obj.tags).union(set(parsed_args.tags)))
@@ -15,10 +15,10 @@
15
15
 
16
16
  """Identity v3 Token action implementations"""
17
17
 
18
- from osc_lib.command import command
19
18
  from osc_lib import exceptions
20
19
  from osc_lib import utils
21
20
 
21
+ from openstackclient import command
22
22
  from openstackclient.i18n import _
23
23
  from openstackclient.identity import common
24
24
 
@@ -37,6 +37,7 @@ class AuthorizeRequestToken(command.ShowOne):
37
37
  parser.add_argument(
38
38
  '--role',
39
39
  metavar='<role>',
40
+ dest='roles',
40
41
  action='append',
41
42
  default=[],
42
43
  required=True,
@@ -52,7 +53,7 @@ class AuthorizeRequestToken(command.ShowOne):
52
53
 
53
54
  # NOTE(stevemar): We want a list of role ids
54
55
  roles = []
55
- for role in parsed_args.role:
56
+ for role in parsed_args.roles:
56
57
  role_id = utils.find_resource(
57
58
  identity_client.roles,
58
59
  role,
@@ -18,10 +18,10 @@ import itertools
18
18
  import logging
19
19
 
20
20
  from openstack import exceptions as sdk_exceptions
21
- from osc_lib.command import command
22
21
  from osc_lib import exceptions
23
22
  from osc_lib import utils
24
23
 
24
+ from openstackclient import command
25
25
  from openstackclient.i18n import _
26
26
  from openstackclient.identity import common
27
27
 
@@ -179,7 +179,9 @@ class CreateTrust(command.ShowOne):
179
179
  roles = []
180
180
  for role in parsed_args.roles:
181
181
  try:
182
- role_id = identity_client.find_role(role).id
182
+ role_id = identity_client.find_role(
183
+ role, ignore_missing=False
184
+ ).id
183
185
  except sdk_exceptions.ForbiddenException:
184
186
  role_id = role
185
187
  roles.append({"id": role_id})
@@ -17,9 +17,9 @@ The first step of federated auth is to fetch an unscoped token. From there,
17
17
  the user can list domains and projects they are allowed to access, and request
18
18
  a scoped token."""
19
19
 
20
- from osc_lib.command import command
21
20
  from osc_lib import utils
22
21
 
22
+ from openstackclient import command
23
23
  from openstackclient.i18n import _
24
24
 
25
25
 
@@ -20,10 +20,10 @@ import logging
20
20
  import typing as ty
21
21
 
22
22
  from openstack import exceptions as sdk_exc
23
- from osc_lib.command import command
24
23
  from osc_lib import exceptions
25
24
  from osc_lib import utils
26
25
 
26
+ from openstackclient import command
27
27
  from openstackclient.i18n import _
28
28
  from openstackclient.identity import common
29
29
 
@@ -82,9 +82,9 @@ def _get_options_for_user(identity_client, parsed_args):
82
82
  options['multi_factor_auth_enabled'] = True
83
83
  if parsed_args.disable_multi_factor_auth:
84
84
  options['multi_factor_auth_enabled'] = False
85
- if parsed_args.multi_factor_auth_rule:
85
+ if parsed_args.multi_factor_auth_rules:
86
86
  auth_rules = [
87
- rule.split(",") for rule in parsed_args.multi_factor_auth_rule
87
+ rule.split(",") for rule in parsed_args.multi_factor_auth_rules
88
88
  ]
89
89
  if auth_rules:
90
90
  options['multi_factor_auth_rules'] = auth_rules
@@ -175,7 +175,8 @@ def _add_user_options(parser):
175
175
  parser.add_argument(
176
176
  '--multi-factor-auth-rule',
177
177
  metavar='<rule>',
178
- action="append",
178
+ dest='multi_factor_auth_rules',
179
+ action='append',
179
180
  default=[],
180
181
  help=_(
181
182
  'Set multi-factor auth rules. For example, to set a rule '
@@ -298,6 +299,9 @@ class CreateUser(command.ShowOne):
298
299
  "when a user does not have a password."
299
300
  )
300
301
  )
302
+ else:
303
+ kwargs['password'] = password
304
+
301
305
  options = _get_options_for_user(identity_client, parsed_args)
302
306
  if options:
303
307
  kwargs['options'] = options
@@ -306,7 +310,6 @@ class CreateUser(command.ShowOne):
306
310
  user = identity_client.create_user(
307
311
  is_enabled=is_enabled,
308
312
  name=parsed_args.name,
309
- password=password,
310
313
  **kwargs,
311
314
  )
312
315
  except sdk_exc.ConflictException:
@@ -420,7 +423,8 @@ class ListUser(command.Lister):
420
423
  dest='is_enabled',
421
424
  default=None,
422
425
  help=_(
423
- 'List only enabled users, does nothing with --project and --group'
426
+ 'List only enabled users, does nothing with '
427
+ '--project and --group'
424
428
  ),
425
429
  )
426
430
  parser.add_argument(
@@ -429,7 +433,8 @@ class ListUser(command.Lister):
429
433
  dest='is_enabled',
430
434
  default=None,
431
435
  help=_(
432
- 'List only disabled users, does nothing with --project and --group'
436
+ 'List only disabled users, does nothing with '
437
+ '--project and --group'
433
438
  ),
434
439
  )
435
440
  return parser
@@ -441,6 +446,7 @@ class ListUser(command.Lister):
441
446
  if parsed_args.domain:
442
447
  domain = identity_client.find_domain(
443
448
  name_or_id=parsed_args.domain,
449
+ ignore_missing=False,
444
450
  ).id
445
451
 
446
452
  group = None
@@ -467,15 +473,13 @@ class ListUser(command.Lister):
467
473
  ignore_missing=False,
468
474
  ).id
469
475
 
470
- assignments = identity_client.role_assignments_filter(
471
- project=project
472
- )
473
-
474
476
  # NOTE(stevemar): If a user has more than one role on a project
475
477
  # then they will have two entries in the returned data. Since we
476
478
  # are looking for any role, let's just track unique user IDs.
477
479
  user_ids = set()
478
- for assignment in assignments:
480
+ for assignment in identity_client.role_assignments(
481
+ scope_project_id=project
482
+ ):
479
483
  if assignment.user:
480
484
  user_ids.add(assignment.user['id'])
481
485
 
@@ -689,7 +693,12 @@ class SetPasswordUser(command.Command):
689
693
  def take_action(self, parsed_args):
690
694
  identity_client = self.app.client_manager.sdk_connection.identity
691
695
  conn = self.app.client_manager.sdk_connection
692
- user_id = conn.config.get_auth().get_user_id(conn.identity)
696
+ auth = conn.config.get_auth()
697
+ if auth is None:
698
+ # this will never happen
699
+ raise exceptions.CommandError('invalid authentication info')
700
+
701
+ user_id = auth.get_user_id(conn.identity)
693
702
 
694
703
  # FIXME(gyee): there are two scenarios:
695
704
  #
@@ -19,15 +19,16 @@ import argparse
19
19
  import logging
20
20
  import os
21
21
  import sys
22
+ import typing as ty
22
23
 
23
24
  from cliff import columns as cliff_columns
24
25
  from osc_lib.api import utils as api_utils
25
26
  from osc_lib.cli import format_columns
26
27
  from osc_lib.cli import parseractions
27
- from osc_lib.command import command
28
28
  from osc_lib import exceptions
29
29
  from osc_lib import utils
30
30
 
31
+ from openstackclient import command
31
32
  from openstackclient.i18n import _
32
33
 
33
34
  CONTAINER_CHOICES = ["ami", "ari", "aki", "bare", "docker", "ova", "ovf"]
@@ -67,10 +68,7 @@ def _get_columns(item):
67
68
  )
68
69
 
69
70
 
70
- _formatters = {}
71
-
72
-
73
- class HumanReadableSizeColumn(cliff_columns.FormattableColumn):
71
+ class HumanReadableSizeColumn(cliff_columns.FormattableColumn[int]):
74
72
  def human_readable(self):
75
73
  """Return a formatted visibility string
76
74
 
@@ -84,7 +82,7 @@ class HumanReadableSizeColumn(cliff_columns.FormattableColumn):
84
82
  return ''
85
83
 
86
84
 
87
- class VisibilityColumn(cliff_columns.FormattableColumn):
85
+ class VisibilityColumn(cliff_columns.FormattableColumn[bool]):
88
86
  def human_readable(self):
89
87
  """Return a formatted visibility string
90
88
 
@@ -340,9 +338,12 @@ class CreateImage(command.ShowOne):
340
338
 
341
339
  if image:
342
340
  display_columns, columns = _get_columns(image)
343
- _formatters['properties'] = format_columns.DictColumn
344
341
  data = utils.get_item_properties(
345
- image, columns, formatters=_formatters
342
+ image,
343
+ columns,
344
+ formatters={
345
+ 'properties': format_columns.DictColumn,
346
+ },
346
347
  )
347
348
  return (display_columns, data)
348
349
  elif info:
@@ -493,19 +494,19 @@ class ListImage(command.Lister):
493
494
  column_headers = columns
494
495
 
495
496
  # List of image data received
496
- data = list(image_client.images(**kwargs))
497
+ images = list(image_client.images(**kwargs))
497
498
 
498
499
  if parsed_args.property:
499
500
  # NOTE(dtroyer): coerce to a list to subscript it in py3
500
501
  attr, value = list(parsed_args.property.items())[0]
501
502
  api_utils.simple_filter(
502
- data,
503
+ images,
503
504
  attr=attr,
504
505
  value=value,
505
506
  property_field='properties',
506
507
  )
507
508
 
508
- data = utils.sort_items(data, parsed_args.sort)
509
+ data = utils.sort_items(images, parsed_args.sort)
509
510
 
510
511
  return (
511
512
  column_headers,
@@ -528,6 +529,16 @@ class SaveImage(command.Command):
528
529
 
529
530
  def get_parser(self, prog_name):
530
531
  parser = super().get_parser(prog_name)
532
+ parser.add_argument(
533
+ "--chunk-size",
534
+ type=int,
535
+ default=1024,
536
+ metavar="<chunk-size>",
537
+ help=_(
538
+ "Size in bytes to read from the wire and buffer at one "
539
+ "time (default: 1024)"
540
+ ),
541
+ )
531
542
  parser.add_argument(
532
543
  "--file",
533
544
  metavar="<filename>",
@@ -550,7 +561,12 @@ class SaveImage(command.Command):
550
561
  if output_file is None:
551
562
  output_file = getattr(sys.stdout, "buffer", sys.stdout)
552
563
 
553
- image_client.download_image(image.id, stream=True, output=output_file)
564
+ image_client.download_image(
565
+ image.id,
566
+ stream=True,
567
+ output=output_file,
568
+ chunk_size=parsed_args.chunk_size,
569
+ )
554
570
 
555
571
 
556
572
  class SetImage(command.Command):
@@ -824,11 +840,13 @@ class ShowImage(command.ShowOne):
824
840
  parsed_args.image, ignore_missing=False
825
841
  )
826
842
 
843
+ formatters: dict[
844
+ str, type[cliff_columns.FormattableColumn[ty.Any]]
845
+ ] = {
846
+ 'properties': format_columns.DictColumn,
847
+ }
827
848
  if parsed_args.human_readable:
828
- _formatters['size'] = HumanReadableSizeColumn
849
+ formatters['size'] = HumanReadableSizeColumn
829
850
  display_columns, columns = _get_columns(image)
830
- _formatters['properties'] = format_columns.DictColumn
831
- data = utils.get_item_properties(
832
- image, columns, formatters=_formatters
833
- )
851
+ data = utils.get_item_properties(image, columns, formatters=formatters)
834
852
  return (display_columns, data)
@@ -17,10 +17,10 @@ import copy
17
17
  import datetime
18
18
  import logging
19
19
 
20
- from osc_lib.command import command
21
20
  from osc_lib import exceptions
22
21
  from osc_lib import utils
23
22
 
23
+ from openstackclient import command
24
24
  from openstackclient.i18n import _
25
25
 
26
26
 
@@ -37,14 +37,18 @@ def _format_image_cache(cached_images):
37
37
  image_obj = copy.deepcopy(image)
38
38
  image_obj['state'] = 'cached'
39
39
  image_obj['last_accessed'] = (
40
- datetime.datetime.utcfromtimestamp(
41
- image['last_accessed']
42
- ).isoformat()
40
+ datetime.datetime.fromtimestamp(
41
+ image['last_accessed'], tz=datetime.timezone.utc
42
+ )
43
+ .replace(tzinfo=None)
44
+ .isoformat()
43
45
  )
44
46
  image_obj['last_modified'] = (
45
- datetime.datetime.utcfromtimestamp(
46
- image['last_modified']
47
- ).isoformat()
47
+ datetime.datetime.fromtimestamp(
48
+ image['last_modified'], tz=datetime.timezone.utc
49
+ )
50
+ .replace(tzinfo=None)
51
+ .isoformat()
48
52
  )
49
53
  image_list.append(image_obj)
50
54
  elif item == "queued_images":
@@ -22,6 +22,7 @@ import logging
22
22
  import os
23
23
  import sys
24
24
  import typing as ty
25
+ import urllib.parse
25
26
 
26
27
  from openstack import exceptions as sdk_exceptions
27
28
  from openstack.image import image_signer
@@ -29,10 +30,10 @@ from openstack import utils as sdk_utils
29
30
  from osc_lib.api import utils as api_utils
30
31
  from osc_lib.cli import format_columns
31
32
  from osc_lib.cli import parseractions
32
- from osc_lib.command import command
33
33
  from osc_lib import exceptions
34
34
  from osc_lib import utils
35
35
 
36
+ from openstackclient import command
36
37
  from openstackclient.common import pagination
37
38
  from openstackclient.common import progressbar
38
39
  from openstackclient.i18n import _
@@ -54,6 +55,19 @@ DISK_CHOICES = [
54
55
  "iso",
55
56
  "ploop",
56
57
  ]
58
+ # A list of openstacksdk Image object attributes (values) that named
59
+ # differently from actual properties stored by Glance (keys).
60
+ IMAGE_ATTRIBUTES_CUSTOM_NAMES = {
61
+ 'os_hidden': 'is_hidden',
62
+ 'protected': 'is_protected',
63
+ 'os_hash_algo': 'hash_algo',
64
+ 'os_hash_value': 'hash_value',
65
+ 'img_config_drive': 'needs_config_drive',
66
+ 'os_secure_boot': 'needs_secure_boot',
67
+ 'hw_vif_multiqueue_enabled': 'is_hw_vif_multiqueue_enabled',
68
+ 'hw_boot_menu': 'is_hw_boot_menu_enabled',
69
+ 'auto_disk_config': 'has_auto_disk_config',
70
+ }
57
71
  MEMBER_STATUS_CHOICES = ["accepted", "pending", "rejected", "all"]
58
72
 
59
73
  LOG = logging.getLogger(__name__)
@@ -84,6 +98,9 @@ def _format_image(image, human_readable=False):
84
98
  'virtual_size',
85
99
  'min_ram',
86
100
  'schema',
101
+ 'is_hidden',
102
+ 'hash_algo',
103
+ 'hash_value',
87
104
  ]
88
105
 
89
106
  # TODO(gtema/anybody): actually it should be possible to drop this method,
@@ -534,7 +551,7 @@ class CreateImage(command.ShowOne):
534
551
  sign_cert_id = parsed_args.sign_cert_id
535
552
  signer = image_signer.ImageSigner()
536
553
  try:
537
- pw = utils.get_password(
554
+ pw: str | None = utils.get_password(
538
555
  self.app.stdin,
539
556
  prompt=(
540
557
  "Please enter private key password, leave "
@@ -545,12 +562,11 @@ class CreateImage(command.ShowOne):
545
562
 
546
563
  if not pw or len(pw) < 1:
547
564
  pw = None
548
- else:
549
- # load_private_key() requires the password to be
550
- # passed as bytes
551
- pw = pw.encode()
552
565
 
553
- signer.load_private_key(sign_key_path, password=pw)
566
+ signer.load_private_key(
567
+ sign_key_path,
568
+ password=pw.encode() if pw else None,
569
+ )
554
570
  except Exception:
555
571
  msg = _(
556
572
  "Error during sign operation: private key "
@@ -889,6 +905,8 @@ class ListImage(command.Lister):
889
905
  'visibility',
890
906
  'is_protected',
891
907
  'owner_id',
908
+ 'hash_algo',
909
+ 'hash_value',
892
910
  'tags',
893
911
  )
894
912
  column_headers: tuple[str, ...] = (
@@ -902,6 +920,8 @@ class ListImage(command.Lister):
902
920
  'Visibility',
903
921
  'Protected',
904
922
  'Project',
923
+ 'Hash Algorithm',
924
+ 'Hash Value',
905
925
  'Tags',
906
926
  )
907
927
  else:
@@ -912,18 +932,19 @@ class ListImage(command.Lister):
912
932
  if 'limit' in kwargs:
913
933
  # Disable automatic pagination in SDK
914
934
  kwargs['paginated'] = False
915
- data = list(image_client.images(**kwargs))
935
+
936
+ images = list(image_client.images(**kwargs))
916
937
 
917
938
  if parsed_args.property:
918
939
  for attr, value in parsed_args.property.items():
919
940
  api_utils.simple_filter(
920
- data,
941
+ images,
921
942
  attr=attr,
922
943
  value=value,
923
944
  property_field='properties',
924
945
  )
925
946
 
926
- data = utils.sort_items(data, parsed_args.sort, str)
947
+ data = utils.sort_items(images, parsed_args.sort, str)
927
948
 
928
949
  return (
929
950
  column_headers,
@@ -1052,6 +1073,16 @@ class SaveImage(command.Command):
1052
1073
 
1053
1074
  def get_parser(self, prog_name):
1054
1075
  parser = super().get_parser(prog_name)
1076
+ parser.add_argument(
1077
+ "--chunk-size",
1078
+ type=int,
1079
+ default=1024,
1080
+ metavar="<chunk-size>",
1081
+ help=_(
1082
+ "Size in bytes to read from the wire and buffer at one "
1083
+ "time (default: 1024)"
1084
+ ),
1085
+ )
1055
1086
  parser.add_argument(
1056
1087
  "--file",
1057
1088
  metavar="<filename>",
@@ -1076,7 +1107,12 @@ class SaveImage(command.Command):
1076
1107
  if output_file is None:
1077
1108
  output_file = getattr(sys.stdout, "buffer", sys.stdout)
1078
1109
 
1079
- image_client.download_image(image.id, stream=True, output=output_file)
1110
+ image_client.download_image(
1111
+ image.id,
1112
+ stream=True,
1113
+ output=output_file,
1114
+ chunk_size=parsed_args.chunk_size,
1115
+ )
1080
1116
 
1081
1117
 
1082
1118
  class SetImage(command.Command):
@@ -1357,7 +1393,10 @@ class SetImage(command.Command):
1357
1393
  if parsed_args.visibility is not None:
1358
1394
  kwargs['visibility'] = parsed_args.visibility
1359
1395
 
1360
- if parsed_args.project:
1396
+ # Only set owner_id if --project is used WITHOUT membership flags
1397
+ # When --project is used with --accept/--reject/--pending, it should
1398
+ # only identify which member's status to update, not change ownership
1399
+ if parsed_args.project and not parsed_args.membership:
1361
1400
  # We already did the project lookup above
1362
1401
  kwargs['owner_id'] = project_id
1363
1402
 
@@ -1477,6 +1516,11 @@ class UnsetImage(command.Command):
1477
1516
  )
1478
1517
  new_props.pop(k, None)
1479
1518
  kwargs['properties'] = new_props
1519
+ elif (
1520
+ k in IMAGE_ATTRIBUTES_CUSTOM_NAMES
1521
+ and IMAGE_ATTRIBUTES_CUSTOM_NAMES[k] in image
1522
+ ):
1523
+ delattr(image, IMAGE_ATTRIBUTES_CUSTOM_NAMES[k])
1480
1524
  else:
1481
1525
  LOG.error(
1482
1526
  _(
@@ -1744,6 +1788,12 @@ class ImportImage(command.ShowOne):
1744
1788
  "'--method=web-download'"
1745
1789
  )
1746
1790
  raise exceptions.CommandError(msg)
1791
+ _parsed = urllib.parse.urlparse(parsed_args.uri)
1792
+ if not all({_parsed.scheme, _parsed.netloc}):
1793
+ msg = _("'%(uri)s' is not a valid url")
1794
+ raise exceptions.CommandError(
1795
+ msg % {'uri': parsed_args.uri},
1796
+ )
1747
1797
  else:
1748
1798
  if parsed_args.uri:
1749
1799
  msg = _(
@@ -12,8 +12,8 @@
12
12
 
13
13
 
14
14
  from osc_lib.cli import format_columns
15
- from osc_lib.command import command
16
15
 
16
+ from openstackclient import command
17
17
  from openstackclient.i18n import _
18
18
 
19
19
 
@@ -18,10 +18,10 @@
18
18
  import logging
19
19
 
20
20
  from osc_lib.cli import format_columns
21
- from osc_lib.command import command
22
21
  from osc_lib import exceptions
23
22
  from osc_lib import utils
24
23
 
24
+ from openstackclient import command
25
25
  from openstackclient.i18n import _
26
26
 
27
27
  _formatters = {
@@ -17,10 +17,10 @@
17
17
 
18
18
  import logging
19
19
 
20
- from osc_lib.command import command
21
20
  from osc_lib import exceptions
22
21
  from osc_lib import utils
23
22
 
23
+ from openstackclient import command
24
24
  from openstackclient.i18n import _
25
25
 
26
26
 
@@ -123,8 +123,11 @@ class DeleteMetadefObject(command.Command):
123
123
  parser.add_argument(
124
124
  "objects",
125
125
  metavar="<object>",
126
- nargs="+",
127
- help=_("Metadef object(s) to delete (name)"),
126
+ nargs="*",
127
+ help=_(
128
+ "Metadef object(s) to delete (name) "
129
+ "(omit this argument to delete all objects in the namespace)"
130
+ ),
128
131
  )
129
132
  return parser
130
133
 
@@ -133,6 +136,9 @@ class DeleteMetadefObject(command.Command):
133
136
 
134
137
  namespace = parsed_args.namespace
135
138
 
139
+ if not parsed_args.objects:
140
+ return image_client.delete_all_metadef_objects(namespace)
141
+
136
142
  result = 0
137
143
  for obj in parsed_args.objects:
138
144
  try:
@@ -15,10 +15,10 @@
15
15
  import json
16
16
  import logging
17
17
 
18
- from osc_lib.command import command
19
18
  from osc_lib import exceptions
20
19
  from osc_lib import utils
21
20
 
21
+ from openstackclient import command
22
22
  from openstackclient.i18n import _
23
23
 
24
24
 
@@ -124,14 +124,22 @@ class DeleteMetadefProperty(command.Command):
124
124
  parser.add_argument(
125
125
  "properties",
126
126
  metavar="<property>",
127
- nargs="+",
128
- help=_("Metadef propert(ies) to delete (name)"),
127
+ nargs="*",
128
+ help=_(
129
+ "Metadef properties to delete (name) "
130
+ "(omit this argument to delete all properties "
131
+ "in the namespace)"
132
+ ),
129
133
  )
130
134
  return parser
131
135
 
132
136
  def take_action(self, parsed_args):
133
137
  image_client = self.app.client_manager.image
134
138
 
139
+ if not parsed_args.properties:
140
+ image_client.delete_all_metadef_properties(parsed_args.namespace)
141
+ return
142
+
135
143
  result = 0
136
144
  for prop in parsed_args.properties:
137
145
  try:
@@ -12,10 +12,10 @@
12
12
 
13
13
  import logging
14
14
 
15
- from osc_lib.command import command
16
15
  from osc_lib import exceptions
17
16
  from osc_lib import utils
18
17
 
18
+ from openstackclient import command
19
19
  from openstackclient.i18n import _
20
20
 
21
21
  LOG = logging.getLogger(__name__)
@@ -12,9 +12,9 @@
12
12
 
13
13
  """Image V2 Action Implementations"""
14
14
 
15
- from osc_lib.command import command
16
15
  from osc_lib import utils
17
16
 
17
+ from openstackclient import command
18
18
  from openstackclient.i18n import _
19
19
 
20
20
 
@@ -11,9 +11,9 @@
11
11
  # under the License.
12
12
 
13
13
  from osc_lib.cli import format_columns
14
- from osc_lib.command import command
15
14
  from osc_lib import utils
16
15
 
16
+ from openstackclient import command
17
17
  from openstackclient.i18n import _
18
18
 
19
19
  _formatters = {