python-openstackclient 10.0.0__py3-none-any.whl → 10.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 (203) hide show
  1. openstackclient/common/availability_zone.py +1 -1
  2. openstackclient/common/module.py +21 -27
  3. openstackclient/common/pagination.py +42 -4
  4. openstackclient/common/project_cleanup.py +1 -2
  5. openstackclient/common/quota.py +9 -5
  6. openstackclient/compute/v2/flavor.py +3 -1
  7. openstackclient/compute/v2/hypervisor.py +2 -0
  8. openstackclient/compute/v2/keypair.py +6 -2
  9. openstackclient/compute/v2/server.py +21 -12
  10. openstackclient/compute/v2/server_event.py +8 -1
  11. openstackclient/compute/v2/server_group.py +2 -0
  12. openstackclient/compute/v2/server_migration.py +3 -0
  13. openstackclient/compute/v2/server_volume.py +3 -1
  14. openstackclient/compute/v2/service.py +3 -1
  15. openstackclient/compute/v2/usage.py +2 -2
  16. openstackclient/identity/common.py +5 -1
  17. openstackclient/identity/v3/access_rule.py +6 -0
  18. openstackclient/identity/v3/application_credential.py +10 -3
  19. openstackclient/identity/v3/credential.py +4 -2
  20. openstackclient/identity/v3/domain.py +4 -2
  21. openstackclient/identity/v3/endpoint.py +57 -45
  22. openstackclient/identity/v3/federation_protocol.py +7 -5
  23. openstackclient/identity/v3/group.py +11 -10
  24. openstackclient/identity/v3/identity_provider.py +4 -1
  25. openstackclient/identity/v3/limit.py +5 -2
  26. openstackclient/identity/v3/mapping.py +36 -19
  27. openstackclient/identity/v3/project.py +18 -5
  28. openstackclient/identity/v3/region.py +4 -2
  29. openstackclient/identity/v3/registered_limit.py +3 -2
  30. openstackclient/identity/v3/role.py +2 -1
  31. openstackclient/identity/v3/role_assignment.py +3 -2
  32. openstackclient/identity/v3/service.py +4 -2
  33. openstackclient/identity/v3/service_provider.py +4 -2
  34. openstackclient/identity/v3/trust.py +8 -5
  35. openstackclient/identity/v3/user.py +38 -11
  36. openstackclient/image/v2/cache.py +2 -2
  37. openstackclient/image/v2/image.py +15 -9
  38. openstackclient/image/v2/metadef_namespaces.py +11 -10
  39. openstackclient/image/v2/metadef_objects.py +5 -5
  40. openstackclient/image/v2/metadef_properties.py +7 -4
  41. openstackclient/image/v2/task.py +11 -22
  42. openstackclient/network/utils.py +0 -41
  43. openstackclient/network/v2/address_group.py +13 -1
  44. openstackclient/network/v2/address_scope.py +13 -8
  45. openstackclient/network/v2/bgpvpn/bgpvpn.py +33 -19
  46. openstackclient/network/v2/bgpvpn/network_association.py +25 -13
  47. openstackclient/network/v2/bgpvpn/port_association.py +35 -21
  48. openstackclient/network/v2/bgpvpn/router_association.py +27 -14
  49. openstackclient/network/v2/default_security_group_rule.py +14 -6
  50. openstackclient/network/v2/floating_ip.py +12 -4
  51. openstackclient/network/v2/floating_ip_port_forwarding.py +12 -2
  52. openstackclient/network/v2/fwaas/group.py +34 -1
  53. openstackclient/network/v2/fwaas/rule.py +39 -3
  54. openstackclient/network/v2/ip_availability.py +13 -4
  55. openstackclient/network/v2/l3_conntrack_helper.py +14 -1
  56. openstackclient/network/v2/local_ip.py +4 -1
  57. openstackclient/network/v2/local_ip_association.py +4 -1
  58. openstackclient/network/v2/ndp_proxy.py +4 -1
  59. openstackclient/network/v2/network.py +87 -20
  60. openstackclient/network/v2/network_agent.py +32 -10
  61. openstackclient/network/v2/network_auto_allocated_topology.py +6 -5
  62. openstackclient/network/v2/network_flavor.py +19 -6
  63. openstackclient/network/v2/network_flavor_profile.py +20 -6
  64. openstackclient/network/v2/network_meter.py +19 -6
  65. openstackclient/network/v2/network_meter_rule.py +20 -2
  66. openstackclient/network/v2/network_qos_policy.py +15 -7
  67. openstackclient/network/v2/network_qos_rule.py +16 -1
  68. openstackclient/network/v2/network_qos_rule_type.py +16 -5
  69. openstackclient/network/v2/network_rbac.py +12 -5
  70. openstackclient/network/v2/network_segment.py +13 -1
  71. openstackclient/network/v2/network_segment_range.py +15 -3
  72. openstackclient/network/v2/network_trunk.py +4 -1
  73. openstackclient/network/v2/port.py +88 -12
  74. openstackclient/network/v2/router.py +27 -16
  75. openstackclient/network/v2/security_group.py +18 -49
  76. openstackclient/network/v2/security_group_rule.py +18 -5
  77. openstackclient/network/v2/subnet.py +15 -7
  78. openstackclient/network/v2/subnet_pool.py +13 -8
  79. openstackclient/network/v2/taas/tap_flow.py +13 -3
  80. openstackclient/network/v2/taas/tap_mirror.py +7 -4
  81. openstackclient/network/v2/taas/tap_service.py +4 -1
  82. openstackclient/object/v1/container.py +3 -1
  83. openstackclient/object/v1/object.py +3 -1
  84. openstackclient/tests/functional/identity/v3/common.py +34 -0
  85. openstackclient/tests/functional/identity/v3/test_application_credential.py +1 -1
  86. openstackclient/tests/functional/identity/v3/test_mapping.py +81 -0
  87. openstackclient/tests/functional/volume/v3/test_volume_group.py +163 -0
  88. openstackclient/tests/unit/common/test_limits.py +1 -1
  89. openstackclient/tests/unit/common/test_module.py +77 -44
  90. openstackclient/tests/unit/common/test_quota.py +9 -0
  91. openstackclient/tests/unit/compute/v2/fakes.py +1 -57
  92. openstackclient/tests/unit/compute/v2/test_agent.py +4 -4
  93. openstackclient/tests/unit/compute/v2/test_aggregate.py +1 -1
  94. openstackclient/tests/unit/compute/v2/test_console.py +2 -2
  95. openstackclient/tests/unit/compute/v2/test_console_connection.py +1 -1
  96. openstackclient/tests/unit/compute/v2/test_flavor.py +1 -1
  97. openstackclient/tests/unit/compute/v2/test_host.py +3 -3
  98. openstackclient/tests/unit/compute/v2/test_hypervisor.py +2 -2
  99. openstackclient/tests/unit/compute/v2/test_hypervisor_stats.py +1 -1
  100. openstackclient/tests/unit/compute/v2/test_keypair.py +1 -1
  101. openstackclient/tests/unit/compute/v2/test_server.py +15 -15
  102. openstackclient/tests/unit/compute/v2/test_server_backup.py +1 -1
  103. openstackclient/tests/unit/compute/v2/test_server_event.py +2 -2
  104. openstackclient/tests/unit/compute/v2/test_server_group.py +1 -1
  105. openstackclient/tests/unit/compute/v2/test_server_image.py +1 -1
  106. openstackclient/tests/unit/compute/v2/test_server_migration.py +4 -4
  107. openstackclient/tests/unit/compute/v2/test_server_share.py +4 -4
  108. openstackclient/tests/unit/compute/v2/test_server_volume.py +2 -2
  109. openstackclient/tests/unit/compute/v2/test_service.py +3 -3
  110. openstackclient/tests/unit/compute/v2/test_usage.py +1 -1
  111. openstackclient/tests/unit/identity/v2_0/fakes.py +3 -7
  112. openstackclient/tests/unit/identity/v2_0/test_endpoint.py +1 -1
  113. openstackclient/tests/unit/identity/v2_0/test_project.py +1 -1
  114. openstackclient/tests/unit/identity/v2_0/test_role.py +1 -1
  115. openstackclient/tests/unit/identity/v2_0/test_role_assignment.py +1 -1
  116. openstackclient/tests/unit/identity/v2_0/test_service.py +1 -1
  117. openstackclient/tests/unit/identity/v2_0/test_token.py +2 -2
  118. openstackclient/tests/unit/identity/v2_0/test_user.py +1 -1
  119. openstackclient/tests/unit/identity/v3/fakes.py +5 -38
  120. openstackclient/tests/unit/identity/v3/test_access_rule.py +3 -3
  121. openstackclient/tests/unit/identity/v3/test_application_credential.py +4 -4
  122. openstackclient/tests/unit/identity/v3/test_credential.py +5 -5
  123. openstackclient/tests/unit/identity/v3/test_domain.py +5 -5
  124. openstackclient/tests/unit/identity/v3/test_endpoint.py +6 -6
  125. openstackclient/tests/unit/identity/v3/test_endpoint_group.py +1 -1
  126. openstackclient/tests/unit/identity/v3/test_group.py +8 -8
  127. openstackclient/tests/unit/identity/v3/test_implied_role.py +1 -1
  128. openstackclient/tests/unit/identity/v3/test_limit.py +5 -5
  129. openstackclient/tests/unit/identity/v3/test_mappings.py +163 -79
  130. openstackclient/tests/unit/identity/v3/test_project.py +28 -5
  131. openstackclient/tests/unit/identity/v3/test_protocol.py +3 -3
  132. openstackclient/tests/unit/identity/v3/test_region.py +5 -5
  133. openstackclient/tests/unit/identity/v3/test_registered_limit.py +5 -5
  134. openstackclient/tests/unit/identity/v3/test_role.py +8 -8
  135. openstackclient/tests/unit/identity/v3/test_role_assignment.py +1 -1
  136. openstackclient/tests/unit/identity/v3/test_service.py +5 -5
  137. openstackclient/tests/unit/identity/v3/test_token.py +2 -2
  138. openstackclient/tests/unit/identity/v3/test_trust.py +4 -4
  139. openstackclient/tests/unit/identity/v3/test_user.py +73 -6
  140. openstackclient/tests/unit/network/v2/fakes.py +5 -77
  141. openstackclient/tests/unit/network/v2/fwaas/test_group.py +28 -2
  142. openstackclient/tests/unit/network/v2/fwaas/test_rule.py +28 -3
  143. openstackclient/tests/unit/network/v2/test_address_group.py +24 -0
  144. openstackclient/tests/unit/network/v2/test_address_scope.py +24 -0
  145. openstackclient/tests/unit/network/v2/test_floating_ip.py +24 -0
  146. openstackclient/tests/unit/network/v2/test_floating_ip_port_forwarding.py +24 -0
  147. openstackclient/tests/unit/network/v2/test_ip_availability.py +25 -0
  148. openstackclient/tests/unit/network/v2/test_l3_conntrack_helper.py +29 -3
  149. openstackclient/tests/unit/network/v2/test_network.py +74 -12
  150. openstackclient/tests/unit/network/v2/test_network_agent.py +50 -1
  151. openstackclient/tests/unit/network/v2/test_network_flavor.py +24 -0
  152. openstackclient/tests/unit/network/v2/test_network_flavor_profile.py +24 -0
  153. openstackclient/tests/unit/network/v2/test_network_meter.py +24 -0
  154. openstackclient/tests/unit/network/v2/test_network_qos_policy.py +24 -0
  155. openstackclient/tests/unit/network/v2/test_network_qos_rule_type.py +24 -0
  156. openstackclient/tests/unit/network/v2/test_network_rbac.py +24 -0
  157. openstackclient/tests/unit/network/v2/test_network_segment.py +24 -0
  158. openstackclient/tests/unit/network/v2/test_network_segment_range.py +24 -0
  159. openstackclient/tests/unit/network/v2/test_port.py +166 -0
  160. openstackclient/tests/unit/network/v2/test_router.py +28 -7
  161. openstackclient/tests/unit/network/v2/test_security_group.py +22 -0
  162. openstackclient/tests/unit/network/v2/test_security_group_rule.py +25 -0
  163. openstackclient/tests/unit/network/v2/test_subnet.py +28 -4
  164. openstackclient/tests/unit/network/v2/test_subnet_pool.py +24 -0
  165. openstackclient/tests/unit/volume/v2/fakes.py +20 -140
  166. openstackclient/tests/unit/volume/v2/test_volume_backup.py +5 -9
  167. openstackclient/tests/unit/volume/v2/test_volume_snapshot.py +6 -0
  168. openstackclient/tests/unit/volume/v3/fakes.py +204 -100
  169. openstackclient/tests/unit/volume/v3/test_backup_record.py +114 -0
  170. openstackclient/tests/unit/volume/v3/test_consistency_group.py +720 -0
  171. openstackclient/tests/unit/volume/v3/test_consistency_group_snapshot.py +354 -0
  172. openstackclient/tests/unit/volume/v3/test_qos_specs.py +455 -0
  173. openstackclient/tests/unit/volume/v3/test_volume_attachment.py +2 -0
  174. openstackclient/tests/unit/volume/v3/test_volume_backend.py +158 -0
  175. openstackclient/tests/unit/volume/v3/test_volume_backup.py +5 -9
  176. openstackclient/tests/unit/volume/v3/test_volume_group_type.py +65 -0
  177. openstackclient/tests/unit/volume/v3/test_volume_host.py +115 -0
  178. openstackclient/tests/unit/volume/v3/test_volume_snapshot.py +6 -0
  179. openstackclient/volume/v2/volume.py +4 -2
  180. openstackclient/volume/v2/volume_backup.py +2 -3
  181. openstackclient/volume/v2/volume_snapshot.py +3 -4
  182. openstackclient/volume/v3/backup_record.py +94 -0
  183. openstackclient/volume/v3/consistency_group.py +400 -0
  184. openstackclient/volume/v3/consistency_group_snapshot.py +225 -0
  185. openstackclient/volume/v3/qos_specs.py +389 -0
  186. openstackclient/volume/v3/volume.py +4 -2
  187. openstackclient/volume/v3/volume_attachment.py +5 -1
  188. openstackclient/volume/v3/volume_backend.py +130 -0
  189. openstackclient/volume/v3/volume_backup.py +2 -3
  190. openstackclient/volume/v3/volume_group_snapshot.py +4 -6
  191. openstackclient/volume/v3/volume_group_type.py +1 -1
  192. openstackclient/volume/v3/volume_host.py +74 -0
  193. openstackclient/volume/v3/volume_message.py +3 -1
  194. openstackclient/volume/v3/volume_snapshot.py +2 -1
  195. {python_openstackclient-10.0.0.dist-info → python_openstackclient-10.1.0.dist-info}/METADATA +3 -4
  196. {python_openstackclient-10.0.0.dist-info → python_openstackclient-10.1.0.dist-info}/RECORD +202 -188
  197. {python_openstackclient-10.0.0.dist-info → python_openstackclient-10.1.0.dist-info}/entry_points.txt +24 -24
  198. {python_openstackclient-10.0.0.dist-info → python_openstackclient-10.1.0.dist-info}/licenses/AUTHORS +5 -0
  199. python_openstackclient-10.1.0.dist-info/pbr.json +1 -0
  200. python_openstackclient-10.0.0.dist-info/pbr.json +0 -1
  201. {python_openstackclient-10.0.0.dist-info → python_openstackclient-10.1.0.dist-info}/WHEEL +0 -0
  202. {python_openstackclient-10.0.0.dist-info → python_openstackclient-10.1.0.dist-info}/licenses/LICENSE +0 -0
  203. {python_openstackclient-10.0.0.dist-info → python_openstackclient-10.1.0.dist-info}/top_level.txt +0 -0
@@ -22,19 +22,20 @@ import logging
22
22
  from typing import Any
23
23
 
24
24
  from openstack import exceptions as sdk_exc
25
+ from openstack.identity.v3 import user as _user
25
26
  from openstack import utils as sdk_utils
26
27
  from osc_lib import exceptions
27
28
  from osc_lib import utils
28
29
 
29
30
  from openstackclient import command
31
+ from openstackclient.common import pagination
30
32
  from openstackclient.i18n import _
31
33
  from openstackclient.identity import common
32
34
 
33
-
34
35
  LOG = logging.getLogger(__name__)
35
36
 
36
37
 
37
- def _format_user(user: Any) -> tuple[tuple[str, ...], Any]:
38
+ def _format_user(user: _user.User) -> tuple[tuple[str, ...], tuple[Any, ...]]:
38
39
  columns = (
39
40
  'default_project_id',
40
41
  'domain_id',
@@ -448,11 +449,18 @@ class ListUser(command.Lister):
448
449
  '--project and --group'
449
450
  ),
450
451
  )
452
+ pagination.add_marker_pagination_option_to_parser(parser)
451
453
  return parser
452
454
 
453
455
  def take_action(
454
456
  self, parsed_args: argparse.Namespace
455
457
  ) -> tuple[Sequence[str], Iterable[tuple[Any, ...]]]:
458
+ if parsed_args.project and (
459
+ parsed_args.limit is not None or parsed_args.marker is not None
460
+ ):
461
+ msg = _('--limit and --marker are not supported with --project')
462
+ raise exceptions.CommandError(msg)
463
+
456
464
  identity_client = sdk_utils.ensure_service_version(
457
465
  self.app.client_manager.sdk_connection.identity, '3'
458
466
  )
@@ -475,6 +483,15 @@ class ListUser(command.Lister):
475
483
  if parsed_args.is_enabled is not None:
476
484
  enabled = parsed_args.is_enabled
477
485
 
486
+ pagination_kwargs: dict[str, Any] = {}
487
+ if parsed_args.limit is not None:
488
+ pagination_kwargs['limit'] = parsed_args.limit
489
+ if parsed_args.max_items is not None:
490
+ pagination_kwargs['max_items'] = parsed_args.max_items
491
+ if parsed_args.marker is not None:
492
+ pagination_kwargs['marker'] = parsed_args.marker
493
+
494
+ data: list[_user.User]
478
495
  if parsed_args.project:
479
496
  if domain is not None:
480
497
  project = identity_client.find_project(
@@ -504,21 +521,28 @@ class ListUser(command.Lister):
504
521
  for user_id in user_ids:
505
522
  user = identity_client.find_user(user_id, ignore_missing=False)
506
523
  data.append(user)
507
-
508
524
  elif parsed_args.group:
509
- data = identity_client.group_users(
510
- domain_id=domain,
511
- group=group,
525
+ assert group is not None
526
+ data = list(
527
+ identity_client.group_users(
528
+ domain_id=domain, group=group, **pagination_kwargs
529
+ )
512
530
  )
513
531
  else:
514
532
  if parsed_args.is_enabled is not None:
515
- data = identity_client.users(
516
- domain_id=domain,
517
- is_enabled=enabled,
533
+ data = list(
534
+ identity_client.users(
535
+ domain_id=domain,
536
+ is_enabled=enabled,
537
+ **pagination_kwargs,
538
+ )
518
539
  )
519
540
  else:
520
- data = identity_client.users(
521
- domain_id=domain,
541
+ data = list(
542
+ identity_client.users(
543
+ domain_id=domain,
544
+ **pagination_kwargs,
545
+ )
522
546
  )
523
547
 
524
548
  # Column handling
@@ -718,6 +742,9 @@ class SetPasswordUser(command.Command):
718
742
  raise exceptions.CommandError('invalid authentication info')
719
743
 
720
744
  user_id = auth.get_user_id(conn.session)
745
+ if user_id is None:
746
+ # this will never happen
747
+ raise exceptions.CommandError('invalid authentication info')
721
748
 
722
749
  # FIXME(gyee): there are two scenarios:
723
750
  #
@@ -41,14 +41,14 @@ def _format_image_cache(cached_images: dict[str, Any]) -> list[dict[str, Any]]:
41
41
  image_obj['state'] = 'cached'
42
42
  image_obj['last_accessed'] = (
43
43
  datetime.datetime.fromtimestamp(
44
- image['last_accessed'], tz=datetime.timezone.utc
44
+ image['last_accessed'], tz=datetime.UTC
45
45
  )
46
46
  .replace(tzinfo=None)
47
47
  .isoformat()
48
48
  )
49
49
  image_obj['last_modified'] = (
50
50
  datetime.datetime.fromtimestamp(
51
- image['last_modified'], tz=datetime.timezone.utc
51
+ image['last_modified'], tz=datetime.UTC
52
52
  )
53
53
  .replace(tzinfo=None)
54
54
  .isoformat()
@@ -27,6 +27,7 @@ import urllib.parse
27
27
 
28
28
  from openstack import exceptions as sdk_exceptions
29
29
  from openstack.image import image_signer
30
+ from openstack.image.v2 import image as _image
30
31
  from openstack import utils as sdk_utils
31
32
  from osc_lib.api import utils as api_utils
32
33
  from osc_lib.cli import format_columns
@@ -74,11 +75,13 @@ MEMBER_STATUS_CHOICES = ["accepted", "pending", "rejected", "all"]
74
75
  LOG = logging.getLogger(__name__)
75
76
 
76
77
 
77
- def _format_image(image: Any, human_readable: bool = False) -> dict[str, Any]:
78
+ def _format_image(
79
+ image: _image.Image, human_readable: bool = False
80
+ ) -> dict[str, object]:
78
81
  """Format an image to make it more consistent with OSC operations."""
79
82
 
80
83
  info = {}
81
- properties = {}
84
+ properties: dict[str, object] = {}
82
85
 
83
86
  # the only fields we're not including is "links", "tags" and the properties
84
87
  fields_to_show = [
@@ -106,25 +109,25 @@ def _format_image(image: Any, human_readable: bool = False) -> dict[str, Any]:
106
109
 
107
110
  # TODO(gtema/anybody): actually it should be possible to drop this method,
108
111
  # since SDK already delivers a proper object
109
- image = image.to_dict(ignore_none=True, original_names=True)
112
+ data = image.to_dict(ignore_none=True, original_names=True)
110
113
 
111
114
  # split out the usual key and the properties which are top-level
112
- for key in image:
115
+ for key in data:
113
116
  if key in fields_to_show:
114
- info[key] = image.get(key)
117
+ info[key] = data[key]
115
118
  elif key == 'tags':
116
119
  continue # handle this later
117
120
  elif key == 'properties':
118
121
  # NOTE(gtema): flatten content of properties
119
- properties.update(image.get(key))
122
+ properties.update(data[key])
120
123
  elif key != 'location':
121
- properties[key] = image.get(key)
124
+ properties[key] = data[key]
122
125
 
123
126
  if human_readable:
124
- info['size'] = utils.format_size(image['size'])
127
+ info['size'] = utils.format_size(data['size'])
125
128
 
126
129
  # format the tags if they are there
127
- info['tags'] = format_columns.ListColumn(image.get('tags'))
130
+ info['tags'] = format_columns.ListColumn(data.get('tags') or [])
128
131
 
129
132
  # add properties back into the dictionary as a top-level key
130
133
  if properties:
@@ -884,6 +887,8 @@ class ListImage(command.Lister):
884
887
  kwargs['visibility'] = parsed_args.visibility
885
888
  if parsed_args.limit:
886
889
  kwargs['limit'] = parsed_args.limit
890
+ if parsed_args.max_items is not None:
891
+ kwargs['max_items'] = parsed_args.max_items
887
892
  if parsed_args.marker:
888
893
  kwargs['marker'] = image_client.find_image(
889
894
  parsed_args.marker,
@@ -1358,6 +1363,7 @@ class SetImage(command.Command):
1358
1363
  # our own membership
1359
1364
  if not project_id:
1360
1365
  project_id = self.app.client_manager.auth_ref.project_id
1366
+ assert project_id is not None, 'this should not happen'
1361
1367
  image_client.update_member(
1362
1368
  image=image.id,
1363
1369
  member=project_id,
@@ -20,6 +20,7 @@ from collections.abc import Iterable, Sequence
20
20
  import logging
21
21
  from typing import Any
22
22
 
23
+ from openstack.image.v2 import metadef_namespace as _metadef_namespace
23
24
  from osc_lib.cli import format_columns
24
25
  from osc_lib import exceptions
25
26
  from osc_lib import utils
@@ -34,7 +35,9 @@ _formatters = {
34
35
  LOG = logging.getLogger(__name__)
35
36
 
36
37
 
37
- def _format_namespace(namespace: Any) -> dict[str, Any]:
38
+ def _format_namespace(
39
+ namespace: _metadef_namespace.MetadefNamespace,
40
+ ) -> dict[str, Any]:
38
41
  info = {}
39
42
 
40
43
  fields_to_show = [
@@ -50,18 +53,16 @@ def _format_namespace(namespace: Any) -> dict[str, Any]:
50
53
  'visibility',
51
54
  ]
52
55
 
53
- namespace = namespace.to_dict(ignore_none=True, original_names=True)
56
+ data = namespace.to_dict(ignore_none=True, original_names=True)
54
57
 
55
58
  # split out the usual key and the properties which are top-level
56
- for key in namespace:
59
+ for key in data:
57
60
  if key in fields_to_show:
58
- info[key] = namespace.get(key)
61
+ info[key] = data.get(key)
59
62
  elif key == "resource_type_associations":
60
- info[key] = [
61
- resource_type['name'] for resource_type in namespace.get(key)
62
- ]
63
+ info[key] = [resource_type['name'] for resource_type in data[key]]
63
64
  elif key == 'properties':
64
- info['properties'] = list(namespace.get(key).keys())
65
+ info['properties'] = list(data[key].keys())
65
66
 
66
67
  return info
67
68
 
@@ -358,7 +359,7 @@ class ShowMetadefNamespace(command.ShowOne):
358
359
  class UnsetMetadefNamespace(command.Command):
359
360
  _description = _("Unset metadef namespace tags")
360
361
 
361
- def get_parser(self, prog_name):
362
+ def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
362
363
  parser = super().get_parser(prog_name)
363
364
  parser.add_argument(
364
365
  "namespace",
@@ -385,7 +386,7 @@ class UnsetMetadefNamespace(command.Command):
385
386
  )
386
387
  return parser
387
388
 
388
- def take_action(self, parsed_args):
389
+ def take_action(self, parsed_args: argparse.Namespace) -> None:
389
390
  image_client = self.app.client_manager.image
390
391
 
391
392
  namespace = image_client.get_metadef_namespace(parsed_args.namespace)
@@ -20,6 +20,7 @@ from collections.abc import Iterable, Sequence
20
20
  import logging
21
21
  from typing import Any
22
22
 
23
+ from openstack.image.v2 import metadef_object as _metadef_object
23
24
  from osc_lib import exceptions
24
25
  from osc_lib import utils
25
26
 
@@ -30,7 +31,9 @@ from openstackclient.i18n import _
30
31
  LOG = logging.getLogger(__name__)
31
32
 
32
33
 
33
- def _format_object(md_object: Any) -> tuple[tuple[str, ...], Any]:
34
+ def _format_object(
35
+ md_object: _metadef_object.MetadefObject,
36
+ ) -> tuple[tuple[str, ...], Iterable[Any]]:
34
37
  fields_to_show = (
35
38
  'created_at',
36
39
  'description',
@@ -43,10 +46,7 @@ def _format_object(md_object: Any) -> tuple[tuple[str, ...], Any]:
43
46
 
44
47
  return (
45
48
  fields_to_show,
46
- utils.get_item_properties(
47
- md_object,
48
- fields_to_show,
49
- ),
49
+ utils.get_item_properties(md_object, fields_to_show),
50
50
  )
51
51
 
52
52
 
@@ -18,6 +18,7 @@ import json
18
18
  import logging
19
19
  from typing import Any
20
20
 
21
+ from openstack.image.v2 import metadef_property as _metadef_property
21
22
  from osc_lib import exceptions
22
23
  from osc_lib import utils
23
24
 
@@ -28,10 +29,12 @@ from openstackclient.i18n import _
28
29
  LOG = logging.getLogger(__name__)
29
30
 
30
31
 
31
- def _format_property(prop: Any) -> dict[str, Any]:
32
- prop = prop.to_dict(ignore_none=True, original_names=True)
32
+ def _format_property(
33
+ prop: _metadef_property.MetadefProperty,
34
+ ) -> dict[str, Any]:
35
+ data = prop.to_dict(ignore_none=True, original_names=True)
33
36
  return {
34
- key: prop[key]
37
+ key: data[key]
35
38
  for key in [
36
39
  'namespace_name',
37
40
  'name',
@@ -53,7 +56,7 @@ def _format_property(prop: Any) -> dict[str, Any]:
53
56
  'max_items',
54
57
  'allow_additional_items',
55
58
  ]
56
- if key in prop
59
+ if key in data
57
60
  }
58
61
 
59
62
 
@@ -14,18 +14,16 @@ import argparse
14
14
  from collections.abc import Iterable, Sequence
15
15
  from typing import Any
16
16
 
17
+ from openstack.image.v2 import task as _task
17
18
  from osc_lib.cli import format_columns
18
19
  from osc_lib import utils
19
20
 
20
21
  from openstackclient import command
22
+ from openstackclient.common import pagination
21
23
  from openstackclient.i18n import _
22
24
 
23
- _formatters = {
24
- 'tags': format_columns.ListColumn,
25
- }
26
25
 
27
-
28
- def _format_task(task: Any) -> dict[str, Any]:
26
+ def _format_task(task: _task.Task) -> dict[str, Any]:
29
27
  """Format an task to make it more consistent with OSC operations."""
30
28
 
31
29
  info = {}
@@ -117,22 +115,7 @@ class ListTask(command.Lister):
117
115
  'by comma)'
118
116
  ),
119
117
  )
120
- parser.add_argument(
121
- '--limit',
122
- metavar='<num-tasks>',
123
- type=int,
124
- help=_('Maximum number of tasks to display.'),
125
- )
126
- parser.add_argument(
127
- '--marker',
128
- metavar='<task>',
129
- help=_(
130
- 'The last task of the previous page. '
131
- 'Display list of tasks after marker. '
132
- 'Display all tasks if not specified. '
133
- '(name or ID)'
134
- ),
135
- )
118
+ pagination.add_marker_pagination_option_to_parser(parser)
136
119
  parser.add_argument(
137
120
  '--type',
138
121
  metavar='<type>',
@@ -182,7 +165,13 @@ class ListTask(command.Lister):
182
165
  return (
183
166
  column_headers,
184
167
  (
185
- utils.get_item_properties(s, columns, formatters=_formatters)
168
+ utils.get_item_properties(
169
+ s,
170
+ columns,
171
+ formatters={
172
+ 'tags': format_columns.ListColumn,
173
+ },
174
+ )
186
175
  for s in data
187
176
  ),
188
177
  )
@@ -9,9 +9,7 @@
9
9
  # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
10
  # License for the specific language governing permissions and limitations
11
11
  # under the License.
12
- #
13
12
 
14
- from collections.abc import Iterable, Sequence
15
13
  from typing import Any, cast
16
14
 
17
15
  from osc_lib import exceptions
@@ -19,37 +17,6 @@ from osc_lib import exceptions
19
17
  from openstackclient.i18n import _
20
18
 
21
19
 
22
- # Transform compute security group rule for display.
23
- def transform_compute_security_group_rule(
24
- sg_rule: dict[str, Any],
25
- ) -> dict[str, Any]:
26
- info = {}
27
- info.update(sg_rule)
28
- from_port = info.pop('from_port')
29
- to_port = info.pop('to_port')
30
- if isinstance(from_port, int) and isinstance(to_port, int):
31
- port_range = {'port_range': f"{from_port}:{to_port}"}
32
- elif from_port is None and to_port is None:
33
- port_range = {'port_range': ""}
34
- else:
35
- port_range = {'port_range': f"{from_port}:{to_port}"}
36
- info.update(port_range)
37
- if 'cidr' in info['ip_range']:
38
- info['ip_range'] = info['ip_range']['cidr']
39
- else:
40
- info['ip_range'] = ''
41
- if info['ip_protocol'] is None:
42
- info['ip_protocol'] = ''
43
- elif info['ip_protocol'].lower() == 'icmp':
44
- info['port_range'] = ''
45
- group = info.pop('group')
46
- if 'name' in group:
47
- info['remote_security_group'] = group['name']
48
- else:
49
- info['remote_security_group'] = ''
50
- return info
51
-
52
-
53
20
  def str2bool(strbool: str | None) -> bool | None:
54
21
  if strbool is None:
55
22
  return None
@@ -88,14 +55,6 @@ def str2dict(strdict: str) -> dict[str, str]:
88
55
  return result
89
56
 
90
57
 
91
- def format_security_group_rule_show(
92
- obj: dict[str, Any],
93
- ) -> tuple[Sequence[str], Iterable[Any]]:
94
- data = transform_compute_security_group_rule(obj)
95
- col_headers, col_data = zip(*sorted(data.items()))
96
- return col_headers, col_data
97
-
98
-
99
58
  def format_network_port_range(rule: dict[str, Any]) -> str:
100
59
  # Display port range or ICMP type and code. For example:
101
60
  # - ICMP type: 'type=3'
@@ -19,10 +19,12 @@ from collections.abc import Iterable, Sequence
19
19
  from typing import Any
20
20
 
21
21
  import netaddr
22
+ from openstack.network.v2 import address_group as _address_group
22
23
  from osc_lib import exceptions
23
24
  from osc_lib import utils
24
25
 
25
26
  from openstackclient import command
27
+ from openstackclient.common import pagination
26
28
  from openstackclient.i18n import _
27
29
  from openstackclient.identity import common as identity_common
28
30
  from openstackclient.network import common
@@ -30,7 +32,9 @@ from openstackclient.network import common
30
32
  LOG = logging.getLogger(__name__)
31
33
 
32
34
 
33
- def _get_columns(item: Any) -> tuple[tuple[str, ...], tuple[str, ...]]:
35
+ def _get_columns(
36
+ item: _address_group.AddressGroup,
37
+ ) -> tuple[tuple[str, ...], tuple[str, ...]]:
34
38
  hidden_columns = ['location', 'tenant_id']
35
39
  return utils.get_osc_show_columns_for_sdk_resource(
36
40
  item, {}, hidden_columns
@@ -169,6 +173,7 @@ class ListAddressGroup(command.Lister):
169
173
  ),
170
174
  )
171
175
  identity_common.add_project_domain_option_to_parser(parser)
176
+ pagination.add_marker_pagination_option_to_parser(parser)
172
177
 
173
178
  return parser
174
179
 
@@ -201,6 +206,13 @@ class ListAddressGroup(command.Lister):
201
206
  parsed_args.project_domain,
202
207
  ).id
203
208
  attrs['project_id'] = project_id
209
+ if parsed_args.marker is not None:
210
+ attrs['marker'] = parsed_args.marker
211
+ if parsed_args.limit is not None:
212
+ attrs['limit'] = parsed_args.limit
213
+ if parsed_args.max_items is not None:
214
+ attrs['max_items'] = parsed_args.max_items
215
+
204
216
  data = client.address_groups(**attrs)
205
217
 
206
218
  return (
@@ -18,10 +18,12 @@ import logging
18
18
  from collections.abc import Iterable, Sequence
19
19
  from typing import Any
20
20
 
21
+ from openstack.network.v2 import address_scope as _address_scope
21
22
  from osc_lib import exceptions
22
23
  from osc_lib import utils
23
24
 
24
25
  from openstackclient import command
26
+ from openstackclient.common import pagination
25
27
  from openstackclient.i18n import _
26
28
  from openstackclient.identity import common as identity_common
27
29
  from openstackclient.network import common
@@ -29,7 +31,9 @@ from openstackclient.network import common
29
31
  LOG = logging.getLogger(__name__)
30
32
 
31
33
 
32
- def _get_columns(item: Any) -> tuple[tuple[str, ...], tuple[str, ...]]:
34
+ def _get_columns(
35
+ item: _address_scope.AddressScope,
36
+ ) -> tuple[tuple[str, ...], tuple[str, ...]]:
33
37
  column_map = {
34
38
  'is_shared': 'shared',
35
39
  }
@@ -61,8 +65,6 @@ def _get_attrs(
61
65
  return attrs
62
66
 
63
67
 
64
- # TODO(rtheis): Use the SDK resource mapped attribute names once the
65
- # OSC minimum requirements include SDK 1.0.
66
68
  class CreateAddressScope(command.ShowOne, common.NeutronCommandWithExtraArgs):
67
69
  _description = _("Create a new Address Scope")
68
70
 
@@ -156,8 +158,6 @@ class DeleteAddressScope(command.Command):
156
158
  raise exceptions.CommandError(msg)
157
159
 
158
160
 
159
- # TODO(yanxing'an): Use the SDK resource mapped attribute names once the
160
- # OSC minimum requirements include SDK 1.0.
161
161
  class ListAddressScope(command.Lister):
162
162
  _description = _("List address scopes")
163
163
 
@@ -189,7 +189,7 @@ class ListAddressScope(command.Lister):
189
189
  ),
190
190
  )
191
191
  identity_common.add_project_domain_option_to_parser(parser)
192
-
192
+ pagination.add_marker_pagination_option_to_parser(parser)
193
193
  shared_group = parser.add_mutually_exclusive_group()
194
194
  shared_group.add_argument(
195
195
  '--share',
@@ -201,6 +201,7 @@ class ListAddressScope(command.Lister):
201
201
  action='store_true',
202
202
  help=_("List only address scopes not shared between projects"),
203
203
  )
204
+
204
205
  return parser
205
206
 
206
207
  def take_action(
@@ -238,6 +239,12 @@ class ListAddressScope(command.Lister):
238
239
  parsed_args.project_domain,
239
240
  ).id
240
241
  attrs['project_id'] = project_id
242
+ if parsed_args.marker is not None:
243
+ attrs['marker'] = parsed_args.marker
244
+ if parsed_args.limit is not None:
245
+ attrs['limit'] = parsed_args.limit
246
+ if parsed_args.max_items is not None:
247
+ attrs['max_items'] = parsed_args.max_items
241
248
  data = client.address_scopes(**attrs)
242
249
 
243
250
  return (
@@ -253,8 +260,6 @@ class ListAddressScope(command.Lister):
253
260
  )
254
261
 
255
262
 
256
- # TODO(rtheis): Use the SDK resource mapped attribute names once the
257
- # OSC minimum requirements include SDK 1.0.
258
263
  class SetAddressScope(common.NeutronCommandWithExtraArgs):
259
264
  _description = _("Set address scope properties")
260
265