python-openstackclient 8.1.0__py3-none-any.whl → 8.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (241) hide show
  1. openstackclient/api/compute_v2.py +2 -2
  2. openstackclient/api/object_store_v1.py +4 -1
  3. openstackclient/api/volume_v2.py +60 -0
  4. openstackclient/api/volume_v3.py +60 -0
  5. openstackclient/command.py +27 -0
  6. openstackclient/common/availability_zone.py +1 -1
  7. openstackclient/common/clientmanager.py +59 -21
  8. openstackclient/common/configuration.py +1 -1
  9. openstackclient/common/extension.py +1 -1
  10. openstackclient/common/limits.py +1 -1
  11. openstackclient/common/module.py +4 -2
  12. openstackclient/common/project_cleanup.py +10 -8
  13. openstackclient/common/quota.py +23 -6
  14. openstackclient/common/versions.py +1 -2
  15. openstackclient/compute/v2/agent.py +1 -1
  16. openstackclient/compute/v2/aggregate.py +6 -5
  17. openstackclient/compute/v2/console.py +5 -3
  18. openstackclient/compute/v2/console_connection.py +1 -1
  19. openstackclient/compute/v2/flavor.py +15 -2
  20. openstackclient/compute/v2/host.py +1 -1
  21. openstackclient/compute/v2/hypervisor.py +1 -1
  22. openstackclient/compute/v2/hypervisor_stats.py +1 -1
  23. openstackclient/compute/v2/keypair.py +1 -1
  24. openstackclient/compute/v2/server.py +77 -30
  25. openstackclient/compute/v2/server_backup.py +1 -1
  26. openstackclient/compute/v2/server_event.py +1 -1
  27. openstackclient/compute/v2/server_group.py +4 -2
  28. openstackclient/compute/v2/server_image.py +1 -1
  29. openstackclient/compute/v2/server_migration.py +1 -1
  30. openstackclient/compute/v2/server_volume.py +1 -1
  31. openstackclient/compute/v2/service.py +1 -1
  32. openstackclient/compute/v2/usage.py +6 -4
  33. openstackclient/identity/common.py +10 -14
  34. openstackclient/identity/v2_0/catalog.py +3 -2
  35. openstackclient/identity/v2_0/ec2creds.py +1 -1
  36. openstackclient/identity/v2_0/endpoint.py +1 -1
  37. openstackclient/identity/v2_0/project.py +17 -7
  38. openstackclient/identity/v2_0/role.py +1 -1
  39. openstackclient/identity/v2_0/role_assignment.py +3 -3
  40. openstackclient/identity/v2_0/service.py +1 -1
  41. openstackclient/identity/v2_0/token.py +1 -1
  42. openstackclient/identity/v2_0/user.py +2 -2
  43. openstackclient/identity/v3/access_rule.py +16 -4
  44. openstackclient/identity/v3/application_credential.py +116 -95
  45. openstackclient/identity/v3/catalog.py +3 -3
  46. openstackclient/identity/v3/consumer.py +1 -1
  47. openstackclient/identity/v3/credential.py +1 -1
  48. openstackclient/identity/v3/domain.py +15 -10
  49. openstackclient/identity/v3/ec2creds.py +1 -1
  50. openstackclient/identity/v3/endpoint.py +33 -12
  51. openstackclient/identity/v3/endpoint_group.py +1 -1
  52. openstackclient/identity/v3/federation_protocol.py +1 -1
  53. openstackclient/identity/v3/group.py +11 -5
  54. openstackclient/identity/v3/identity_provider.py +12 -10
  55. openstackclient/identity/v3/implied_role.py +1 -1
  56. openstackclient/identity/v3/limit.py +1 -1
  57. openstackclient/identity/v3/mapping.py +1 -1
  58. openstackclient/identity/v3/policy.py +1 -1
  59. openstackclient/identity/v3/project.py +34 -22
  60. openstackclient/identity/v3/region.py +1 -1
  61. openstackclient/identity/v3/registered_limit.py +16 -11
  62. openstackclient/identity/v3/role.py +27 -41
  63. openstackclient/identity/v3/role_assignment.py +12 -23
  64. openstackclient/identity/v3/service.py +1 -1
  65. openstackclient/identity/v3/service_provider.py +1 -1
  66. openstackclient/identity/v3/tag.py +3 -2
  67. openstackclient/identity/v3/token.py +3 -2
  68. openstackclient/identity/v3/trust.py +4 -2
  69. openstackclient/identity/v3/unscoped_saml.py +1 -1
  70. openstackclient/identity/v3/user.py +22 -13
  71. openstackclient/image/v1/image.py +35 -17
  72. openstackclient/image/v2/cache.py +11 -7
  73. openstackclient/image/v2/image.py +62 -12
  74. openstackclient/image/v2/info.py +1 -1
  75. openstackclient/image/v2/metadef_namespaces.py +1 -1
  76. openstackclient/image/v2/metadef_objects.py +9 -3
  77. openstackclient/image/v2/metadef_properties.py +11 -3
  78. openstackclient/image/v2/metadef_resource_type_association.py +1 -1
  79. openstackclient/image/v2/metadef_resource_types.py +1 -1
  80. openstackclient/image/v2/task.py +1 -1
  81. openstackclient/network/common.py +10 -9
  82. openstackclient/network/v2/address_group.py +4 -3
  83. openstackclient/network/v2/address_scope.py +8 -6
  84. openstackclient/network/v2/default_security_group_rule.py +9 -8
  85. openstackclient/network/v2/floating_ip.py +16 -9
  86. openstackclient/network/v2/floating_ip_port_forwarding.py +9 -6
  87. openstackclient/network/v2/ip_availability.py +7 -4
  88. openstackclient/network/v2/l3_conntrack_helper.py +11 -4
  89. openstackclient/network/v2/local_ip.py +13 -7
  90. openstackclient/network/v2/local_ip_association.py +7 -4
  91. openstackclient/network/v2/ndp_proxy.py +13 -6
  92. openstackclient/network/v2/network.py +33 -16
  93. openstackclient/network/v2/network_agent.py +5 -5
  94. openstackclient/network/v2/network_auto_allocated_topology.py +1 -1
  95. openstackclient/network/v2/network_flavor.py +1 -1
  96. openstackclient/network/v2/network_flavor_profile.py +1 -1
  97. openstackclient/network/v2/network_meter.py +1 -1
  98. openstackclient/network/v2/network_meter_rule.py +1 -1
  99. openstackclient/network/v2/network_qos_policy.py +7 -5
  100. openstackclient/network/v2/network_qos_rule.py +1 -1
  101. openstackclient/network/v2/network_qos_rule_type.py +1 -1
  102. openstackclient/network/v2/network_rbac.py +8 -5
  103. openstackclient/network/v2/network_segment.py +2 -2
  104. openstackclient/network/v2/network_segment_range.py +13 -6
  105. openstackclient/network/v2/network_service_provider.py +1 -1
  106. openstackclient/network/v2/network_trunk.py +65 -42
  107. openstackclient/network/v2/port.py +38 -20
  108. openstackclient/network/v2/router.py +19 -8
  109. openstackclient/network/v2/security_group.py +52 -7
  110. openstackclient/network/v2/security_group_rule.py +27 -4
  111. openstackclient/network/v2/subnet.py +17 -18
  112. openstackclient/network/v2/subnet_pool.py +11 -9
  113. openstackclient/network/v2/taas/__init__.py +0 -0
  114. openstackclient/network/v2/taas/tap_flow.py +245 -0
  115. openstackclient/network/v2/taas/tap_mirror.py +237 -0
  116. openstackclient/network/v2/taas/tap_service.py +211 -0
  117. openstackclient/object/v1/account.py +1 -1
  118. openstackclient/object/v1/container.py +1 -1
  119. openstackclient/object/v1/object.py +1 -1
  120. openstackclient/shell.py +18 -8
  121. openstackclient/tests/functional/identity/v3/test_access_rule.py +1 -1
  122. openstackclient/tests/functional/identity/v3/test_application_credential.py +7 -7
  123. openstackclient/tests/functional/identity/v3/test_catalog.py +42 -23
  124. openstackclient/tests/functional/identity/v3/test_role_assignment.py +174 -0
  125. openstackclient/tests/functional/image/v2/test_cache.py +54 -0
  126. openstackclient/tests/functional/image/v2/test_image.py +36 -14
  127. openstackclient/tests/functional/image/v2/test_metadef_resource_type.py +55 -0
  128. openstackclient/tests/functional/volume/v2/test_volume.py +1 -1
  129. openstackclient/tests/functional/volume/v3/test_volume.py +2 -2
  130. openstackclient/tests/unit/api/test_volume_v2.py +124 -0
  131. openstackclient/tests/unit/api/test_volume_v3.py +124 -0
  132. openstackclient/tests/unit/common/test_command.py +1 -1
  133. openstackclient/tests/unit/common/test_extension.py +2 -3
  134. openstackclient/tests/unit/common/test_module.py +14 -7
  135. openstackclient/tests/unit/common/test_quota.py +20 -0
  136. openstackclient/tests/unit/compute/v2/test_aggregate.py +5 -3
  137. openstackclient/tests/unit/compute/v2/test_console.py +1 -4
  138. openstackclient/tests/unit/compute/v2/test_flavor.py +160 -177
  139. openstackclient/tests/unit/compute/v2/test_hypervisor_stats.py +1 -9
  140. openstackclient/tests/unit/compute/v2/test_server.py +406 -81
  141. openstackclient/tests/unit/compute/v2/test_server_backup.py +1 -3
  142. openstackclient/tests/unit/compute/v2/test_service.py +1 -3
  143. openstackclient/tests/unit/fakes.py +35 -134
  144. openstackclient/tests/unit/identity/test_common.py +100 -0
  145. openstackclient/tests/unit/identity/v2_0/test_project.py +4 -4
  146. openstackclient/tests/unit/identity/v3/fakes.py +10 -2
  147. openstackclient/tests/unit/identity/v3/test_application_credential.py +50 -44
  148. openstackclient/tests/unit/identity/v3/test_domain.py +3 -3
  149. openstackclient/tests/unit/identity/v3/test_endpoint.py +1 -1
  150. openstackclient/tests/unit/identity/v3/test_group.py +4 -2
  151. openstackclient/tests/unit/identity/v3/test_identity_provider.py +10 -10
  152. openstackclient/tests/unit/identity/v3/test_oauth.py +1 -1
  153. openstackclient/tests/unit/identity/v3/test_project.py +31 -54
  154. openstackclient/tests/unit/identity/v3/test_registered_limit.py +2 -2
  155. openstackclient/tests/unit/identity/v3/test_role.py +3 -90
  156. openstackclient/tests/unit/identity/v3/test_user.py +7 -51
  157. openstackclient/tests/unit/image/v1/test_image.py +47 -0
  158. openstackclient/tests/unit/image/v2/test_image.py +190 -9
  159. openstackclient/tests/unit/image/v2/test_metadef_objects.py +22 -0
  160. openstackclient/tests/unit/image/v2/test_metadef_properties.py +24 -10
  161. openstackclient/tests/unit/network/test_common.py +9 -13
  162. openstackclient/tests/unit/network/v2/fakes.py +1 -0
  163. openstackclient/tests/unit/network/v2/taas/__init__.py +0 -0
  164. openstackclient/tests/unit/network/v2/taas/test_osc_tap_flow.py +276 -0
  165. openstackclient/tests/unit/network/v2/taas/test_osc_tap_mirror.py +288 -0
  166. openstackclient/tests/unit/network/v2/taas/test_osc_tap_service.py +271 -0
  167. openstackclient/tests/unit/network/v2/test_address_group.py +19 -22
  168. openstackclient/tests/unit/network/v2/test_address_scope.py +10 -15
  169. openstackclient/tests/unit/network/v2/test_default_security_group_rule.py +38 -49
  170. openstackclient/tests/unit/network/v2/test_floating_ip_network.py +21 -27
  171. openstackclient/tests/unit/network/v2/test_floating_ip_port_forwarding.py +21 -18
  172. openstackclient/tests/unit/network/v2/test_ip_availability.py +6 -8
  173. openstackclient/tests/unit/network/v2/test_l3_conntrack_helper.py +6 -15
  174. openstackclient/tests/unit/network/v2/test_local_ip.py +12 -23
  175. openstackclient/tests/unit/network/v2/test_local_ip_association.py +13 -18
  176. openstackclient/tests/unit/network/v2/test_ndp_proxy.py +13 -23
  177. openstackclient/tests/unit/network/v2/test_network.py +41 -37
  178. openstackclient/tests/unit/network/v2/test_network_agent.py +13 -20
  179. openstackclient/tests/unit/network/v2/test_network_auto_allocated_topology.py +5 -8
  180. openstackclient/tests/unit/network/v2/test_network_flavor.py +14 -26
  181. openstackclient/tests/unit/network/v2/test_network_flavor_profile.py +14 -17
  182. openstackclient/tests/unit/network/v2/test_network_meter.py +7 -17
  183. openstackclient/tests/unit/network/v2/test_network_meter_rule.py +10 -20
  184. openstackclient/tests/unit/network/v2/test_network_qos_policy.py +7 -13
  185. openstackclient/tests/unit/network/v2/test_network_qos_rule.py +44 -54
  186. openstackclient/tests/unit/network/v2/test_network_qos_rule_type.py +2 -7
  187. openstackclient/tests/unit/network/v2/test_network_rbac.py +21 -36
  188. openstackclient/tests/unit/network/v2/test_network_segment.py +13 -29
  189. openstackclient/tests/unit/network/v2/test_network_segment_range.py +20 -19
  190. openstackclient/tests/unit/network/v2/test_network_service_provider.py +1 -4
  191. openstackclient/tests/unit/network/v2/test_network_trunk.py +52 -47
  192. openstackclient/tests/unit/network/v2/test_port.py +113 -84
  193. openstackclient/tests/unit/network/v2/test_router.py +104 -126
  194. openstackclient/tests/unit/network/v2/test_security_group_network.py +25 -26
  195. openstackclient/tests/unit/network/v2/test_security_group_rule_network.py +66 -18
  196. openstackclient/tests/unit/network/v2/test_subnet.py +35 -46
  197. openstackclient/tests/unit/network/v2/test_subnet_pool.py +21 -33
  198. openstackclient/tests/unit/volume/test_find_resource.py +4 -13
  199. openstackclient/tests/unit/volume/v2/test_volume.py +358 -305
  200. openstackclient/tests/unit/volume/v2/test_volume_backup.py +3 -1
  201. openstackclient/tests/unit/volume/v3/test_volume.py +443 -415
  202. openstackclient/tests/unit/volume/v3/test_volume_backup.py +9 -0
  203. openstackclient/volume/client.py +7 -17
  204. openstackclient/volume/v2/backup_record.py +1 -1
  205. openstackclient/volume/v2/consistency_group.py +1 -1
  206. openstackclient/volume/v2/consistency_group_snapshot.py +1 -1
  207. openstackclient/volume/v2/qos_specs.py +1 -1
  208. openstackclient/volume/v2/service.py +2 -2
  209. openstackclient/volume/v2/volume.py +80 -54
  210. openstackclient/volume/v2/volume_backend.py +1 -1
  211. openstackclient/volume/v2/volume_backup.py +5 -3
  212. openstackclient/volume/v2/volume_host.py +1 -2
  213. openstackclient/volume/v2/volume_snapshot.py +2 -2
  214. openstackclient/volume/v2/volume_transfer_request.py +1 -1
  215. openstackclient/volume/v2/volume_type.py +11 -6
  216. openstackclient/volume/v3/block_storage_cleanup.py +1 -1
  217. openstackclient/volume/v3/block_storage_cluster.py +1 -1
  218. openstackclient/volume/v3/block_storage_log_level.py +1 -1
  219. openstackclient/volume/v3/block_storage_manage.py +1 -1
  220. openstackclient/volume/v3/block_storage_resource_filter.py +1 -1
  221. openstackclient/volume/v3/service.py +2 -2
  222. openstackclient/volume/v3/volume.py +104 -77
  223. openstackclient/volume/v3/volume_attachment.py +6 -5
  224. openstackclient/volume/v3/volume_backup.py +18 -3
  225. openstackclient/volume/v3/volume_group.py +2 -2
  226. openstackclient/volume/v3/volume_group_snapshot.py +1 -1
  227. openstackclient/volume/v3/volume_group_type.py +1 -1
  228. openstackclient/volume/v3/volume_message.py +1 -1
  229. openstackclient/volume/v3/volume_snapshot.py +2 -2
  230. openstackclient/volume/v3/volume_transfer_request.py +1 -1
  231. openstackclient/volume/v3/volume_type.py +15 -9
  232. {python_openstackclient-8.1.0.dist-info → python_openstackclient-8.3.0.dist-info}/METADATA +19 -17
  233. {python_openstackclient-8.1.0.dist-info → python_openstackclient-8.3.0.dist-info}/RECORD +239 -224
  234. {python_openstackclient-8.1.0.dist-info → python_openstackclient-8.3.0.dist-info}/WHEEL +1 -1
  235. {python_openstackclient-8.1.0.dist-info → python_openstackclient-8.3.0.dist-info}/entry_points.txt +15 -0
  236. {python_openstackclient-8.1.0.dist-info → python_openstackclient-8.3.0.dist-info/licenses}/AUTHORS +15 -0
  237. python_openstackclient-8.3.0.dist-info/pbr.json +1 -0
  238. openstackclient/tests/unit/common/test_logs.py +0 -221
  239. python_openstackclient-8.1.0.dist-info/pbr.json +0 -1
  240. {python_openstackclient-8.1.0.dist-info → python_openstackclient-8.3.0.dist-info/licenses}/LICENSE +0 -0
  241. {python_openstackclient-8.1.0.dist-info → python_openstackclient-8.3.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,211 @@
1
+ # All Rights Reserved 2020
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+ # not use this file except in compliance with the License. You may obtain
5
+ # a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+ # License for the specific language governing permissions and limitations
13
+ # under the License.
14
+
15
+ import logging
16
+
17
+ from osc_lib.cli import identity as identity_utils
18
+ from osc_lib import exceptions
19
+ from osc_lib import utils as osc_utils
20
+ from osc_lib.utils import columns as column_util
21
+
22
+ from openstackclient import command
23
+ from openstackclient.i18n import _
24
+ from openstackclient.identity import common
25
+
26
+ LOG = logging.getLogger(__name__)
27
+
28
+ TAP_SERVICE = 'tap_service'
29
+ TAP_SERVICES = f'{TAP_SERVICE}s'
30
+
31
+ _attr_map = [
32
+ ('id', 'ID', column_util.LIST_BOTH),
33
+ ('tenant_id', 'Tenant', column_util.LIST_LONG_ONLY),
34
+ ('name', 'Name', column_util.LIST_BOTH),
35
+ ('port_id', 'Port', column_util.LIST_BOTH),
36
+ ('status', 'Status', column_util.LIST_BOTH),
37
+ ]
38
+
39
+
40
+ def _add_updatable_args(parser):
41
+ parser.add_argument('--name', help=_('Name of the tap service.'))
42
+ parser.add_argument(
43
+ '--description', help=_('Description of the tap service.')
44
+ )
45
+
46
+
47
+ def _get_columns(item):
48
+ column_map: dict[str, str] = {}
49
+ hidden_columns = ['location', 'tenant_id']
50
+ return osc_utils.get_osc_show_columns_for_sdk_resource(
51
+ item, column_map, hidden_columns
52
+ )
53
+
54
+
55
+ class CreateTapService(command.ShowOne):
56
+ _description = _("Create a new tap service.")
57
+
58
+ def get_parser(self, prog_name):
59
+ parser = super().get_parser(prog_name)
60
+ identity_utils.add_project_owner_option_to_parser(parser)
61
+ _add_updatable_args(parser)
62
+ parser.add_argument(
63
+ '--port',
64
+ dest='port_id',
65
+ required=True,
66
+ metavar="PORT",
67
+ help=_('Port (name or ID) to connect to the tap service.'),
68
+ )
69
+ return parser
70
+
71
+ def take_action(self, parsed_args):
72
+ client = self.app.client_manager.network
73
+ attrs = {}
74
+ if parsed_args.name is not None:
75
+ attrs['name'] = parsed_args.name
76
+ if parsed_args.description is not None:
77
+ attrs['description'] = parsed_args.description
78
+ if parsed_args.port_id is not None:
79
+ port_id = client.find_port(
80
+ parsed_args.port_id, ignore_missing=False
81
+ ).id
82
+ attrs['port_id'] = port_id
83
+ if 'project' in parsed_args and parsed_args.project is not None:
84
+ attrs['project_id'] = common.find_project(
85
+ self.app.client_manager.identity,
86
+ parsed_args.project,
87
+ parsed_args.project_domain,
88
+ ).id
89
+ obj = client.create_tap_service(**attrs)
90
+ display_columns, columns = _get_columns(obj)
91
+ data = osc_utils.get_dict_properties(obj, columns)
92
+ return display_columns, data
93
+
94
+
95
+ class ListTapService(command.Lister):
96
+ _description = _("List tap services.")
97
+
98
+ def get_parser(self, prog_name):
99
+ parser = super().get_parser(prog_name)
100
+ identity_utils.add_project_owner_option_to_parser(parser)
101
+
102
+ return parser
103
+
104
+ def take_action(self, parsed_args):
105
+ client = self.app.client_manager.network
106
+ params = {}
107
+ if parsed_args.project is not None:
108
+ params['project_id'] = common.find_project(
109
+ self.app.client_manager.identity,
110
+ parsed_args.project,
111
+ parsed_args.project_domain,
112
+ ).id
113
+ objs = client.tap_services(retrieve_all=True, params=params)
114
+ headers, columns = column_util.get_column_definitions(
115
+ _attr_map, long_listing=True
116
+ )
117
+ return (
118
+ headers,
119
+ (osc_utils.get_dict_properties(s, columns) for s in objs),
120
+ )
121
+
122
+
123
+ class ShowTapService(command.ShowOne):
124
+ _description = _("Show tap service details.")
125
+
126
+ def get_parser(self, prog_name):
127
+ parser = super().get_parser(prog_name)
128
+ parser.add_argument(
129
+ TAP_SERVICE,
130
+ metavar=f"<{TAP_SERVICE}>",
131
+ help=_("Tap service to display (name or ID)."),
132
+ )
133
+ return parser
134
+
135
+ def take_action(self, parsed_args):
136
+ client = self.app.client_manager.network
137
+ id = client.find_tap_service(
138
+ parsed_args.tap_service, ignore_missing=False
139
+ ).id
140
+ obj = client.get_tap_service(id)
141
+ display_columns, columns = _get_columns(obj)
142
+ data = osc_utils.get_dict_properties(obj, columns)
143
+ return display_columns, data
144
+
145
+
146
+ class DeleteTapService(command.Command):
147
+ _description = _("Delete a tap service.")
148
+
149
+ def get_parser(self, prog_name):
150
+ parser = super().get_parser(prog_name)
151
+ parser.add_argument(
152
+ TAP_SERVICE,
153
+ metavar=f"<{TAP_SERVICE}>",
154
+ nargs="+",
155
+ help=_("Tap service to delete (name or ID)."),
156
+ )
157
+ return parser
158
+
159
+ def take_action(self, parsed_args):
160
+ client = self.app.client_manager.network
161
+ fails = 0
162
+ for id_or_name in parsed_args.tap_service:
163
+ try:
164
+ id = client.find_tap_service(
165
+ id_or_name, ignore_missing=False
166
+ ).id
167
+
168
+ client.delete_tap_service(id)
169
+ LOG.warning("Tap service %(id)s deleted", {'id': id})
170
+ except Exception as e:
171
+ fails += 1
172
+ LOG.error(
173
+ "Failed to delete tap service with name or ID "
174
+ "'%(id_or_name)s': %(e)s",
175
+ {'id_or_name': id_or_name, 'e': e},
176
+ )
177
+ if fails > 0:
178
+ msg = _("Failed to delete %(fails)s of %(total)s tap service.") % {
179
+ 'fails': fails,
180
+ 'total': len(parsed_args.tap_service),
181
+ }
182
+ raise exceptions.CommandError(msg)
183
+
184
+
185
+ class UpdateTapService(command.ShowOne):
186
+ _description = _("Update a tap service.")
187
+
188
+ def get_parser(self, prog_name):
189
+ parser = super().get_parser(prog_name)
190
+ parser.add_argument(
191
+ TAP_SERVICE,
192
+ metavar=f"<{TAP_SERVICE}>",
193
+ help=_("Tap service to modify (name or ID)."),
194
+ )
195
+ _add_updatable_args(parser)
196
+ return parser
197
+
198
+ def take_action(self, parsed_args):
199
+ client = self.app.client_manager.network
200
+ original_t_s = client.find_tap_service(
201
+ parsed_args.tap_service, ignore_missing=False
202
+ ).id
203
+ attrs = {}
204
+ if parsed_args.name is not None:
205
+ attrs['name'] = parsed_args.name
206
+ if parsed_args.description is not None:
207
+ attrs['description'] = parsed_args.description
208
+ obj = client.update_tap_service(original_t_s, **attrs)
209
+ display_columns, columns = _get_columns(obj)
210
+ data = osc_utils.get_dict_properties(obj, columns)
211
+ return display_columns, data
@@ -15,8 +15,8 @@
15
15
 
16
16
  from osc_lib.cli import format_columns
17
17
  from osc_lib.cli import parseractions
18
- from osc_lib.command import command
19
18
 
19
+ from openstackclient import command
20
20
  from openstackclient.i18n import _
21
21
 
22
22
 
@@ -19,9 +19,9 @@ import logging
19
19
 
20
20
  from osc_lib.cli import format_columns
21
21
  from osc_lib.cli import parseractions
22
- from osc_lib.command import command
23
22
  from osc_lib import utils
24
23
 
24
+ from openstackclient import command
25
25
  from openstackclient.common import pagination
26
26
  from openstackclient.i18n import _
27
27
 
@@ -19,10 +19,10 @@ import logging
19
19
 
20
20
  from osc_lib.cli import format_columns
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.common import pagination
27
27
  from openstackclient.i18n import _
28
28
 
openstackclient/shell.py CHANGED
@@ -26,16 +26,27 @@ from osc_lib import shell
26
26
  import openstackclient
27
27
  from openstackclient.common import clientmanager
28
28
 
29
-
30
29
  DEFAULT_DOMAIN = 'default'
30
+ # list of modules that were originally out-of-tree and are now in
31
+ # core OSC
32
+ IGNORED_MODULES = (
33
+ 'neutron_taas.taas_client.osc',
34
+ 'neutronclient.osc.v2.taas',
35
+ )
31
36
 
32
37
 
33
38
  class OpenStackShell(shell.OpenStackShell):
39
+ client_manager: clientmanager.ClientManager
40
+
34
41
  def __init__(self):
42
+ command_manager = commandmanager.CommandManager(
43
+ 'openstack.cli', ignored_modules=IGNORED_MODULES
44
+ )
45
+
35
46
  super().__init__(
36
47
  description=__doc__.strip(),
37
48
  version=openstackclient.__version__,
38
- command_manager=commandmanager.CommandManager('openstack.cli'),
49
+ command_manager=command_manager,
39
50
  deferred_help=True,
40
51
  )
41
52
 
@@ -48,8 +59,10 @@ class OpenStackShell(shell.OpenStackShell):
48
59
  # about them
49
60
  warnings.filterwarnings('ignore', module='openstack')
50
61
 
51
- def build_option_parser(self, description, version):
52
- parser = super().build_option_parser(description, version)
62
+ def build_option_parser(self, description, version, argparse_kwargs=None):
63
+ parser = super().build_option_parser(
64
+ description, version, argparse_kwargs
65
+ )
53
66
  parser = clientmanager.build_plugin_option_parser(parser)
54
67
  parser = auth.build_auth_plugins_option_parser(parser)
55
68
  return parser
@@ -65,10 +78,7 @@ class OpenStackShell(shell.OpenStackShell):
65
78
  self._auth_type = 'password'
66
79
 
67
80
  def _load_plugins(self):
68
- """Load plugins via stevedore
69
-
70
- osc-lib has no opinion on what plugins should be loaded
71
- """
81
+ """Load plugins via stevedore."""
72
82
  # Loop through extensions to get API versions
73
83
  for mod in clientmanager.PLUGIN_MODULES:
74
84
  default_version = getattr(mod, 'DEFAULT_API_VERSION', None)
@@ -62,7 +62,7 @@ class AccessRuleTests(common.IdentityTests):
62
62
 
63
63
  items = self.parse_show_as_object(raw_output)
64
64
  self.access_rule_ids = [
65
- x['id'] for x in ast.literal_eval(items['access_rules'])
65
+ x['id'] for x in ast.literal_eval(items['Access Rules'])
66
66
  ]
67
67
  self.addCleanup(
68
68
  self.openstack,
@@ -21,13 +21,13 @@ from openstackclient.tests.functional.identity.v3 import common
21
21
 
22
22
  class ApplicationCredentialTests(common.IdentityTests):
23
23
  APPLICATION_CREDENTIAL_FIELDS = [
24
- 'id',
25
- 'name',
26
- 'project_id',
27
- 'description',
28
- 'roles',
29
- 'expires_at',
30
- 'unrestricted',
24
+ 'ID',
25
+ 'Name',
26
+ 'Project ID',
27
+ 'Description',
28
+ 'Roles',
29
+ 'Expires At',
30
+ 'Unrestricted',
31
31
  ]
32
32
  APPLICATION_CREDENTIAL_LIST_HEADERS = [
33
33
  'ID',
@@ -10,35 +10,54 @@
10
10
  # License for the specific language governing permissions and limitations
11
11
  # under the License.
12
12
 
13
+
13
14
  from openstackclient.tests.functional.identity.v3 import common
14
15
 
15
16
 
16
17
  class CatalogTests(common.IdentityTests):
17
- def test_catalog_list(self):
18
+ """Functional tests for catalog commands"""
19
+
20
+ def test_catalog(self):
21
+ """Test catalog list and show functionality"""
22
+ # Create a test service for isolated testing
23
+ _dummy_service_name = self._create_dummy_service(add_clean_up=True)
24
+
25
+ # list catalogs
18
26
  raw_output = self.openstack('catalog list')
19
27
  items = self.parse_listing(raw_output)
20
28
  self.assert_table_structure(items, ['Name', 'Type', 'Endpoints'])
21
29
 
22
- def test_catalog_show(self):
23
- """test catalog show command
24
-
25
- The output example:
26
- +-----------+----------------------------------------+
27
- | Field | Value |
28
- +-----------+----------------------------------------+
29
- | endpoints | test1 |
30
- | | public: http://localhost:5000/v2.0 |
31
- | | test1 |
32
- | | internal: http://localhost:5000/v2.0 |
33
- | | test1 |
34
- | | admin: http://localhost:35357/v2.0 |
35
- | | |
36
- | id | e1e68b5ba21a43a39ff1cf58e736c3aa |
37
- | name | keystone |
38
- | type | identity |
39
- +-----------+----------------------------------------+
40
- """
41
- raw_output = self.openstack('catalog show {}'.format('identity'))
30
+ # Verify created service appears in catalog
31
+ service_names = [
32
+ item.get('Name') for item in items if item.get('Name')
33
+ ]
34
+ self.assertIn(
35
+ _dummy_service_name,
36
+ service_names,
37
+ "Created dummy service should be present in catalog",
38
+ )
39
+
40
+ # show service (by name)
41
+ raw_output = self.openstack(f'catalog show {_dummy_service_name}')
42
42
  items = self.parse_show(raw_output)
43
- # items may have multiple endpoint urls with empty key
44
- self.assert_show_fields(items, ['endpoints', 'name', 'type', '', 'id'])
43
+ self.assert_show_fields(items, ['endpoints', 'name', 'type', 'id'])
44
+
45
+ # Extract the type from the dummy service
46
+ _dummy_service_type = next(
47
+ (item['type'] for item in items if 'type' in item), None
48
+ )
49
+
50
+ # show service (by type)
51
+ raw_output = self.openstack(f'catalog show {_dummy_service_type}')
52
+ items = self.parse_show(raw_output)
53
+ self.assert_show_fields(items, ['endpoints', 'name', 'type', 'id'])
54
+
55
+ # show service (non-existent)
56
+ result = self.openstack(
57
+ 'catalog show nonexistent-service-xyz', fail_ok=True
58
+ )
59
+ self.assertEqual(
60
+ '',
61
+ result.strip(),
62
+ "Non-existent service should return empty result",
63
+ )
@@ -62,6 +62,47 @@ class RoleAssignmentTests(common.IdentityTests):
62
62
  items = self.parse_listing(raw_output)
63
63
  self.assert_table_structure(items, self.ROLE_ASSIGNMENT_LIST_HEADERS)
64
64
 
65
+ def test_role_assignment_list_group_domain(self):
66
+ domain_name_A = self._create_dummy_domain()
67
+ domain_name_B = self._create_dummy_domain()
68
+ role_name = self._create_dummy_role()
69
+ group_name = 'group_name'
70
+ self.openstack(f'group create --domain {domain_name_A} {group_name}')
71
+ self.addCleanup(
72
+ self.openstack,
73
+ f'group delete --domain {domain_name_A} {group_name}',
74
+ )
75
+ self.openstack(f'group create --domain {domain_name_B} {group_name}')
76
+ self.addCleanup(
77
+ self.openstack,
78
+ f'group delete --domain {domain_name_B} {group_name}',
79
+ )
80
+ raw_output = self.openstack(
81
+ 'role add '
82
+ f'--project {self.project_name} '
83
+ f'--group {group_name} --group-domain {domain_name_A} '
84
+ f'{role_name}'
85
+ )
86
+ self.addCleanup(
87
+ self.openstack,
88
+ 'role remove '
89
+ f'--project {self.project_name} '
90
+ f'--group {group_name} --group-domain {domain_name_A} '
91
+ f'{role_name}',
92
+ )
93
+ self.assertEqual('', raw_output.strip())
94
+ raw_output = self.openstack(
95
+ f'role assignment list '
96
+ f'--group {group_name} --group-domain {domain_name_A} '
97
+ )
98
+ items = self.parse_listing(raw_output)
99
+ self.assert_table_structure(items, self.ROLE_ASSIGNMENT_LIST_HEADERS)
100
+ raw_output = self.openstack(
101
+ f'role assignment list '
102
+ f'--group {group_name} --group-domain {domain_name_B} '
103
+ )
104
+ self.assertEqual('', raw_output.strip())
105
+
65
106
  def test_role_assignment_list_domain(self):
66
107
  role_name = self._create_dummy_role()
67
108
  username = self._create_dummy_user()
@@ -85,6 +126,89 @@ class RoleAssignmentTests(common.IdentityTests):
85
126
  items = self.parse_listing(raw_output)
86
127
  self.assert_table_structure(items, self.ROLE_ASSIGNMENT_LIST_HEADERS)
87
128
 
129
+ def test_role_assignment_list_user_domain(self):
130
+ domain_name_A = self._create_dummy_domain()
131
+ domain_name_B = self._create_dummy_domain()
132
+ role_name = self._create_dummy_role()
133
+ username = 'username'
134
+ self.openstack(f'user create --domain {domain_name_A} {username}')
135
+ self.addCleanup(
136
+ self.openstack, f'user delete --domain {domain_name_A} {username}'
137
+ )
138
+ self.openstack(f'user create --domain {domain_name_B} {username}')
139
+ self.addCleanup(
140
+ self.openstack, f'user delete --domain {domain_name_B} {username}'
141
+ )
142
+ raw_output = self.openstack(
143
+ 'role add '
144
+ f'--project {self.project_name} '
145
+ f'--user {username} --user-domain {domain_name_A} '
146
+ f'{role_name}'
147
+ )
148
+ self.addCleanup(
149
+ self.openstack,
150
+ 'role remove '
151
+ f'--project {self.project_name} '
152
+ f'--user {username} --user-domain {domain_name_A} '
153
+ f'{role_name}',
154
+ )
155
+ self.assertEqual('', raw_output.strip())
156
+ raw_output = self.openstack(
157
+ f'role assignment list '
158
+ f'--user {username} --user-domain {domain_name_A} '
159
+ )
160
+ items = self.parse_listing(raw_output)
161
+ self.assert_table_structure(items, self.ROLE_ASSIGNMENT_LIST_HEADERS)
162
+ raw_output = self.openstack(
163
+ f'role assignment list '
164
+ f'--user {username} --user-domain {domain_name_B} '
165
+ )
166
+ self.assertEqual('', raw_output.strip())
167
+
168
+ def test_role_assignment_list_role_domain(self):
169
+ domain_name_A = self._create_dummy_domain()
170
+ domain_name_B = self._create_dummy_domain()
171
+ role_name = 'role_name'
172
+ username = 'username'
173
+ self.openstack(f'role create --domain {domain_name_A} {role_name}')
174
+ self.addCleanup(
175
+ self.openstack, f'role delete --domain {domain_name_A} {role_name}'
176
+ )
177
+ self.openstack(f'role create --domain {domain_name_B} {role_name}')
178
+ self.addCleanup(
179
+ self.openstack, f'role delete --domain {domain_name_B} {role_name}'
180
+ )
181
+ self.openstack(f'user create --domain {domain_name_A} {username}')
182
+ self.addCleanup(
183
+ self.openstack, f'user delete --domain {domain_name_A} {username}'
184
+ )
185
+ raw_output = self.openstack(
186
+ 'role add '
187
+ f'--user {username} --domain {domain_name_A} '
188
+ f'--role-domain {domain_name_A} '
189
+ f'{role_name}'
190
+ )
191
+ self.addCleanup(
192
+ self.openstack,
193
+ 'role remove '
194
+ f'--user {username} --domain {domain_name_A} '
195
+ f'--role-domain {domain_name_A} '
196
+ f'{role_name}',
197
+ )
198
+ self.assertEqual('', raw_output.strip())
199
+ raw_output = self.openstack(
200
+ f'role assignment list '
201
+ f'--role {role_name} --role-domain {domain_name_A}'
202
+ )
203
+ items = self.parse_listing(raw_output)
204
+ self.assert_table_structure(items, self.ROLE_ASSIGNMENT_LIST_HEADERS)
205
+ raw_output = self.openstack(
206
+ f'role assignment list '
207
+ f'--role {role_name} --role-domain {domain_name_B}'
208
+ )
209
+ items = self.parse_listing(raw_output)
210
+ self.assertEqual('', raw_output.strip())
211
+
88
212
  def test_role_assignment_list_project(self):
89
213
  role_name = self._create_dummy_role()
90
214
  username = self._create_dummy_user()
@@ -108,6 +232,56 @@ class RoleAssignmentTests(common.IdentityTests):
108
232
  items = self.parse_listing(raw_output)
109
233
  self.assert_table_structure(items, self.ROLE_ASSIGNMENT_LIST_HEADERS)
110
234
 
235
+ def test_role_assignment_list_project_domain(self):
236
+ domain_name_A = self._create_dummy_domain()
237
+ domain_name_B = self._create_dummy_domain()
238
+ role_name = self._create_dummy_role()
239
+ project_name = 'project_name'
240
+ username = 'username'
241
+ self.openstack(
242
+ f'project create --domain {domain_name_A} {project_name}'
243
+ )
244
+ self.addCleanup(
245
+ self.openstack,
246
+ f'project delete --domain {domain_name_A} {project_name}',
247
+ )
248
+ self.openstack(
249
+ f'project create --domain {domain_name_B} {project_name}'
250
+ )
251
+ self.addCleanup(
252
+ self.openstack,
253
+ f'project delete --domain {domain_name_B} {project_name}',
254
+ )
255
+ self.openstack(f'user create --domain {domain_name_A} {username}')
256
+ self.addCleanup(
257
+ self.openstack, f'user delete --domain {domain_name_A} {username}'
258
+ )
259
+ raw_output = self.openstack(
260
+ 'role add '
261
+ f'--project {project_name} --project-domain {domain_name_A} '
262
+ f'--user {username} --user-domain {domain_name_A} '
263
+ f'{role_name}'
264
+ )
265
+ self.addCleanup(
266
+ self.openstack,
267
+ 'role remove '
268
+ f'--project {project_name} --project-domain {domain_name_A} '
269
+ f'--user {username} --user-domain {domain_name_A} '
270
+ f'{role_name}',
271
+ )
272
+ self.assertEqual('', raw_output.strip())
273
+ raw_output = self.openstack(
274
+ f'role assignment list '
275
+ f'--project {project_name} --project-domain {domain_name_A} '
276
+ )
277
+ items = self.parse_listing(raw_output)
278
+ self.assert_table_structure(items, self.ROLE_ASSIGNMENT_LIST_HEADERS)
279
+ raw_output = self.openstack(
280
+ f'role assignment list '
281
+ f'--project {project_name} --project-domain {domain_name_B} '
282
+ )
283
+ self.assertEqual('', raw_output.strip())
284
+
111
285
  def test_role_assignment_list_effective(self):
112
286
  raw_output = self.openstack('role assignment list --effective')
113
287
  items = self.parse_listing(raw_output)
@@ -0,0 +1,54 @@
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
+ import uuid
14
+
15
+ from openstackclient.tests.functional.image import base
16
+
17
+
18
+ class CacheTests(base.BaseImageTests):
19
+ """Functional tests for Cache commands"""
20
+
21
+ def test_cached_image(self):
22
+ """Test cached image operations including queue and clear"""
23
+ # Create test image
24
+ name = uuid.uuid4().hex
25
+ output = self.openstack(
26
+ f'image create {name}',
27
+ parse_output=True,
28
+ )
29
+ image_id = output["id"]
30
+ self.assertOutput(name, output['name'])
31
+
32
+ # Register cleanup for created image
33
+ self.addCleanup(
34
+ self.openstack, 'cached image delete ' + image_id, fail_ok=True
35
+ )
36
+ self.addCleanup(self.openstack, 'image delete ' + image_id)
37
+
38
+ # Queue image for caching
39
+ self.openstack('cached image queue ' + image_id)
40
+
41
+ # Verify queuing worked
42
+ cache_output = self.openstack('cached image list', parse_output=True)
43
+ self.assertIsInstance(cache_output, list)
44
+ image_ids = [img['ID'] for img in cache_output]
45
+ self.assertIn(image_id, image_ids)
46
+
47
+ # Clear cached images
48
+ self.openstack('cached image clear')
49
+
50
+ # Verify clearing worked
51
+ output = self.openstack('cached image list', parse_output=True)
52
+ if output:
53
+ image_ids = [img['ID'] for img in output]
54
+ self.assertNotIn(image_id, image_ids)