python-openstackclient 8.0.0__py3-none-any.whl → 8.2.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 (106) hide show
  1. openstackclient/api/compute_v2.py +2 -2
  2. openstackclient/api/volume_v2.py +60 -0
  3. openstackclient/api/volume_v3.py +60 -0
  4. openstackclient/compute/client.py +5 -0
  5. openstackclient/compute/v2/console.py +7 -0
  6. openstackclient/compute/v2/console_connection.py +48 -0
  7. openstackclient/compute/v2/flavor.py +14 -1
  8. openstackclient/compute/v2/keypair.py +10 -3
  9. openstackclient/compute/v2/server.py +76 -13
  10. openstackclient/compute/v2/server_event.py +1 -1
  11. openstackclient/identity/common.py +85 -11
  12. openstackclient/identity/v3/application_credential.py +88 -87
  13. openstackclient/identity/v3/domain.py +67 -49
  14. openstackclient/identity/v3/group.py +113 -68
  15. openstackclient/identity/v3/project.py +42 -20
  16. openstackclient/identity/v3/role.py +7 -2
  17. openstackclient/identity/v3/user.py +38 -5
  18. openstackclient/image/client.py +5 -0
  19. openstackclient/image/v1/image.py +16 -1
  20. openstackclient/image/v2/cache.py +10 -6
  21. openstackclient/image/v2/image.py +59 -12
  22. openstackclient/image/v2/metadef_objects.py +8 -2
  23. openstackclient/image/v2/metadef_properties.py +9 -2
  24. openstackclient/network/client.py +0 -6
  25. openstackclient/network/v2/floating_ip.py +58 -29
  26. openstackclient/network/v2/network_qos_rule.py +3 -11
  27. openstackclient/network/v2/port.py +16 -0
  28. openstackclient/network/v2/router.py +1 -1
  29. openstackclient/network/v2/security_group.py +49 -7
  30. openstackclient/network/v2/security_group_rule.py +18 -1
  31. openstackclient/shell.py +1 -1
  32. openstackclient/tests/functional/base.py +5 -1
  33. openstackclient/tests/functional/compute/v2/test_keypair.py +41 -5
  34. openstackclient/tests/functional/identity/v3/test_access_rule.py +1 -1
  35. openstackclient/tests/functional/identity/v3/test_application_credential.py +7 -7
  36. openstackclient/tests/functional/image/v2/test_image.py +36 -14
  37. openstackclient/tests/functional/volume/v2/test_volume.py +1 -1
  38. openstackclient/tests/functional/volume/v3/test_volume.py +2 -2
  39. openstackclient/tests/unit/api/test_volume_v2.py +124 -0
  40. openstackclient/tests/unit/api/test_volume_v3.py +124 -0
  41. openstackclient/tests/unit/compute/v2/fakes.py +81 -305
  42. openstackclient/tests/unit/compute/v2/test_console.py +18 -1
  43. openstackclient/tests/unit/compute/v2/test_console_connection.py +72 -0
  44. openstackclient/tests/unit/compute/v2/test_flavor.py +160 -175
  45. openstackclient/tests/unit/compute/v2/test_keypair.py +12 -5
  46. openstackclient/tests/unit/compute/v2/test_server.py +211 -97
  47. openstackclient/tests/unit/compute/v2/test_server_backup.py +32 -71
  48. openstackclient/tests/unit/compute/v2/test_server_event.py +2 -2
  49. openstackclient/tests/unit/compute/v2/test_server_image.py +33 -72
  50. openstackclient/tests/unit/compute/v2/test_server_migration.py +4 -4
  51. openstackclient/tests/unit/identity/v3/test_application_credential.py +93 -65
  52. openstackclient/tests/unit/identity/v3/test_domain.py +117 -107
  53. openstackclient/tests/unit/identity/v3/test_group.py +353 -202
  54. openstackclient/tests/unit/identity/v3/test_project.py +46 -53
  55. openstackclient/tests/unit/identity/v3/test_role.py +2 -8
  56. openstackclient/tests/unit/identity/v3/test_user.py +86 -6
  57. openstackclient/tests/unit/image/v1/test_image.py +55 -9
  58. openstackclient/tests/unit/image/v2/test_image.py +128 -58
  59. openstackclient/tests/unit/image/v2/test_metadef_objects.py +22 -0
  60. openstackclient/tests/unit/image/v2/test_metadef_properties.py +24 -10
  61. openstackclient/tests/unit/network/v2/fakes.py +406 -485
  62. openstackclient/tests/unit/network/v2/test_floating_ip_network.py +13 -19
  63. openstackclient/tests/unit/network/v2/test_l3_conntrack_helper.py +2 -2
  64. openstackclient/tests/unit/network/v2/test_ndp_proxy.py +3 -5
  65. openstackclient/tests/unit/network/v2/test_network.py +4 -4
  66. openstackclient/tests/unit/network/v2/test_network_agent.py +15 -29
  67. openstackclient/tests/unit/network/v2/test_network_qos_policy.py +16 -19
  68. openstackclient/tests/unit/network/v2/test_network_qos_rule.py +79 -152
  69. openstackclient/tests/unit/network/v2/test_network_qos_rule_type.py +4 -6
  70. openstackclient/tests/unit/network/v2/test_network_rbac.py +2 -2
  71. openstackclient/tests/unit/network/v2/test_port.py +57 -17
  72. openstackclient/tests/unit/network/v2/test_router.py +73 -57
  73. openstackclient/tests/unit/network/v2/test_security_group_network.py +31 -27
  74. openstackclient/tests/unit/network/v2/test_security_group_rule_compute.py +1 -3
  75. openstackclient/tests/unit/network/v2/test_security_group_rule_network.py +82 -39
  76. openstackclient/tests/unit/volume/v2/fakes.py +1 -2
  77. openstackclient/tests/unit/volume/v2/test_service.py +57 -91
  78. openstackclient/tests/unit/volume/v2/test_volume.py +466 -410
  79. openstackclient/tests/unit/volume/v2/test_volume_backup.py +141 -148
  80. openstackclient/tests/unit/volume/v2/test_volume_snapshot.py +293 -283
  81. openstackclient/tests/unit/volume/v3/test_block_storage_log_level.py +61 -71
  82. openstackclient/tests/unit/volume/v3/test_service.py +221 -141
  83. openstackclient/tests/unit/volume/v3/test_volume.py +569 -534
  84. openstackclient/tests/unit/volume/v3/test_volume_attachment.py +1 -1
  85. openstackclient/tests/unit/volume/v3/test_volume_backup.py +198 -203
  86. openstackclient/tests/unit/volume/v3/test_volume_snapshot.py +682 -47
  87. openstackclient/volume/v2/service.py +41 -38
  88. openstackclient/volume/v2/volume.py +140 -88
  89. openstackclient/volume/v2/volume_backup.py +9 -3
  90. openstackclient/volume/v2/volume_snapshot.py +121 -84
  91. openstackclient/volume/v3/block_storage_log_level.py +22 -28
  92. openstackclient/volume/v3/service.py +105 -14
  93. openstackclient/volume/v3/volume.py +287 -99
  94. openstackclient/volume/v3/volume_backup.py +24 -19
  95. openstackclient/volume/v3/volume_group.py +1 -1
  96. openstackclient/volume/v3/volume_snapshot.py +485 -10
  97. {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.2.0.dist-info}/AUTHORS +13 -0
  98. python_openstackclient-8.2.0.dist-info/METADATA +264 -0
  99. {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.2.0.dist-info}/RECORD +104 -98
  100. {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.2.0.dist-info}/entry_points.txt +7 -6
  101. python_openstackclient-8.2.0.dist-info/pbr.json +1 -0
  102. python_openstackclient-8.0.0.dist-info/METADATA +0 -166
  103. python_openstackclient-8.0.0.dist-info/pbr.json +0 -1
  104. {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.2.0.dist-info}/LICENSE +0 -0
  105. {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.2.0.dist-info}/WHEEL +0 -0
  106. {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.2.0.dist-info}/top_level.txt +0 -0
@@ -20,6 +20,7 @@ import json
20
20
  import logging
21
21
  import uuid
22
22
 
23
+ from cliff import columns as cliff_columns
23
24
  from osc_lib.command import command
24
25
  from osc_lib import exceptions
25
26
  from osc_lib import utils
@@ -27,10 +28,84 @@ from osc_lib import utils
27
28
  from openstackclient.i18n import _
28
29
  from openstackclient.identity import common
29
30
 
30
-
31
31
  LOG = logging.getLogger(__name__)
32
32
 
33
33
 
34
+ class RolesColumn(cliff_columns.FormattableColumn):
35
+ """Generate a formatted string of role names."""
36
+
37
+ def human_readable(self):
38
+ return utils.format_list(r['name'] for r in self._value)
39
+
40
+
41
+ def _format_application_credential(
42
+ application_credential, *, include_secret=False
43
+ ):
44
+ column_headers: tuple[str, ...] = (
45
+ 'ID',
46
+ 'Name',
47
+ 'Description',
48
+ 'Project ID',
49
+ 'Roles',
50
+ 'Unrestricted',
51
+ 'Access Rules',
52
+ 'Expires At',
53
+ )
54
+ columns: tuple[str, ...] = (
55
+ 'id',
56
+ 'name',
57
+ 'description',
58
+ 'project_id',
59
+ 'roles',
60
+ 'unrestricted',
61
+ 'access_rules',
62
+ 'expires_at',
63
+ )
64
+ if include_secret:
65
+ column_headers += ('Secret',)
66
+ columns += ('secret',)
67
+
68
+ return (
69
+ column_headers,
70
+ utils.get_item_properties(
71
+ application_credential, columns, formatters={'roles': RolesColumn}
72
+ ),
73
+ )
74
+
75
+
76
+ def _format_application_credentials(application_credentials):
77
+ column_headers = (
78
+ 'ID',
79
+ 'Name',
80
+ 'Description',
81
+ 'Project ID',
82
+ 'Roles',
83
+ 'Unrestricted',
84
+ 'Access Rules',
85
+ 'Expires At',
86
+ )
87
+ columns = (
88
+ 'id',
89
+ 'name',
90
+ 'description',
91
+ 'project_id',
92
+ 'roles',
93
+ 'unrestricted',
94
+ 'access_rules',
95
+ 'expires_at',
96
+ )
97
+
98
+ return (
99
+ column_headers,
100
+ (
101
+ utils.get_item_properties(
102
+ x, columns, formatters={'roles': RolesColumn}
103
+ )
104
+ for x in application_credentials
105
+ ),
106
+ )
107
+
108
+
34
109
  # TODO(stephenfin): Move this to osc_lib since it's useful elsewhere
35
110
  def is_uuid_like(value) -> bool:
36
111
  """Returns validation of a value as a UUID.
@@ -38,9 +113,6 @@ def is_uuid_like(value) -> bool:
38
113
  :param val: Value to verify
39
114
  :type val: string
40
115
  :returns: bool
41
-
42
- .. versionchanged:: 1.1.1
43
- Support non-lowercase UUIDs.
44
116
  """
45
117
  try:
46
118
  formatted_value = (
@@ -179,31 +251,8 @@ class CreateApplicationCredential(command.ShowOne):
179
251
  access_rules=access_rules,
180
252
  )
181
253
 
182
- # Format roles into something sensible
183
- if application_credential['roles']:
184
- roles = application_credential['roles']
185
- msg = ' '.join(r['name'] for r in roles)
186
- application_credential['roles'] = msg
187
-
188
- columns = (
189
- 'id',
190
- 'name',
191
- 'description',
192
- 'project_id',
193
- 'roles',
194
- 'unrestricted',
195
- 'access_rules',
196
- 'expires_at',
197
- 'secret',
198
- )
199
- return (
200
- columns,
201
- (
202
- utils.get_dict_properties(
203
- application_credential,
204
- columns,
205
- )
206
- ),
254
+ return _format_application_credential(
255
+ application_credential, include_secret=True
207
256
  )
208
257
 
209
258
 
@@ -252,6 +301,8 @@ class DeleteApplicationCredential(command.Command):
252
301
  ) % {'errors': errors, 'total': total}
253
302
  raise exceptions.CommandError(msg)
254
303
 
304
+ return None
305
+
255
306
 
256
307
  class ListApplicationCredential(command.Lister):
257
308
  _description = _("List application credentials")
@@ -269,46 +320,19 @@ class ListApplicationCredential(command.Lister):
269
320
  def take_action(self, parsed_args):
270
321
  identity_client = self.app.client_manager.sdk_connection.identity
271
322
  if parsed_args.user:
272
- user_id = common.find_user(
323
+ user_id = common.find_user_id_sdk(
273
324
  identity_client, parsed_args.user, parsed_args.user_domain
274
- ).id
325
+ )
275
326
  else:
276
327
  conn = self.app.client_manager.sdk_connection
277
328
  user_id = conn.config.get_auth().get_user_id(conn.identity)
278
329
 
279
- data = identity_client.application_credentials(user=user_id)
280
-
281
- data_formatted = []
282
- for ac in data:
283
- # Format roles into something sensible
284
- roles = ac['roles']
285
- msg = ' '.join(r['name'] for r in roles)
286
- ac['roles'] = msg
287
-
288
- data_formatted.append(ac)
289
-
290
- columns = (
291
- 'ID',
292
- 'Name',
293
- 'Description',
294
- 'Project ID',
295
- 'Roles',
296
- 'Unrestricted',
297
- 'Access Rules',
298
- 'Expires At',
299
- )
300
- return (
301
- columns,
302
- (
303
- utils.get_item_properties(
304
- s,
305
- columns,
306
- formatters={},
307
- )
308
- for s in data_formatted
309
- ),
330
+ application_credentials = identity_client.application_credentials(
331
+ user=user_id
310
332
  )
311
333
 
334
+ return _format_application_credentials(application_credentials)
335
+
312
336
 
313
337
  class ShowApplicationCredential(command.ShowOne):
314
338
  _description = _("Display application credential details")
@@ -327,31 +351,8 @@ class ShowApplicationCredential(command.ShowOne):
327
351
  conn = self.app.client_manager.sdk_connection
328
352
  user_id = conn.config.get_auth().get_user_id(conn.identity)
329
353
 
330
- app_cred = identity_client.find_application_credential(
354
+ application_credential = identity_client.find_application_credential(
331
355
  user_id, parsed_args.application_credential
332
356
  )
333
357
 
334
- # Format roles into something sensible
335
- roles = app_cred['roles']
336
- msg = ' '.join(r['name'] for r in roles)
337
- app_cred['roles'] = msg
338
-
339
- columns = (
340
- 'id',
341
- 'name',
342
- 'description',
343
- 'project_id',
344
- 'roles',
345
- 'unrestricted',
346
- 'access_rules',
347
- 'expires_at',
348
- )
349
- return (
350
- columns,
351
- (
352
- utils.get_dict_properties(
353
- app_cred,
354
- columns,
355
- )
356
- ),
357
- )
358
+ return _format_application_credential(application_credential)
@@ -17,7 +17,7 @@
17
17
 
18
18
  import logging
19
19
 
20
- from keystoneauth1 import exceptions as ks_exc
20
+ from openstack import exceptions as sdk_exceptions
21
21
  from osc_lib.command import command
22
22
  from osc_lib import exceptions
23
23
  from osc_lib import utils
@@ -29,6 +29,31 @@ from openstackclient.identity import common
29
29
  LOG = logging.getLogger(__name__)
30
30
 
31
31
 
32
+ def _format_domain(domain):
33
+ columns = (
34
+ 'id',
35
+ 'name',
36
+ 'is_enabled',
37
+ 'description',
38
+ 'options',
39
+ )
40
+ column_headers = (
41
+ 'id',
42
+ 'name',
43
+ 'enabled',
44
+ 'description',
45
+ 'options',
46
+ )
47
+
48
+ return (
49
+ column_headers,
50
+ utils.get_item_properties(
51
+ domain,
52
+ columns,
53
+ ),
54
+ )
55
+
56
+
32
57
  class CreateDomain(command.ShowOne):
33
58
  _description = _("Create new domain")
34
59
 
@@ -47,12 +72,15 @@ class CreateDomain(command.ShowOne):
47
72
  enable_group = parser.add_mutually_exclusive_group()
48
73
  enable_group.add_argument(
49
74
  '--enable',
75
+ dest='is_enabled',
50
76
  action='store_true',
77
+ default=True,
51
78
  help=_('Enable domain (default)'),
52
79
  )
53
80
  enable_group.add_argument(
54
81
  '--disable',
55
- action='store_true',
82
+ dest='is_enabled',
83
+ action='store_false',
56
84
  help=_('Disable domain'),
57
85
  )
58
86
  parser.add_argument(
@@ -64,32 +92,27 @@ class CreateDomain(command.ShowOne):
64
92
  return parser
65
93
 
66
94
  def take_action(self, parsed_args):
67
- identity_client = self.app.client_manager.identity
95
+ identity_client = self.app.client_manager.sdk_connection.identity
68
96
 
69
- enabled = True
70
- if parsed_args.disable:
71
- enabled = False
72
-
73
- options = common.get_immutable_options(parsed_args)
97
+ options = {}
98
+ if parsed_args.immutable is not None:
99
+ options['immutable'] = parsed_args.immutable
74
100
 
75
101
  try:
76
- domain = identity_client.domains.create(
102
+ domain = identity_client.create_domain(
77
103
  name=parsed_args.name,
78
104
  description=parsed_args.description,
79
105
  options=options,
80
- enabled=enabled,
106
+ is_enabled=parsed_args.is_enabled,
81
107
  )
82
- except ks_exc.Conflict:
108
+ except sdk_exceptions.ConflictException:
83
109
  if parsed_args.or_show:
84
- domain = utils.find_resource(
85
- identity_client.domains, parsed_args.name
86
- )
110
+ domain = identity_client.find_domain(parsed_args.name)
87
111
  LOG.info(_('Returning existing domain %s'), domain.name)
88
112
  else:
89
113
  raise
90
114
 
91
- domain._info.pop('links')
92
- return zip(*sorted(domain._info.items()))
115
+ return _format_domain(domain)
93
116
 
94
117
 
95
118
  class DeleteDomain(command.Command):
@@ -106,12 +129,12 @@ class DeleteDomain(command.Command):
106
129
  return parser
107
130
 
108
131
  def take_action(self, parsed_args):
109
- identity_client = self.app.client_manager.identity
132
+ identity_client = self.app.client_manager.sdk_connection.identity
110
133
  result = 0
111
134
  for i in parsed_args.domain:
112
135
  try:
113
- domain = utils.find_resource(identity_client.domains, i)
114
- identity_client.domains.delete(domain.id)
136
+ domain = identity_client.find_domain(i, ignore_missing=False)
137
+ identity_client.delete_domain(domain.id)
115
138
  except Exception as e:
116
139
  result += 1
117
140
  LOG.error(
@@ -143,7 +166,7 @@ class ListDomain(command.Lister):
143
166
  )
144
167
  parser.add_argument(
145
168
  '--enabled',
146
- dest='enabled',
169
+ dest='is_enabled',
147
170
  action='store_true',
148
171
  help=_('The domains that are enabled will be returned'),
149
172
  )
@@ -153,13 +176,17 @@ class ListDomain(command.Lister):
153
176
  kwargs = {}
154
177
  if parsed_args.name:
155
178
  kwargs['name'] = parsed_args.name
156
- if parsed_args.enabled:
157
- kwargs['enabled'] = True
179
+ if parsed_args.is_enabled:
180
+ kwargs['is_enabled'] = True
181
+
182
+ columns = ('id', 'name', 'is_enabled', 'description')
183
+ column_headers = ('ID', 'Name', 'Enabled', 'Description')
184
+ data = self.app.client_manager.sdk_connection.identity.domains(
185
+ **kwargs
186
+ )
158
187
 
159
- columns = ('ID', 'Name', 'Enabled', 'Description')
160
- data = self.app.client_manager.identity.domains.list(**kwargs)
161
188
  return (
162
- columns,
189
+ column_headers,
163
190
  (
164
191
  utils.get_item_properties(
165
192
  s,
@@ -194,38 +221,35 @@ class SetDomain(command.Command):
194
221
  enable_group = parser.add_mutually_exclusive_group()
195
222
  enable_group.add_argument(
196
223
  '--enable',
224
+ dest='is_enabled',
197
225
  action='store_true',
226
+ default=None,
198
227
  help=_('Enable domain'),
199
228
  )
200
229
  enable_group.add_argument(
201
230
  '--disable',
202
- action='store_true',
231
+ dest='is_enabled',
232
+ action='store_false',
233
+ default=None,
203
234
  help=_('Disable domain'),
204
235
  )
205
236
  common.add_resource_option_to_parser(parser)
206
237
  return parser
207
238
 
208
239
  def take_action(self, parsed_args):
209
- identity_client = self.app.client_manager.identity
210
- domain = utils.find_resource(
211
- identity_client.domains, parsed_args.domain
212
- )
240
+ identity_client = self.app.client_manager.sdk_connection.identity
241
+ domain = identity_client.find_domain(parsed_args.domain)
213
242
  kwargs = {}
214
243
  if parsed_args.name:
215
244
  kwargs['name'] = parsed_args.name
216
245
  if parsed_args.description:
217
246
  kwargs['description'] = parsed_args.description
247
+ if parsed_args.is_enabled is not None:
248
+ kwargs['is_enabled'] = parsed_args.is_enabled
249
+ if parsed_args.immutable is not None:
250
+ kwargs['options'] = {'immutable': parsed_args.immutable}
218
251
 
219
- if parsed_args.enable:
220
- kwargs['enabled'] = True
221
- if parsed_args.disable:
222
- kwargs['enabled'] = False
223
-
224
- options = common.get_immutable_options(parsed_args)
225
- if options:
226
- kwargs['options'] = options
227
-
228
- identity_client.domains.update(domain.id, **kwargs)
252
+ identity_client.update_domain(domain.id, **kwargs)
229
253
 
230
254
 
231
255
  class ShowDomain(command.ShowOne):
@@ -241,13 +265,7 @@ class ShowDomain(command.ShowOne):
241
265
  return parser
242
266
 
243
267
  def take_action(self, parsed_args):
244
- identity_client = self.app.client_manager.identity
245
-
246
- domain_str = common._get_token_resource(
247
- identity_client, 'domain', parsed_args.domain
248
- )
249
-
250
- domain = utils.find_resource(identity_client.domains, domain_str)
268
+ identity_client = self.app.client_manager.sdk_connection.identity
269
+ domain = identity_client.find_domain(parsed_args.domain)
251
270
 
252
- domain._info.pop('links')
253
- return zip(*sorted(domain._info.items()))
271
+ return _format_domain(domain)