python-openstackclient 8.2.0__py3-none-any.whl → 9.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. openstackclient/api/object_store_v1.py +4 -1
  2. openstackclient/command.py +27 -0
  3. openstackclient/common/availability_zone.py +1 -1
  4. openstackclient/common/clientmanager.py +59 -21
  5. openstackclient/common/configuration.py +1 -1
  6. openstackclient/common/extension.py +1 -1
  7. openstackclient/common/limits.py +1 -1
  8. openstackclient/common/module.py +5 -3
  9. openstackclient/common/project_cleanup.py +10 -8
  10. openstackclient/common/quota.py +54 -23
  11. openstackclient/common/versions.py +1 -2
  12. openstackclient/compute/v2/agent.py +1 -1
  13. openstackclient/compute/v2/aggregate.py +6 -5
  14. openstackclient/compute/v2/console.py +5 -3
  15. openstackclient/compute/v2/console_connection.py +1 -1
  16. openstackclient/compute/v2/flavor.py +1 -1
  17. openstackclient/compute/v2/host.py +1 -1
  18. openstackclient/compute/v2/hypervisor.py +1 -1
  19. openstackclient/compute/v2/hypervisor_stats.py +1 -1
  20. openstackclient/compute/v2/keypair.py +1 -1
  21. openstackclient/compute/v2/server.py +78 -29
  22. openstackclient/compute/v2/server_backup.py +1 -1
  23. openstackclient/compute/v2/server_event.py +1 -1
  24. openstackclient/compute/v2/server_group.py +4 -2
  25. openstackclient/compute/v2/server_image.py +1 -1
  26. openstackclient/compute/v2/server_migration.py +1 -1
  27. openstackclient/compute/v2/server_volume.py +1 -1
  28. openstackclient/compute/v2/service.py +1 -1
  29. openstackclient/compute/v2/usage.py +6 -4
  30. openstackclient/identity/common.py +33 -1
  31. openstackclient/identity/v2_0/catalog.py +3 -2
  32. openstackclient/identity/v2_0/ec2creds.py +1 -1
  33. openstackclient/identity/v2_0/endpoint.py +1 -1
  34. openstackclient/identity/v2_0/project.py +17 -7
  35. openstackclient/identity/v2_0/role.py +1 -1
  36. openstackclient/identity/v2_0/role_assignment.py +3 -3
  37. openstackclient/identity/v2_0/service.py +4 -2
  38. openstackclient/identity/v2_0/token.py +1 -1
  39. openstackclient/identity/v2_0/user.py +2 -2
  40. openstackclient/identity/v3/access_rule.py +16 -4
  41. openstackclient/identity/v3/application_credential.py +30 -10
  42. openstackclient/identity/v3/catalog.py +3 -3
  43. openstackclient/identity/v3/consumer.py +1 -1
  44. openstackclient/identity/v3/credential.py +1 -1
  45. openstackclient/identity/v3/domain.py +10 -4
  46. openstackclient/identity/v3/ec2creds.py +1 -1
  47. openstackclient/identity/v3/endpoint.py +33 -12
  48. openstackclient/identity/v3/endpoint_group.py +1 -1
  49. openstackclient/identity/v3/federation_protocol.py +40 -41
  50. openstackclient/identity/v3/group.py +11 -5
  51. openstackclient/identity/v3/identity_provider.py +12 -10
  52. openstackclient/identity/v3/implied_role.py +1 -1
  53. openstackclient/identity/v3/limit.py +86 -85
  54. openstackclient/identity/v3/mapping.py +1 -1
  55. openstackclient/identity/v3/policy.py +1 -1
  56. openstackclient/identity/v3/project.py +191 -115
  57. openstackclient/identity/v3/region.py +1 -1
  58. openstackclient/identity/v3/registered_limit.py +97 -109
  59. openstackclient/identity/v3/role.py +20 -39
  60. openstackclient/identity/v3/role_assignment.py +12 -23
  61. openstackclient/identity/v3/service.py +1 -1
  62. openstackclient/identity/v3/service_provider.py +1 -1
  63. openstackclient/identity/v3/tag.py +1 -11
  64. openstackclient/identity/v3/token.py +3 -2
  65. openstackclient/identity/v3/trust.py +4 -2
  66. openstackclient/identity/v3/unscoped_saml.py +1 -1
  67. openstackclient/identity/v3/user.py +22 -13
  68. openstackclient/image/v1/image.py +19 -16
  69. openstackclient/image/v2/cache.py +1 -1
  70. openstackclient/image/v2/image.py +16 -12
  71. openstackclient/image/v2/info.py +1 -1
  72. openstackclient/image/v2/metadef_namespaces.py +1 -1
  73. openstackclient/image/v2/metadef_objects.py +1 -1
  74. openstackclient/image/v2/metadef_properties.py +3 -2
  75. openstackclient/image/v2/metadef_resource_type_association.py +1 -1
  76. openstackclient/image/v2/metadef_resource_types.py +1 -1
  77. openstackclient/image/v2/task.py +1 -1
  78. openstackclient/network/common.py +10 -9
  79. openstackclient/network/v2/address_group.py +4 -3
  80. openstackclient/network/v2/address_scope.py +8 -6
  81. openstackclient/network/v2/default_security_group_rule.py +9 -8
  82. openstackclient/network/v2/floating_ip.py +16 -9
  83. openstackclient/network/v2/floating_ip_port_forwarding.py +9 -6
  84. openstackclient/network/v2/ip_availability.py +7 -4
  85. openstackclient/network/v2/l3_conntrack_helper.py +11 -4
  86. openstackclient/network/v2/local_ip.py +13 -7
  87. openstackclient/network/v2/local_ip_association.py +7 -4
  88. openstackclient/network/v2/ndp_proxy.py +13 -6
  89. openstackclient/network/v2/network.py +33 -16
  90. openstackclient/network/v2/network_agent.py +5 -5
  91. openstackclient/network/v2/network_auto_allocated_topology.py +1 -1
  92. openstackclient/network/v2/network_flavor.py +1 -1
  93. openstackclient/network/v2/network_flavor_profile.py +1 -1
  94. openstackclient/network/v2/network_meter.py +1 -1
  95. openstackclient/network/v2/network_meter_rule.py +1 -1
  96. openstackclient/network/v2/network_qos_policy.py +7 -5
  97. openstackclient/network/v2/network_qos_rule.py +1 -1
  98. openstackclient/network/v2/network_qos_rule_type.py +1 -1
  99. openstackclient/network/v2/network_rbac.py +8 -5
  100. openstackclient/network/v2/network_segment.py +2 -2
  101. openstackclient/network/v2/network_segment_range.py +13 -6
  102. openstackclient/network/v2/network_service_provider.py +1 -1
  103. openstackclient/network/v2/network_trunk.py +65 -42
  104. openstackclient/network/v2/port.py +22 -20
  105. openstackclient/network/v2/router.py +19 -8
  106. openstackclient/network/v2/security_group.py +10 -6
  107. openstackclient/network/v2/security_group_rule.py +11 -5
  108. openstackclient/network/v2/subnet.py +17 -18
  109. openstackclient/network/v2/subnet_pool.py +11 -9
  110. openstackclient/network/v2/taas/__init__.py +0 -0
  111. openstackclient/network/v2/taas/tap_flow.py +245 -0
  112. openstackclient/network/v2/taas/tap_mirror.py +237 -0
  113. openstackclient/network/v2/taas/tap_service.py +211 -0
  114. openstackclient/object/v1/account.py +1 -1
  115. openstackclient/object/v1/container.py +1 -1
  116. openstackclient/object/v1/object.py +1 -1
  117. openstackclient/shell.py +18 -8
  118. openstackclient/tests/functional/identity/v3/test_catalog.py +42 -23
  119. openstackclient/tests/functional/identity/v3/test_limit.py +47 -0
  120. openstackclient/tests/functional/identity/v3/test_role_assignment.py +174 -0
  121. openstackclient/tests/functional/image/v2/test_cache.py +54 -0
  122. openstackclient/tests/functional/image/v2/test_metadef_objects.py +69 -0
  123. openstackclient/tests/functional/image/v2/test_metadef_resource_type.py +55 -0
  124. openstackclient/tests/functional/volume/v3/test_volume_snapshot.py +46 -132
  125. openstackclient/tests/unit/common/test_command.py +1 -1
  126. openstackclient/tests/unit/common/test_extension.py +2 -3
  127. openstackclient/tests/unit/common/test_module.py +14 -7
  128. openstackclient/tests/unit/common/test_quota.py +79 -0
  129. openstackclient/tests/unit/compute/v2/test_aggregate.py +5 -3
  130. openstackclient/tests/unit/compute/v2/test_console.py +1 -4
  131. openstackclient/tests/unit/compute/v2/test_flavor.py +1 -3
  132. openstackclient/tests/unit/compute/v2/test_hypervisor_stats.py +1 -9
  133. openstackclient/tests/unit/compute/v2/test_server.py +370 -38
  134. openstackclient/tests/unit/compute/v2/test_server_backup.py +1 -3
  135. openstackclient/tests/unit/compute/v2/test_service.py +1 -3
  136. openstackclient/tests/unit/fakes.py +35 -134
  137. openstackclient/tests/unit/identity/test_common.py +100 -0
  138. openstackclient/tests/unit/identity/v2_0/test_project.py +4 -4
  139. openstackclient/tests/unit/identity/v3/fakes.py +10 -2
  140. openstackclient/tests/unit/identity/v3/test_application_credential.py +3 -3
  141. openstackclient/tests/unit/identity/v3/test_domain.py +1 -1
  142. openstackclient/tests/unit/identity/v3/test_endpoint.py +1 -1
  143. openstackclient/tests/unit/identity/v3/test_group.py +4 -2
  144. openstackclient/tests/unit/identity/v3/test_identity_provider.py +10 -10
  145. openstackclient/tests/unit/identity/v3/test_limit.py +197 -145
  146. openstackclient/tests/unit/identity/v3/test_oauth.py +1 -1
  147. openstackclient/tests/unit/identity/v3/test_project.py +832 -513
  148. openstackclient/tests/unit/identity/v3/test_protocol.py +97 -88
  149. openstackclient/tests/unit/identity/v3/test_registered_limit.py +356 -221
  150. openstackclient/tests/unit/identity/v3/test_role.py +1 -82
  151. openstackclient/tests/unit/identity/v3/test_user.py +7 -51
  152. openstackclient/tests/unit/image/v2/test_image.py +116 -5
  153. openstackclient/tests/unit/network/test_common.py +9 -13
  154. openstackclient/tests/unit/network/v2/taas/__init__.py +0 -0
  155. openstackclient/tests/unit/network/v2/taas/test_osc_tap_flow.py +276 -0
  156. openstackclient/tests/unit/network/v2/taas/test_osc_tap_mirror.py +288 -0
  157. openstackclient/tests/unit/network/v2/taas/test_osc_tap_service.py +271 -0
  158. openstackclient/tests/unit/network/v2/test_address_group.py +19 -22
  159. openstackclient/tests/unit/network/v2/test_address_scope.py +10 -15
  160. openstackclient/tests/unit/network/v2/test_default_security_group_rule.py +38 -49
  161. openstackclient/tests/unit/network/v2/test_floating_ip_network.py +21 -27
  162. openstackclient/tests/unit/network/v2/test_floating_ip_port_forwarding.py +21 -18
  163. openstackclient/tests/unit/network/v2/test_ip_availability.py +6 -8
  164. openstackclient/tests/unit/network/v2/test_l3_conntrack_helper.py +6 -15
  165. openstackclient/tests/unit/network/v2/test_local_ip.py +12 -23
  166. openstackclient/tests/unit/network/v2/test_local_ip_association.py +13 -18
  167. openstackclient/tests/unit/network/v2/test_ndp_proxy.py +11 -21
  168. openstackclient/tests/unit/network/v2/test_network.py +41 -37
  169. openstackclient/tests/unit/network/v2/test_network_agent.py +13 -20
  170. openstackclient/tests/unit/network/v2/test_network_auto_allocated_topology.py +5 -8
  171. openstackclient/tests/unit/network/v2/test_network_flavor.py +14 -26
  172. openstackclient/tests/unit/network/v2/test_network_flavor_profile.py +14 -17
  173. openstackclient/tests/unit/network/v2/test_network_meter.py +7 -17
  174. openstackclient/tests/unit/network/v2/test_network_meter_rule.py +10 -20
  175. openstackclient/tests/unit/network/v2/test_network_qos_policy.py +7 -13
  176. openstackclient/tests/unit/network/v2/test_network_qos_rule.py +44 -54
  177. openstackclient/tests/unit/network/v2/test_network_qos_rule_type.py +2 -7
  178. openstackclient/tests/unit/network/v2/test_network_rbac.py +21 -36
  179. openstackclient/tests/unit/network/v2/test_network_segment.py +13 -29
  180. openstackclient/tests/unit/network/v2/test_network_segment_range.py +20 -19
  181. openstackclient/tests/unit/network/v2/test_network_service_provider.py +1 -4
  182. openstackclient/tests/unit/network/v2/test_network_trunk.py +52 -47
  183. openstackclient/tests/unit/network/v2/test_port.py +75 -86
  184. openstackclient/tests/unit/network/v2/test_router.py +104 -126
  185. openstackclient/tests/unit/network/v2/test_security_group_network.py +19 -26
  186. openstackclient/tests/unit/network/v2/test_security_group_rule_network.py +17 -18
  187. openstackclient/tests/unit/network/v2/test_subnet.py +35 -46
  188. openstackclient/tests/unit/network/v2/test_subnet_pool.py +21 -33
  189. openstackclient/tests/unit/volume/test_find_resource.py +4 -13
  190. openstackclient/tests/unit/volume/v2/test_consistency_group.py +8 -2
  191. openstackclient/tests/unit/volume/v2/test_volume.py +7 -6
  192. openstackclient/tests/unit/volume/v2/test_volume_backup.py +3 -1
  193. openstackclient/tests/unit/volume/v3/test_volume.py +38 -12
  194. openstackclient/tests/unit/volume/v3/test_volume_backup.py +9 -0
  195. openstackclient/volume/client.py +7 -17
  196. openstackclient/volume/v2/backup_record.py +1 -1
  197. openstackclient/volume/v2/consistency_group.py +9 -9
  198. openstackclient/volume/v2/consistency_group_snapshot.py +3 -3
  199. openstackclient/volume/v2/qos_specs.py +3 -3
  200. openstackclient/volume/v2/service.py +1 -1
  201. openstackclient/volume/v2/volume.py +14 -7
  202. openstackclient/volume/v2/volume_backend.py +1 -1
  203. openstackclient/volume/v2/volume_backup.py +7 -5
  204. openstackclient/volume/v2/volume_host.py +1 -2
  205. openstackclient/volume/v2/volume_snapshot.py +4 -4
  206. openstackclient/volume/v2/volume_transfer_request.py +3 -3
  207. openstackclient/volume/v2/volume_type.py +16 -11
  208. openstackclient/volume/v3/block_storage_cleanup.py +1 -1
  209. openstackclient/volume/v3/block_storage_cluster.py +1 -1
  210. openstackclient/volume/v3/block_storage_log_level.py +1 -1
  211. openstackclient/volume/v3/block_storage_manage.py +1 -1
  212. openstackclient/volume/v3/block_storage_resource_filter.py +1 -1
  213. openstackclient/volume/v3/service.py +1 -1
  214. openstackclient/volume/v3/volume.py +16 -9
  215. openstackclient/volume/v3/volume_attachment.py +6 -5
  216. openstackclient/volume/v3/volume_backup.py +20 -5
  217. openstackclient/volume/v3/volume_group.py +1 -1
  218. openstackclient/volume/v3/volume_group_snapshot.py +1 -1
  219. openstackclient/volume/v3/volume_group_type.py +1 -1
  220. openstackclient/volume/v3/volume_message.py +1 -1
  221. openstackclient/volume/v3/volume_snapshot.py +4 -4
  222. openstackclient/volume/v3/volume_transfer_request.py +3 -3
  223. openstackclient/volume/v3/volume_type.py +20 -14
  224. {python_openstackclient-8.2.0.dist-info → python_openstackclient-9.0.0.dist-info}/METADATA +15 -13
  225. {python_openstackclient-8.2.0.dist-info → python_openstackclient-9.0.0.dist-info}/RECORD +231 -219
  226. {python_openstackclient-8.2.0.dist-info → python_openstackclient-9.0.0.dist-info}/WHEEL +1 -1
  227. {python_openstackclient-8.2.0.dist-info → python_openstackclient-9.0.0.dist-info}/entry_points.txt +15 -0
  228. {python_openstackclient-8.2.0.dist-info → python_openstackclient-9.0.0.dist-info/licenses}/AUTHORS +15 -0
  229. python_openstackclient-9.0.0.dist-info/pbr.json +1 -0
  230. openstackclient/tests/unit/common/test_logs.py +0 -221
  231. python_openstackclient-8.2.0.dist-info/pbr.json +0 -1
  232. {python_openstackclient-8.2.0.dist-info → python_openstackclient-9.0.0.dist-info/licenses}/LICENSE +0 -0
  233. {python_openstackclient-8.2.0.dist-info → python_openstackclient-9.0.0.dist-info}/top_level.txt +0 -0
@@ -17,12 +17,12 @@
17
17
 
18
18
  import logging
19
19
 
20
- from keystoneauth1 import exceptions as ks_exc
20
+ from openstack import exceptions as sdk_exc
21
21
  from osc_lib.cli import parseractions
22
- from osc_lib.command import command
23
22
  from osc_lib import exceptions
24
23
  from osc_lib import utils
25
24
 
25
+ from openstackclient import command
26
26
  from openstackclient.i18n import _
27
27
  from openstackclient.identity import common
28
28
  from openstackclient.identity.v3 import tag
@@ -30,6 +30,21 @@ from openstackclient.identity.v3 import tag
30
30
  LOG = logging.getLogger(__name__)
31
31
 
32
32
 
33
+ def _format_project(project):
34
+ # NOTE(0weng): Projects allow unknown attributes in the body, so extract
35
+ # the column names separately.
36
+ (column_headers, columns) = utils.get_osc_show_columns_for_sdk_resource(
37
+ project,
38
+ {'is_enabled': 'enabled'},
39
+ ['links', 'location', 'parents_as_ids', 'subtree_as_ids'],
40
+ )
41
+
42
+ return (
43
+ column_headers,
44
+ utils.get_item_properties(project, columns),
45
+ )
46
+
47
+
33
48
  class CreateProject(command.ShowOne):
34
49
  _description = _("Create new project")
35
50
 
@@ -73,8 +88,8 @@ class CreateProject(command.ShowOne):
73
88
  parser.add_argument(
74
89
  '--property',
75
90
  metavar='<key=value>',
76
- action=parseractions.KeyValueAction,
77
91
  dest='properties',
92
+ action=parseractions.KeyValueAction,
78
93
  help=_(
79
94
  'Add a property to <name> '
80
95
  '(repeat option to set multiple properties)'
@@ -90,22 +105,13 @@ class CreateProject(command.ShowOne):
90
105
  return parser
91
106
 
92
107
  def take_action(self, parsed_args):
93
- identity_client = self.app.client_manager.identity
94
-
95
- domain = None
96
- if parsed_args.domain:
97
- domain = common.find_domain(identity_client, parsed_args.domain).id
98
-
99
- parent = None
100
- if parsed_args.parent:
101
- parent = utils.find_resource(
102
- identity_client.projects,
103
- parsed_args.parent,
104
- ).id
108
+ identity_client = self.app.client_manager.sdk_connection.identity
105
109
 
106
110
  kwargs = {}
111
+
107
112
  if parsed_args.properties:
108
113
  kwargs = parsed_args.properties.copy()
114
+
109
115
  if 'is_domain' in kwargs.keys():
110
116
  if kwargs['is_domain'].lower() == "true":
111
117
  kwargs['is_domain'] = True
@@ -114,39 +120,66 @@ class CreateProject(command.ShowOne):
114
120
  elif kwargs['is_domain'].lower() == "none":
115
121
  kwargs['is_domain'] = None
116
122
 
117
- kwargs['tags'] = list(set(parsed_args.tags))
123
+ if parsed_args.description:
124
+ kwargs['description'] = parsed_args.description
125
+
126
+ if parsed_args.name:
127
+ kwargs['name'] = parsed_args.name
128
+
129
+ domain = None
130
+ if parsed_args.domain:
131
+ domain = common.find_domain_id_sdk(
132
+ identity_client, parsed_args.domain
133
+ )
134
+ kwargs['domain_id'] = domain
135
+
136
+ if parsed_args.parent:
137
+ kwargs['parent_id'] = common.find_project_id_sdk(
138
+ identity_client,
139
+ parsed_args.parent,
140
+ domain_name_or_id=domain,
141
+ )
142
+
143
+ kwargs['is_enabled'] = parsed_args.enabled
144
+
145
+ if parsed_args.tags:
146
+ kwargs['tags'] = list(set(parsed_args.tags))
118
147
 
119
- options = {}
120
148
  if parsed_args.immutable is not None:
121
- options['immutable'] = parsed_args.immutable
149
+ kwargs['options'] = {'immutable': parsed_args.immutable}
122
150
 
123
151
  try:
124
- project = identity_client.projects.create(
125
- name=parsed_args.name,
126
- domain=domain,
127
- parent=parent,
128
- description=parsed_args.description,
129
- enabled=parsed_args.enabled,
130
- options=options,
152
+ project = identity_client.create_project(
131
153
  **kwargs,
132
154
  )
133
- except ks_exc.Conflict:
155
+ except sdk_exc.ConflictException:
134
156
  if parsed_args.or_show:
135
- project = utils.find_resource(
136
- identity_client.projects,
137
- parsed_args.name,
138
- domain_id=domain,
139
- )
157
+ if parsed_args.domain:
158
+ project = identity_client.find_project(
159
+ parsed_args.name,
160
+ domain_id=domain,
161
+ ignore_missing=False,
162
+ )
163
+ else:
164
+ project = identity_client.find_project(
165
+ parsed_args.name, ignore_missing=False
166
+ )
140
167
  LOG.info(_('Returning existing project %s'), project.name)
141
168
  else:
142
169
  raise
143
170
 
144
- project._info.pop('links')
145
- return zip(*sorted(project._info.items()))
171
+ return _format_project(project)
146
172
 
147
173
 
148
174
  class DeleteProject(command.Command):
149
- _description = _("Delete project(s)")
175
+ _description = _(
176
+ "Delete project(s). This command will remove specified "
177
+ "existing project(s) if an active user is authorized to do "
178
+ "this. If there are resources managed by other services "
179
+ "(for example, Nova, Neutron, Cinder) associated with "
180
+ "specified project(s), delete operation will proceed "
181
+ "regardless."
182
+ )
150
183
 
151
184
  def get_parser(self, prog_name):
152
185
  parser = super().get_parser(prog_name)
@@ -164,23 +197,19 @@ class DeleteProject(command.Command):
164
197
  return parser
165
198
 
166
199
  def take_action(self, parsed_args):
167
- identity_client = self.app.client_manager.identity
200
+ identity_client = self.app.client_manager.sdk_connection.identity
168
201
 
169
- domain = None
170
- if parsed_args.domain:
171
- domain = common.find_domain(identity_client, parsed_args.domain)
172
202
  errors = 0
173
203
  for project in parsed_args.projects:
174
204
  try:
175
- if domain is not None:
176
- project_obj = utils.find_resource(
177
- identity_client.projects, project, domain_id=domain.id
178
- )
179
- else:
180
- project_obj = utils.find_resource(
181
- identity_client.projects, project
182
- )
183
- identity_client.projects.delete(project_obj.id)
205
+ project = common.find_project_id_sdk(
206
+ identity_client,
207
+ project,
208
+ domain_name_or_id=parsed_args.domain,
209
+ validate_actor_existence=True,
210
+ validate_domain_actor_existence=False,
211
+ )
212
+ identity_client.delete_project(project)
184
213
  except Exception as e:
185
214
  errors += 1
186
215
  LOG.error(
@@ -261,38 +290,46 @@ class ListProject(command.Lister):
261
290
  return parser
262
291
 
263
292
  def take_action(self, parsed_args):
264
- identity_client = self.app.client_manager.identity
265
- columns: tuple[str, ...] = ('ID', 'Name')
293
+ identity_client = self.app.client_manager.sdk_connection.identity
294
+
295
+ column_headers: tuple[str, ...] = ('ID', 'Name')
296
+ if parsed_args.long:
297
+ column_headers += ('Domain ID', 'Description', 'Enabled')
298
+
299
+ columns: tuple[str, ...] = ('id', 'name')
266
300
  if parsed_args.long:
267
- columns += ('Domain ID', 'Description', 'Enabled')
301
+ columns += ('domain_id', 'description', 'is_enabled')
302
+
268
303
  kwargs = {}
269
304
 
270
305
  domain_id = None
271
306
  if parsed_args.domain:
272
- domain_id = common.find_domain(
307
+ domain_id = common.find_domain_id_sdk(
273
308
  identity_client, parsed_args.domain
274
- ).id
275
- kwargs['domain'] = domain_id
309
+ )
310
+ kwargs['domain_id'] = domain_id
276
311
 
277
312
  if parsed_args.parent:
278
- parent_id = common.find_project(
279
- identity_client, parsed_args.parent
280
- ).id
281
- kwargs['parent'] = parent_id
313
+ parent_id = common.find_project_id_sdk(
314
+ identity_client,
315
+ parsed_args.parent,
316
+ domain_name_or_id=domain_id,
317
+ )
318
+ kwargs['parent_id'] = parent_id
282
319
 
320
+ user = None
283
321
  if parsed_args.user:
284
322
  if parsed_args.domain:
285
- user_id = utils.find_resource(
286
- identity_client.users,
323
+ user = common.find_user_id_sdk(
324
+ identity_client,
287
325
  parsed_args.user,
288
- domain_id=domain_id,
289
- ).id
326
+ domain_name_or_id=domain_id,
327
+ )
290
328
  else:
291
- user_id = utils.find_resource(
292
- identity_client.users, parsed_args.user
293
- ).id
294
-
295
- kwargs['user'] = user_id
329
+ user = common.find_user_id_sdk(
330
+ identity_client,
331
+ parsed_args.user,
332
+ )
296
333
 
297
334
  if parsed_args.is_enabled is not None:
298
335
  kwargs['is_enabled'] = parsed_args.is_enabled
@@ -301,32 +338,29 @@ class ListProject(command.Lister):
301
338
 
302
339
  if parsed_args.my_projects:
303
340
  # NOTE(adriant): my-projects supersedes all the other filters.
304
- kwargs = {'user': self.app.client_manager.auth_ref.user_id}
341
+ kwargs = {}
342
+ user = self.app.client_manager.auth_ref.user_id
305
343
 
306
- try:
307
- data = identity_client.projects.list(**kwargs)
308
- except ks_exc.Forbidden:
309
- # NOTE(adriant): if no filters, assume a forbidden is non-admin
310
- # wanting their own project list.
311
- if not kwargs:
312
- user = self.app.client_manager.auth_ref.user_id
313
- data = identity_client.projects.list(user=user)
314
- else:
315
- raise
344
+ if user:
345
+ data = identity_client.user_projects(user, **kwargs)
346
+ else:
347
+ try:
348
+ data = identity_client.projects(**kwargs)
349
+ except sdk_exc.ForbiddenException:
350
+ # NOTE(adriant): if no filters, assume a forbidden is non-admin
351
+ # wanting their own project list.
352
+ if not kwargs:
353
+ user = self.app.client_manager.auth_ref.user_id
354
+ data = identity_client.user_projects(user)
355
+ else:
356
+ raise
316
357
 
317
358
  if parsed_args.sort:
318
359
  data = utils.sort_items(data, parsed_args.sort)
319
360
 
320
361
  return (
321
- columns,
322
- (
323
- utils.get_item_properties(
324
- s,
325
- columns,
326
- formatters={},
327
- )
328
- for s in data
329
- ),
362
+ column_headers,
363
+ (utils.get_item_properties(s, columns) for s in data),
330
364
  )
331
365
 
332
366
 
@@ -385,11 +419,7 @@ class SetProject(command.Command):
385
419
  return parser
386
420
 
387
421
  def take_action(self, parsed_args):
388
- identity_client = self.app.client_manager.identity
389
-
390
- project = common.find_project(
391
- identity_client, parsed_args.project, parsed_args.domain
392
- )
422
+ identity_client = self.app.client_manager.sdk_connection.identity
393
423
 
394
424
  kwargs = {}
395
425
  if parsed_args.name:
@@ -402,9 +432,50 @@ class SetProject(command.Command):
402
432
  kwargs['options'] = {'immutable': parsed_args.immutable}
403
433
  if parsed_args.properties:
404
434
  kwargs.update(parsed_args.properties)
405
- tag.update_tags_in_args(parsed_args, project, kwargs)
406
435
 
407
- identity_client.projects.update(project.id, **kwargs)
436
+ if parsed_args.domain:
437
+ domain = common.find_domain_id_sdk(
438
+ identity_client,
439
+ parsed_args.domain,
440
+ validate_actor_existence=False,
441
+ )
442
+ project = identity_client.find_project(
443
+ parsed_args.project,
444
+ domain_id=domain,
445
+ ignore_missing=True,
446
+ )
447
+ else:
448
+ project = identity_client.find_project(
449
+ parsed_args.project,
450
+ ignore_missing=True,
451
+ )
452
+
453
+ if (
454
+ parsed_args.tags
455
+ or parsed_args.remove_tags
456
+ or parsed_args.clear_tags
457
+ ):
458
+ existing_tags = []
459
+ if project:
460
+ existing_tags = project.tags
461
+
462
+ if parsed_args.clear_tags:
463
+ kwargs['tags'] = []
464
+ else:
465
+ existing_tags_set = set(existing_tags)
466
+ if parsed_args.remove_tags:
467
+ tags = sorted(
468
+ existing_tags_set - set(parsed_args.remove_tags)
469
+ )
470
+ if parsed_args.tags:
471
+ tags = sorted(
472
+ existing_tags_set.union(set(parsed_args.tags))
473
+ )
474
+ kwargs['tags'] = tags
475
+
476
+ project_id = project.id if project else parsed_args.project
477
+
478
+ identity_client.update_project(project_id, **kwargs)
408
479
 
409
480
 
410
481
  class ShowProject(command.ShowOne):
@@ -437,31 +508,36 @@ class ShowProject(command.ShowOne):
437
508
  return parser
438
509
 
439
510
  def take_action(self, parsed_args):
440
- identity_client = self.app.client_manager.identity
511
+ identity_client = self.app.client_manager.sdk_connection.identity
441
512
 
442
- project_str = common._get_token_resource(
443
- identity_client, 'project', parsed_args.project, parsed_args.domain
444
- )
513
+ kwargs = {}
445
514
 
515
+ domain = None
446
516
  if parsed_args.domain:
447
- domain = common.find_domain(identity_client, parsed_args.domain)
448
- project = utils.find_resource(
449
- identity_client.projects, project_str, domain_id=domain.id
450
- )
451
- else:
452
- project = utils.find_resource(
453
- identity_client.projects, project_str
517
+ domain = common.find_domain_id_sdk(
518
+ identity_client, parsed_args.domain
454
519
  )
455
520
 
456
- if parsed_args.parents or parsed_args.children:
457
- # NOTE(RuiChen): utils.find_resource() can't pass kwargs,
458
- # if id query hit the result at first, so call
459
- # identity manager.get() with kwargs directly.
460
- project = identity_client.projects.get(
461
- project.id,
462
- parents_as_ids=parsed_args.parents,
463
- subtree_as_ids=parsed_args.children,
464
- )
521
+ kwargs['domain_id'] = domain
522
+
523
+ # Get project id first; otherwise, find_project() can't find
524
+ # parents/children if only project name was given
525
+ project = common.find_project_id_sdk(
526
+ identity_client,
527
+ parsed_args.project,
528
+ domain_name_or_id=domain,
529
+ validate_actor_existence=False,
530
+ validate_domain_actor_existence=False,
531
+ )
532
+
533
+ # Include these options as query parameters if they are provided
534
+ if parsed_args.parents:
535
+ kwargs['parents_as_ids'] = True
536
+ if parsed_args.children:
537
+ kwargs['subtree_as_ids'] = True
538
+
539
+ project = identity_client.find_project(
540
+ project, **kwargs, ignore_missing=False
541
+ )
465
542
 
466
- project._info.pop('links')
467
- return zip(*sorted(project._info.items()))
543
+ return _format_project(project)
@@ -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