python-openstackclient 8.0.0__py3-none-any.whl → 8.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 (85) hide show
  1. openstackclient/compute/client.py +5 -0
  2. openstackclient/compute/v2/console.py +7 -0
  3. openstackclient/compute/v2/console_connection.py +48 -0
  4. openstackclient/compute/v2/keypair.py +10 -3
  5. openstackclient/compute/v2/server.py +75 -10
  6. openstackclient/compute/v2/server_event.py +1 -1
  7. openstackclient/identity/common.py +79 -0
  8. openstackclient/identity/v3/application_credential.py +2 -2
  9. openstackclient/identity/v3/domain.py +62 -43
  10. openstackclient/identity/v3/group.py +113 -68
  11. openstackclient/identity/v3/project.py +17 -0
  12. openstackclient/identity/v3/user.py +38 -5
  13. openstackclient/image/client.py +5 -0
  14. openstackclient/image/v2/image.py +11 -11
  15. openstackclient/network/client.py +0 -6
  16. openstackclient/network/v2/floating_ip.py +58 -29
  17. openstackclient/network/v2/network_qos_rule.py +3 -11
  18. openstackclient/network/v2/router.py +1 -1
  19. openstackclient/network/v2/security_group.py +5 -4
  20. openstackclient/network/v2/security_group_rule.py +1 -1
  21. openstackclient/shell.py +1 -1
  22. openstackclient/tests/functional/base.py +5 -1
  23. openstackclient/tests/functional/compute/v2/test_keypair.py +41 -5
  24. openstackclient/tests/unit/compute/v2/fakes.py +81 -305
  25. openstackclient/tests/unit/compute/v2/test_console.py +18 -1
  26. openstackclient/tests/unit/compute/v2/test_console_connection.py +72 -0
  27. openstackclient/tests/unit/compute/v2/test_flavor.py +1 -1
  28. openstackclient/tests/unit/compute/v2/test_keypair.py +12 -5
  29. openstackclient/tests/unit/compute/v2/test_server.py +169 -46
  30. openstackclient/tests/unit/compute/v2/test_server_backup.py +32 -71
  31. openstackclient/tests/unit/compute/v2/test_server_event.py +2 -2
  32. openstackclient/tests/unit/compute/v2/test_server_image.py +33 -72
  33. openstackclient/tests/unit/compute/v2/test_server_migration.py +4 -4
  34. openstackclient/tests/unit/identity/v3/test_application_credential.py +47 -25
  35. openstackclient/tests/unit/identity/v3/test_domain.py +115 -105
  36. openstackclient/tests/unit/identity/v3/test_group.py +353 -202
  37. openstackclient/tests/unit/identity/v3/test_project.py +16 -0
  38. openstackclient/tests/unit/identity/v3/test_user.py +86 -6
  39. openstackclient/tests/unit/image/v1/test_image.py +8 -9
  40. openstackclient/tests/unit/image/v2/test_image.py +49 -49
  41. openstackclient/tests/unit/network/v2/fakes.py +405 -485
  42. openstackclient/tests/unit/network/v2/test_floating_ip_network.py +13 -19
  43. openstackclient/tests/unit/network/v2/test_l3_conntrack_helper.py +2 -2
  44. openstackclient/tests/unit/network/v2/test_ndp_proxy.py +1 -3
  45. openstackclient/tests/unit/network/v2/test_network.py +4 -4
  46. openstackclient/tests/unit/network/v2/test_network_agent.py +15 -29
  47. openstackclient/tests/unit/network/v2/test_network_qos_policy.py +16 -19
  48. openstackclient/tests/unit/network/v2/test_network_qos_rule.py +79 -152
  49. openstackclient/tests/unit/network/v2/test_network_qos_rule_type.py +4 -6
  50. openstackclient/tests/unit/network/v2/test_network_rbac.py +2 -2
  51. openstackclient/tests/unit/network/v2/test_port.py +17 -17
  52. openstackclient/tests/unit/network/v2/test_router.py +73 -57
  53. openstackclient/tests/unit/network/v2/test_security_group_network.py +25 -27
  54. openstackclient/tests/unit/network/v2/test_security_group_rule_compute.py +1 -3
  55. openstackclient/tests/unit/network/v2/test_security_group_rule_network.py +33 -39
  56. openstackclient/tests/unit/volume/v2/fakes.py +1 -2
  57. openstackclient/tests/unit/volume/v2/test_service.py +57 -91
  58. openstackclient/tests/unit/volume/v2/test_volume.py +108 -105
  59. openstackclient/tests/unit/volume/v2/test_volume_backup.py +141 -148
  60. openstackclient/tests/unit/volume/v2/test_volume_snapshot.py +293 -283
  61. openstackclient/tests/unit/volume/v3/test_block_storage_log_level.py +61 -71
  62. openstackclient/tests/unit/volume/v3/test_service.py +221 -141
  63. openstackclient/tests/unit/volume/v3/test_volume.py +130 -119
  64. openstackclient/tests/unit/volume/v3/test_volume_attachment.py +1 -1
  65. openstackclient/tests/unit/volume/v3/test_volume_backup.py +198 -203
  66. openstackclient/tests/unit/volume/v3/test_volume_snapshot.py +682 -47
  67. openstackclient/volume/v2/service.py +41 -38
  68. openstackclient/volume/v2/volume.py +63 -37
  69. openstackclient/volume/v2/volume_backup.py +9 -3
  70. openstackclient/volume/v2/volume_snapshot.py +121 -84
  71. openstackclient/volume/v3/block_storage_log_level.py +22 -28
  72. openstackclient/volume/v3/service.py +105 -14
  73. openstackclient/volume/v3/volume.py +200 -39
  74. openstackclient/volume/v3/volume_backup.py +24 -19
  75. openstackclient/volume/v3/volume_snapshot.py +485 -10
  76. {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.1.0.dist-info}/AUTHORS +8 -0
  77. python_openstackclient-8.1.0.dist-info/METADATA +264 -0
  78. {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.1.0.dist-info}/RECORD +83 -81
  79. {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.1.0.dist-info}/entry_points.txt +7 -6
  80. python_openstackclient-8.1.0.dist-info/pbr.json +1 -0
  81. python_openstackclient-8.0.0.dist-info/METADATA +0 -166
  82. python_openstackclient-8.0.0.dist-info/pbr.json +0 -1
  83. {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.1.0.dist-info}/LICENSE +0 -0
  84. {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.1.0.dist-info}/WHEEL +0 -0
  85. {python_openstackclient-8.0.0.dist-info → python_openstackclient-8.1.0.dist-info}/top_level.txt +0 -0
@@ -46,3 +46,8 @@ def build_option_parser(parser):
46
46
  % DEFAULT_API_VERSION,
47
47
  )
48
48
  return parser
49
+
50
+
51
+ def check_api_version(check_version):
52
+ # SDK supports auto-negotiation for us: always return True
53
+ return True
@@ -106,6 +106,13 @@ class ShowConsoleURL(command.ShowOne):
106
106
  const='spice-html5',
107
107
  help=_("Show SPICE console URL"),
108
108
  )
109
+ type_group.add_argument(
110
+ '--spice-direct',
111
+ dest='url_type',
112
+ action='store_const',
113
+ const='spice-direct',
114
+ help=_("Show SPICE direct protocol native console URL"),
115
+ )
109
116
  type_group.add_argument(
110
117
  '--rdp',
111
118
  dest='url_type',
@@ -0,0 +1,48 @@
1
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+ # not use this file except in compliance with the License. You may obtain
3
+ # a copy of the License at
4
+ #
5
+ # http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+ # License for the specific language governing permissions and limitations
11
+ # under the License.
12
+ #
13
+
14
+ """Compute v2 Console auth token implementations."""
15
+
16
+ from osc_lib.command import command
17
+ from osc_lib import utils
18
+
19
+ from openstackclient.i18n import _
20
+
21
+
22
+ def _get_console_connection_columns(item):
23
+ column_map: dict[str, str] = {}
24
+ hidden_columns = ['id', 'location', 'name']
25
+ return utils.get_osc_show_columns_for_sdk_resource(
26
+ item, column_map, hidden_columns
27
+ )
28
+
29
+
30
+ class ShowConsoleConnectionInformation(command.ShowOne):
31
+ _description = _("Show server's remote console connection information")
32
+
33
+ def get_parser(self, prog_name):
34
+ parser = super().get_parser(prog_name)
35
+ parser.add_argument(
36
+ 'token',
37
+ metavar='<token>',
38
+ help=_("Nova console token to lookup"),
39
+ )
40
+ return parser
41
+
42
+ def take_action(self, parsed_args):
43
+ compute_client = self.app.client_manager.compute
44
+ data = compute_client.validate_console_auth_token(parsed_args.token)
45
+ display_columns, columns = _get_console_connection_columns(data)
46
+ data = utils.get_dict_properties(data, columns)
47
+
48
+ return (display_columns, data)
@@ -300,6 +300,7 @@ class ListKeypair(command.Lister):
300
300
  def take_action(self, parsed_args):
301
301
  compute_client = self.app.client_manager.compute
302
302
  identity_client = self.app.client_manager.identity
303
+ identity_sdk_client = self.app.client_manager.sdk_connection.identity
303
304
 
304
305
  kwargs = {}
305
306
 
@@ -345,11 +346,17 @@ class ListKeypair(command.Lister):
345
346
  parsed_args.project,
346
347
  parsed_args.project_domain,
347
348
  ).id
348
- users = identity_client.users.list(tenant_id=project)
349
+ assignments = identity_sdk_client.role_assignments(
350
+ scope_project_id=project
351
+ )
352
+ user_ids = set()
353
+ for assignment in assignments:
354
+ if assignment.user:
355
+ user_ids.add(assignment.user['id'])
349
356
 
350
357
  data = []
351
- for user in users:
352
- kwargs['user_id'] = user.id
358
+ for user_id in user_ids:
359
+ kwargs['user_id'] = user_id
353
360
  data.extend(compute_client.keypairs(**kwargs))
354
361
  elif parsed_args.user:
355
362
  if not sdk_utils.supports_microversion(compute_client, '2.10'):
@@ -21,7 +21,6 @@ import getpass
21
21
  import json
22
22
  import logging
23
23
  import os
24
- import typing as ty
25
24
 
26
25
  from cliff import columns as cliff_columns
27
26
  import iso8601
@@ -185,6 +184,7 @@ def _prep_server_detail(compute_client, image_client, server, *, refresh=True):
185
184
  'user_data': 'OS-EXT-SRV-ATTR:user_data',
186
185
  'vm_state': 'OS-EXT-STS:vm_state',
187
186
  'pinned_availability_zone': 'pinned_availability_zone',
187
+ 'scheduler_hints': 'scheduler_hints',
188
188
  }
189
189
  # Some columns returned by openstacksdk should not be shown because they're
190
190
  # either irrelevant or duplicates
@@ -205,7 +205,6 @@ def _prep_server_detail(compute_client, image_client, server, *, refresh=True):
205
205
  'min_count',
206
206
  'networks',
207
207
  'personality',
208
- 'scheduler_hints',
209
208
  # aliases
210
209
  'volumes',
211
210
  # unnecessary
@@ -236,6 +235,11 @@ def _prep_server_detail(compute_client, image_client, server, *, refresh=True):
236
235
 
237
236
  info = data
238
237
 
238
+ # NOTE(dviroel): microversion 2.100 is now retrieving scheduler_hints
239
+ # content from request_spec on detailed responses
240
+ if not sdk_utils.supports_microversion(compute_client, '2.100'):
241
+ info.pop('scheduler_hints', None)
242
+
239
243
  # Convert the image blob to a name
240
244
  image_info = info.get('image', {})
241
245
  if image_info and any(image_info.values()):
@@ -322,6 +326,11 @@ def _prep_server_detail(compute_client, image_client, server, *, refresh=True):
322
326
  info['OS-EXT-STS:power_state']
323
327
  )
324
328
 
329
+ if 'scheduler_hints' in info:
330
+ info['scheduler_hints'] = format_columns.DictListColumn(
331
+ info.pop('scheduler_hints', {}),
332
+ )
333
+
325
334
  return info
326
335
 
327
336
 
@@ -1864,7 +1873,7 @@ class CreateServer(command.ShowOne):
1864
1873
 
1865
1874
  # Default to empty list if nothing was specified and let nova
1866
1875
  # decide the default behavior.
1867
- networks: ty.Union[str, list[dict[str, str]], None] = []
1876
+ networks: str | list[dict[str, str]] | None = []
1868
1877
 
1869
1878
  if 'auto' in parsed_args.nics or 'none' in parsed_args.nics:
1870
1879
  if len(parsed_args.nics) > 1:
@@ -1938,9 +1947,9 @@ class CreateServer(command.ShowOne):
1938
1947
  network['port'] = nic['port-id']
1939
1948
 
1940
1949
  if nic['v4-fixed-ip']:
1941
- network['fixed'] = nic['v4-fixed-ip']
1950
+ network['fixed_ip'] = nic['v4-fixed-ip']
1942
1951
  elif nic['v6-fixed-ip']:
1943
- network['fixed'] = nic['v6-fixed-ip']
1952
+ network['fixed_ip'] = nic['v6-fixed-ip']
1944
1953
 
1945
1954
  if nic.get('tag'): # tags are optional
1946
1955
  network['tag'] = nic['tag']
@@ -2834,14 +2843,20 @@ class ListServer(command.Lister):
2834
2843
  'pinned_availability_zone',
2835
2844
  'hypervisor_hostname',
2836
2845
  'metadata',
2846
+ 'scheduler_hints',
2837
2847
  )
2838
2848
  column_headers += (
2839
2849
  'Availability Zone',
2840
2850
  'Pinned Availability Zone',
2841
2851
  'Host',
2842
2852
  'Properties',
2853
+ 'Scheduler Hints',
2843
2854
  )
2844
2855
 
2856
+ if parsed_args.all_projects:
2857
+ columns += ('project_id',)
2858
+ column_headers += ('Project ID',)
2859
+
2845
2860
  # support for additional columns
2846
2861
  if parsed_args.columns:
2847
2862
  for c in parsed_args.columns:
@@ -2884,6 +2899,12 @@ class ListServer(command.Lister):
2884
2899
  if c in ('Properties', "properties"):
2885
2900
  columns += ('Metadata',)
2886
2901
  column_headers += ('Properties',)
2902
+ if c in (
2903
+ 'scheduler_hints',
2904
+ "Scheduler Hints",
2905
+ ):
2906
+ columns += ('scheduler_hints',)
2907
+ column_headers += ('Scheduler Hints',)
2887
2908
 
2888
2909
  # remove duplicates
2889
2910
  column_headers = tuple(dict.fromkeys(column_headers))
@@ -2986,7 +3007,7 @@ class ListServer(command.Lister):
2986
3007
  # infrastructure failure situations.
2987
3008
  # For those servers with partial constructs we just skip the
2988
3009
  # processing of the image and flavor information.
2989
- if not hasattr(s, 'image') or not hasattr(s, 'flavor'):
3010
+ if getattr(s, 'status') == 'UNKNOWN':
2990
3011
  continue
2991
3012
 
2992
3013
  if 'id' in s.image and s.image.id is not None:
@@ -3050,6 +3071,7 @@ class ListServer(command.Lister):
3050
3071
  'metadata': format_columns.DictColumn,
3051
3072
  'security_groups_name': format_columns.ListColumn,
3052
3073
  'hypervisor_hostname': HostColumn,
3074
+ 'scheduler_hints': format_columns.DictListColumn,
3053
3075
  },
3054
3076
  )
3055
3077
  for s in data
@@ -3860,9 +3882,15 @@ host."""
3860
3882
  compute_client.evacuate_server(server, **kwargs)
3861
3883
 
3862
3884
  if parsed_args.wait:
3885
+ orig_status = server.status
3886
+ success = ['ACTIVE']
3887
+ if orig_status == 'SHUTOFF':
3888
+ success.append('SHUTOFF')
3889
+
3863
3890
  if utils.wait_for_status(
3864
3891
  compute_client.get_server,
3865
3892
  server.id,
3893
+ success_status=success,
3866
3894
  callback=_show_progress,
3867
3895
  ):
3868
3896
  self.app.stdout.write(_('Complete\n'))
@@ -4462,15 +4490,27 @@ class SetServer(command.Command):
4462
4490
  '(repeat option to set multiple properties)'
4463
4491
  ),
4464
4492
  )
4493
+ parser.add_argument(
4494
+ '--auto-approve',
4495
+ action='store_true',
4496
+ help=_(
4497
+ "Allow server state override without asking for confirmation"
4498
+ ),
4499
+ )
4465
4500
  parser.add_argument(
4466
4501
  '--state',
4467
4502
  metavar='<state>',
4468
4503
  choices=['active', 'error'],
4469
4504
  help=_(
4470
- 'New server state '
4471
- '**WARNING** This can result in instances that are no longer '
4472
- 'usable and should be used with caution '
4473
- '(admin only)'
4505
+ 'New server state.'
4506
+ '**WARNING** Resetting the state is intended to work around '
4507
+ 'servers stuck in an intermediate state, such as deleting. '
4508
+ 'If the server is in an error state then this is almost '
4509
+ 'never the correct command to run and you should prefer hard '
4510
+ 'reboot where possible. In particular, if the server is in '
4511
+ 'an error state due to a move operation, setting the state '
4512
+ 'can result in instances that are no longer usable. Proceed '
4513
+ 'with caution. (admin only)'
4474
4514
  ),
4475
4515
  )
4476
4516
  parser.add_argument(
@@ -4505,6 +4545,20 @@ class SetServer(command.Command):
4505
4545
  )
4506
4546
  return parser
4507
4547
 
4548
+ @staticmethod
4549
+ def ask_user_yesno(msg):
4550
+ """Ask user Y/N question
4551
+
4552
+ :param str msg: question text
4553
+ :return bool: User choice
4554
+ """
4555
+ while True:
4556
+ answer = getpass.getpass('{} [{}]: '.format(msg, 'y/n'))
4557
+ if answer in ('y', 'Y', 'yes'):
4558
+ return True
4559
+ elif answer in ('n', 'N', 'no'):
4560
+ return False
4561
+
4508
4562
  def take_action(self, parsed_args):
4509
4563
  compute_client = self.app.client_manager.compute
4510
4564
  server = compute_client.find_server(
@@ -4555,6 +4609,17 @@ class SetServer(command.Command):
4555
4609
  )
4556
4610
 
4557
4611
  if parsed_args.state:
4612
+ if not parsed_args.auto_approve:
4613
+ if not self.ask_user_yesno(
4614
+ _(
4615
+ "Resetting the server state can make it much harder "
4616
+ "to recover a server from an error state. If the "
4617
+ "server is in error status due to a failed move "
4618
+ "operation then this is likely not the correct "
4619
+ "approach to fix the problem. Do you wish to continue?"
4620
+ )
4621
+ ):
4622
+ return
4558
4623
  compute_client.reset_server_state(server, state=parsed_args.state)
4559
4624
 
4560
4625
  if parsed_args.root_password:
@@ -82,7 +82,7 @@ class ServerActionEventColumn(columns.FormattableColumn):
82
82
 
83
83
 
84
84
  def _get_server_event_columns(item, client):
85
- hidden_columns = ['name', 'server_id', 'links', 'location']
85
+ hidden_columns = ['name', 'server_id', 'links', 'location', 'finish_time']
86
86
 
87
87
  if not sdk_utils.supports_microversion(client, '2.58'):
88
88
  # updated_at was introduced in 2.58
@@ -189,6 +189,16 @@ def find_domain(identity_client, name_or_id):
189
189
  )
190
190
 
191
191
 
192
+ def find_domain_id_sdk(
193
+ identity_client, name_or_id, *, validate_actor_existence=True
194
+ ):
195
+ return _find_sdk_id(
196
+ identity_client.find_domain,
197
+ name_or_id=name_or_id,
198
+ validate_actor_existence=validate_actor_existence,
199
+ )
200
+
201
+
192
202
  def find_group(identity_client, name_or_id, domain_name_or_id=None):
193
203
  if domain_name_or_id is None:
194
204
  return _find_identity_resource(
@@ -204,6 +214,33 @@ def find_group(identity_client, name_or_id, domain_name_or_id=None):
204
214
  )
205
215
 
206
216
 
217
+ def find_group_id_sdk(
218
+ identity_client,
219
+ name_or_id,
220
+ domain_name_or_id=None,
221
+ *,
222
+ validate_actor_existence=True,
223
+ ):
224
+ if domain_name_or_id is None:
225
+ return _find_sdk_id(
226
+ identity_client.find_group,
227
+ name_or_id=name_or_id,
228
+ validate_actor_existence=validate_actor_existence,
229
+ )
230
+
231
+ domain_id = find_domain_id_sdk(
232
+ identity_client,
233
+ name_or_id=domain_name_or_id,
234
+ validate_actor_existence=validate_actor_existence,
235
+ )
236
+ return _find_sdk_id(
237
+ identity_client.find_group,
238
+ name_or_id=name_or_id,
239
+ validate_actor_existence=validate_actor_existence,
240
+ domain_id=domain_id,
241
+ )
242
+
243
+
207
244
  def find_project(identity_client, name_or_id, domain_name_or_id=None):
208
245
  if domain_name_or_id is None:
209
246
  return _find_identity_resource(
@@ -229,6 +266,32 @@ def find_user(identity_client, name_or_id, domain_name_or_id=None):
229
266
  )
230
267
 
231
268
 
269
+ def find_user_id_sdk(
270
+ identity_client,
271
+ name_or_id,
272
+ domain_name_or_id=None,
273
+ *,
274
+ validate_actor_existence=True,
275
+ ):
276
+ if domain_name_or_id is None:
277
+ return _find_sdk_id(
278
+ identity_client.find_user,
279
+ name_or_id=name_or_id,
280
+ validate_actor_existence=validate_actor_existence,
281
+ )
282
+ domain_id = find_domain_id_sdk(
283
+ identity_client,
284
+ name_or_id=domain_name_or_id,
285
+ validate_actor_existence=validate_actor_existence,
286
+ )
287
+ return _find_sdk_id(
288
+ identity_client.find_user,
289
+ name_or_id=name_or_id,
290
+ validate_actor_existence=validate_actor_existence,
291
+ domain_id=domain_id,
292
+ )
293
+
294
+
232
295
  def _find_identity_resource(
233
296
  identity_client_manager, name_or_id, resource_type, **kwargs
234
297
  ):
@@ -269,6 +332,22 @@ def _find_identity_resource(
269
332
  return resource_type(None, {'id': name_or_id, 'name': name_or_id})
270
333
 
271
334
 
335
+ def _find_sdk_id(
336
+ find_command, name_or_id, *, validate_actor_existence=True, **kwargs
337
+ ):
338
+ try:
339
+ resource = find_command(
340
+ name_or_id=name_or_id, ignore_missing=False, **kwargs
341
+ )
342
+ except sdk_exceptions.ForbiddenException:
343
+ return name_or_id
344
+ except sdk_exceptions.ResourceNotFound as exc:
345
+ if not validate_actor_existence:
346
+ return name_or_id
347
+ raise exceptions.CommandError from exc
348
+ return resource.id
349
+
350
+
272
351
  def get_immutable_options(parsed_args):
273
352
  options = {}
274
353
  if parsed_args.immutable:
@@ -269,9 +269,9 @@ class ListApplicationCredential(command.Lister):
269
269
  def take_action(self, parsed_args):
270
270
  identity_client = self.app.client_manager.sdk_connection.identity
271
271
  if parsed_args.user:
272
- user_id = common.find_user(
272
+ user_id = common.find_user_id_sdk(
273
273
  identity_client, parsed_args.user, parsed_args.user_domain
274
- ).id
274
+ )
275
275
  else:
276
276
  conn = self.app.client_manager.sdk_connection
277
277
  user_id = conn.config.get_auth().get_user_id(conn.identity)
@@ -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,25 @@ 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
68
-
69
- enabled = True
70
- if parsed_args.disable:
71
- enabled = False
95
+ identity_client = self.app.client_manager.sdk_connection.identity
72
96
 
73
97
  options = common.get_immutable_options(parsed_args)
74
98
 
75
99
  try:
76
- domain = identity_client.domains.create(
100
+ domain = identity_client.create_domain(
77
101
  name=parsed_args.name,
78
102
  description=parsed_args.description,
79
103
  options=options,
80
- enabled=enabled,
104
+ is_enabled=parsed_args.is_enabled,
81
105
  )
82
- except ks_exc.Conflict:
106
+ except sdk_exceptions.ConflictException:
83
107
  if parsed_args.or_show:
84
- domain = utils.find_resource(
85
- identity_client.domains, parsed_args.name
86
- )
108
+ domain = identity_client.find_domain(parsed_args.name)
87
109
  LOG.info(_('Returning existing domain %s'), domain.name)
88
110
  else:
89
111
  raise
90
112
 
91
- domain._info.pop('links')
92
- return zip(*sorted(domain._info.items()))
113
+ return _format_domain(domain)
93
114
 
94
115
 
95
116
  class DeleteDomain(command.Command):
@@ -106,12 +127,12 @@ class DeleteDomain(command.Command):
106
127
  return parser
107
128
 
108
129
  def take_action(self, parsed_args):
109
- identity_client = self.app.client_manager.identity
130
+ identity_client = self.app.client_manager.sdk_connection.identity
110
131
  result = 0
111
132
  for i in parsed_args.domain:
112
133
  try:
113
- domain = utils.find_resource(identity_client.domains, i)
114
- identity_client.domains.delete(domain.id)
134
+ domain = identity_client.find_domain(i, ignore_missing=False)
135
+ identity_client.delete_domain(domain.id)
115
136
  except Exception as e:
116
137
  result += 1
117
138
  LOG.error(
@@ -143,7 +164,7 @@ class ListDomain(command.Lister):
143
164
  )
144
165
  parser.add_argument(
145
166
  '--enabled',
146
- dest='enabled',
167
+ dest='is_enabled',
147
168
  action='store_true',
148
169
  help=_('The domains that are enabled will be returned'),
149
170
  )
@@ -153,13 +174,17 @@ class ListDomain(command.Lister):
153
174
  kwargs = {}
154
175
  if parsed_args.name:
155
176
  kwargs['name'] = parsed_args.name
156
- if parsed_args.enabled:
157
- kwargs['enabled'] = True
177
+ if parsed_args.is_enabled:
178
+ kwargs['is_enabled'] = True
179
+
180
+ columns = ('id', 'name', 'is_enabled', 'description')
181
+ column_headers = ('ID', 'Name', 'Enabled', 'Description')
182
+ data = self.app.client_manager.sdk_connection.identity.domains(
183
+ **kwargs
184
+ )
158
185
 
159
- columns = ('ID', 'Name', 'Enabled', 'Description')
160
- data = self.app.client_manager.identity.domains.list(**kwargs)
161
186
  return (
162
- columns,
187
+ column_headers,
163
188
  (
164
189
  utils.get_item_properties(
165
190
  s,
@@ -194,38 +219,38 @@ class SetDomain(command.Command):
194
219
  enable_group = parser.add_mutually_exclusive_group()
195
220
  enable_group.add_argument(
196
221
  '--enable',
222
+ dest='is_enabled',
197
223
  action='store_true',
224
+ default=None,
198
225
  help=_('Enable domain'),
199
226
  )
200
227
  enable_group.add_argument(
201
228
  '--disable',
202
- action='store_true',
229
+ dest='is_enabled',
230
+ action='store_false',
231
+ default=None,
203
232
  help=_('Disable domain'),
204
233
  )
205
234
  common.add_resource_option_to_parser(parser)
206
235
  return parser
207
236
 
208
237
  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
- )
238
+ identity_client = self.app.client_manager.sdk_connection.identity
239
+ domain = identity_client.find_domain(parsed_args.domain)
213
240
  kwargs = {}
214
241
  if parsed_args.name:
215
242
  kwargs['name'] = parsed_args.name
216
243
  if parsed_args.description:
217
244
  kwargs['description'] = parsed_args.description
218
245
 
219
- if parsed_args.enable:
220
- kwargs['enabled'] = True
221
- if parsed_args.disable:
222
- kwargs['enabled'] = False
246
+ if parsed_args.is_enabled is not None:
247
+ kwargs['is_enabled'] = parsed_args.is_enabled
223
248
 
224
249
  options = common.get_immutable_options(parsed_args)
225
250
  if options:
226
251
  kwargs['options'] = options
227
252
 
228
- identity_client.domains.update(domain.id, **kwargs)
253
+ identity_client.update_domain(domain.id, **kwargs)
229
254
 
230
255
 
231
256
  class ShowDomain(command.ShowOne):
@@ -241,13 +266,7 @@ class ShowDomain(command.ShowOne):
241
266
  return parser
242
267
 
243
268
  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)
269
+ identity_client = self.app.client_manager.sdk_connection.identity
270
+ domain = identity_client.find_domain(parsed_args.domain)
251
271
 
252
- domain._info.pop('links')
253
- return zip(*sorted(domain._info.items()))
272
+ return _format_domain(domain)