python-openstackclient 6.3.0__py3-none-any.whl → 6.5.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.
- openstackclient/common/availability_zone.py +4 -4
- openstackclient/common/pagination.py +82 -0
- openstackclient/compute/v2/flavor.py +2 -16
- openstackclient/compute/v2/hypervisor.py +2 -21
- openstackclient/compute/v2/keypair.py +2 -9
- openstackclient/compute/v2/server.py +220 -131
- openstackclient/compute/v2/server_event.py +30 -19
- openstackclient/compute/v2/server_group.py +2 -23
- openstackclient/compute/v2/server_migration.py +2 -22
- openstackclient/compute/v2/usage.py +4 -6
- openstackclient/identity/v3/mapping.py +25 -3
- openstackclient/identity/v3/policy.py +3 -1
- openstackclient/image/v2/cache.py +218 -0
- openstackclient/image/v2/image.py +40 -17
- openstackclient/image/v2/metadef_namespaces.py +25 -21
- openstackclient/image/v2/metadef_objects.py +189 -0
- openstackclient/image/v2/metadef_properties.py +284 -0
- openstackclient/network/utils.py +100 -0
- openstackclient/network/v2/default_security_group_rule.py +418 -0
- openstackclient/network/v2/local_ip_association.py +1 -1
- openstackclient/network/v2/ndp_proxy.py +7 -3
- openstackclient/network/v2/network.py +2 -2
- openstackclient/network/v2/port.py +65 -19
- openstackclient/network/v2/security_group_rule.py +18 -111
- openstackclient/network/v2/subnet.py +1 -0
- openstackclient/object/v1/container.py +2 -12
- openstackclient/object/v1/object.py +2 -11
- openstackclient/tests/functional/base.py +13 -6
- openstackclient/tests/functional/identity/v3/test_role.py +11 -3
- openstackclient/tests/functional/network/v2/common.py +7 -1
- openstackclient/tests/functional/network/v2/test_address_group.py +2 -4
- openstackclient/tests/functional/network/v2/test_address_scope.py +0 -6
- openstackclient/tests/functional/network/v2/test_default_security_group_rule.py +67 -0
- openstackclient/tests/functional/network/v2/test_floating_ip.py +3 -6
- openstackclient/tests/functional/network/v2/test_ip_availability.py +3 -8
- openstackclient/tests/functional/network/v2/test_l3_conntrack_helper.py +3 -4
- openstackclient/tests/functional/network/v2/test_local_ip.py +2 -4
- openstackclient/tests/functional/network/v2/test_network.py +18 -17
- openstackclient/tests/functional/network/v2/test_network_agent.py +24 -21
- openstackclient/tests/functional/network/v2/test_network_flavor.py +0 -6
- openstackclient/tests/functional/network/v2/test_network_flavor_profile.py +0 -6
- openstackclient/tests/functional/network/v2/test_network_meter.py +6 -6
- openstackclient/tests/functional/network/v2/test_network_meter_rule.py +7 -8
- openstackclient/tests/functional/network/v2/test_network_ndp_proxy.py +1 -3
- openstackclient/tests/functional/network/v2/test_network_qos_policy.py +4 -4
- openstackclient/tests/functional/network/v2/test_network_qos_rule.py +16 -20
- openstackclient/tests/functional/network/v2/test_network_qos_rule_type.py +4 -4
- openstackclient/tests/functional/network/v2/test_network_rbac.py +1 -4
- openstackclient/tests/functional/network/v2/test_network_segment.py +7 -12
- openstackclient/tests/functional/network/v2/test_network_segment_range.py +3 -4
- openstackclient/tests/functional/network/v2/test_network_service_provider.py +2 -4
- openstackclient/tests/functional/network/v2/test_network_trunk.py +3 -3
- openstackclient/tests/functional/network/v2/test_port.py +2 -8
- openstackclient/tests/functional/network/v2/test_router.py +0 -6
- openstackclient/tests/functional/network/v2/test_security_group.py +1 -4
- openstackclient/tests/functional/network/v2/test_security_group_rule.py +1 -4
- openstackclient/tests/functional/network/v2/test_subnet.py +4 -22
- openstackclient/tests/functional/network/v2/test_subnet_pool.py +0 -6
- openstackclient/tests/unit/common/test_availability_zone.py +28 -30
- openstackclient/tests/unit/common/test_extension.py +1 -4
- openstackclient/tests/unit/common/test_limits.py +2 -4
- openstackclient/tests/unit/common/test_project_cleanup.py +3 -10
- openstackclient/tests/unit/common/test_quota.py +18 -24
- openstackclient/tests/unit/compute/v2/fakes.py +24 -11
- openstackclient/tests/unit/compute/v2/test_agent.py +1 -1
- openstackclient/tests/unit/compute/v2/test_aggregate.py +62 -72
- openstackclient/tests/unit/compute/v2/test_console.py +18 -30
- openstackclient/tests/unit/compute/v2/test_flavor.py +85 -89
- openstackclient/tests/unit/compute/v2/test_host.py +12 -19
- openstackclient/tests/unit/compute/v2/test_hypervisor.py +23 -25
- openstackclient/tests/unit/compute/v2/test_hypervisor_stats.py +2 -6
- openstackclient/tests/unit/compute/v2/test_keypair.py +25 -39
- openstackclient/tests/unit/compute/v2/test_server.py +316 -365
- openstackclient/tests/unit/compute/v2/test_server_backup.py +5 -17
- openstackclient/tests/unit/compute/v2/test_server_event.py +23 -25
- openstackclient/tests/unit/compute/v2/test_server_group.py +41 -33
- openstackclient/tests/unit/compute/v2/test_server_image.py +6 -18
- openstackclient/tests/unit/compute/v2/test_server_migration.py +45 -45
- openstackclient/tests/unit/compute/v2/test_server_volume.py +15 -31
- openstackclient/tests/unit/compute/v2/test_service.py +51 -56
- openstackclient/tests/unit/compute/v2/test_usage.py +10 -13
- openstackclient/tests/unit/fakes.py +4 -0
- openstackclient/tests/unit/identity/v3/test_mappings.py +9 -4
- openstackclient/tests/unit/identity/v3/test_trust.py +0 -2
- openstackclient/tests/unit/image/v1/fakes.py +2 -1
- openstackclient/tests/unit/image/v1/test_image.py +1 -1
- openstackclient/tests/unit/image/v2/fakes.py +82 -0
- openstackclient/tests/unit/image/v2/test_cache.py +214 -0
- openstackclient/tests/unit/image/v2/test_image.py +62 -4
- openstackclient/tests/unit/image/v2/test_metadef_namespaces.py +5 -19
- openstackclient/tests/unit/image/v2/test_metadef_objects.py +162 -0
- openstackclient/tests/unit/image/v2/test_metadef_properties.py +227 -0
- openstackclient/tests/unit/integ/cli/test_shell.py +0 -2
- openstackclient/tests/unit/network/test_common.py +3 -3
- openstackclient/tests/unit/network/v2/fakes.py +1 -0
- openstackclient/tests/unit/network/v2/test_default_security_group_rule.py +1133 -0
- openstackclient/tests/unit/network/v2/test_floating_ip_compute.py +5 -13
- openstackclient/tests/unit/network/v2/test_floating_ip_pool_compute.py +1 -9
- openstackclient/tests/unit/network/v2/test_network.py +33 -0
- openstackclient/tests/unit/network/v2/test_network_compute.py +5 -11
- openstackclient/tests/unit/network/v2/test_network_trunk.py +6 -8
- openstackclient/tests/unit/network/v2/test_port.py +83 -38
- openstackclient/tests/unit/network/v2/test_security_group_compute.py +7 -15
- openstackclient/tests/unit/network/v2/test_security_group_rule_compute.py +19 -27
- openstackclient/tests/unit/network/v2/test_security_group_rule_network.py +3 -6
- openstackclient/tests/unit/network/v2/test_subnet.py +92 -0
- openstackclient/tests/unit/network/v2/test_subnet_pool.py +11 -13
- openstackclient/tests/unit/test_shell.py +1 -7
- openstackclient/tests/unit/utils.py +10 -4
- openstackclient/tests/unit/volume/v1/fakes.py +7 -1
- openstackclient/tests/unit/volume/v1/test_qos_specs.py +2 -2
- openstackclient/tests/unit/volume/v1/test_service.py +1 -1
- openstackclient/tests/unit/volume/v1/test_transfer_request.py +2 -2
- openstackclient/tests/unit/volume/v1/test_type.py +2 -4
- openstackclient/tests/unit/volume/v1/test_volume.py +5 -7
- openstackclient/tests/unit/volume/v1/test_volume_backup.py +4 -4
- openstackclient/tests/unit/volume/v2/fakes.py +32 -12
- openstackclient/tests/unit/volume/v2/test_backup_record.py +1 -1
- openstackclient/tests/unit/volume/v2/test_consistency_group.py +4 -6
- openstackclient/tests/unit/volume/v2/test_consistency_group_snapshot.py +2 -4
- openstackclient/tests/unit/volume/v2/test_qos_specs.py +2 -2
- openstackclient/tests/unit/volume/v2/test_service.py +1 -1
- openstackclient/tests/unit/volume/v2/test_volume.py +78 -16
- openstackclient/tests/unit/volume/v2/test_volume_backend.py +10 -22
- openstackclient/tests/unit/volume/v2/test_volume_backup.py +76 -89
- openstackclient/tests/unit/volume/v2/test_volume_host.py +1 -1
- openstackclient/tests/unit/volume/v2/test_volume_snapshot.py +5 -7
- openstackclient/tests/unit/volume/v2/test_volume_transfer_request.py +4 -8
- openstackclient/tests/unit/volume/v2/test_volume_type.py +164 -24
- openstackclient/tests/unit/volume/v3/fakes.py +91 -15
- openstackclient/tests/unit/volume/v3/test_block_storage_cleanup.py +3 -7
- openstackclient/tests/unit/volume/v3/test_block_storage_cluster.py +11 -31
- openstackclient/tests/unit/volume/v3/test_block_storage_log_level.py +6 -16
- openstackclient/tests/unit/volume/v3/test_block_storage_manage.py +219 -157
- openstackclient/tests/unit/volume/v3/test_block_storage_resource_filter.py +32 -23
- openstackclient/tests/unit/volume/v3/test_volume.py +50 -48
- openstackclient/tests/unit/volume/v3/test_volume_attachment.py +17 -47
- openstackclient/tests/unit/volume/v3/test_volume_group.py +23 -65
- openstackclient/tests/unit/volume/v3/test_volume_group_snapshot.py +88 -77
- openstackclient/tests/unit/volume/v3/test_volume_group_type.py +14 -42
- openstackclient/tests/unit/volume/v3/test_volume_message.py +10 -28
- openstackclient/volume/v1/volume.py +2 -14
- openstackclient/volume/v2/volume.py +30 -15
- openstackclient/volume/v2/volume_backend.py +10 -18
- openstackclient/volume/v2/volume_backup.py +18 -15
- openstackclient/volume/v2/volume_snapshot.py +2 -12
- openstackclient/volume/v2/volume_type.py +211 -14
- openstackclient/volume/v3/block_storage_manage.py +72 -11
- openstackclient/volume/v3/block_storage_resource_filter.py +33 -11
- openstackclient/volume/v3/volume_attachment.py +2 -14
- openstackclient/volume/v3/volume_group_snapshot.py +27 -27
- openstackclient/volume/v3/volume_message.py +2 -13
- {python_openstackclient-6.3.0.dist-info → python_openstackclient-6.5.0.dist-info}/AUTHORS +11 -0
- {python_openstackclient-6.3.0.dist-info → python_openstackclient-6.5.0.dist-info}/METADATA +6 -5
- {python_openstackclient-6.3.0.dist-info → python_openstackclient-6.5.0.dist-info}/RECORD +160 -151
- {python_openstackclient-6.3.0.dist-info → python_openstackclient-6.5.0.dist-info}/entry_points.txt +23 -5
- python_openstackclient-6.5.0.dist-info/pbr.json +1 -0
- openstackclient/tests/unit/common/test_parseractions.py +0 -233
- python_openstackclient-6.3.0.dist-info/pbr.json +0 -1
- {python_openstackclient-6.3.0.dist-info → python_openstackclient-6.5.0.dist-info}/LICENSE +0 -0
- {python_openstackclient-6.3.0.dist-info → python_openstackclient-6.5.0.dist-info}/WHEEL +0 -0
- {python_openstackclient-6.3.0.dist-info → python_openstackclient-6.5.0.dist-info}/top_level.txt +0 -0
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"""Compute v2 Server operation event implementations"""
|
|
17
17
|
|
|
18
18
|
import logging
|
|
19
|
+
import uuid
|
|
19
20
|
|
|
20
21
|
from cliff import columns
|
|
21
22
|
import iso8601
|
|
@@ -24,14 +25,38 @@ from openstack import utils as sdk_utils
|
|
|
24
25
|
from osc_lib.command import command
|
|
25
26
|
from osc_lib import exceptions
|
|
26
27
|
from osc_lib import utils
|
|
27
|
-
from oslo_utils import uuidutils
|
|
28
28
|
|
|
29
|
+
from openstackclient.common import pagination
|
|
29
30
|
from openstackclient.i18n import _
|
|
30
31
|
|
|
31
|
-
|
|
32
32
|
LOG = logging.getLogger(__name__)
|
|
33
33
|
|
|
34
34
|
|
|
35
|
+
# TODO(stephenfin): Move this to osc_lib since it's useful elsewhere (e.g.
|
|
36
|
+
# glance)
|
|
37
|
+
def is_uuid_like(value) -> bool:
|
|
38
|
+
"""Returns validation of a value as a UUID.
|
|
39
|
+
|
|
40
|
+
:param val: Value to verify
|
|
41
|
+
:type val: string
|
|
42
|
+
:returns: bool
|
|
43
|
+
|
|
44
|
+
.. versionchanged:: 1.1.1
|
|
45
|
+
Support non-lowercase UUIDs.
|
|
46
|
+
"""
|
|
47
|
+
try:
|
|
48
|
+
formatted_value = (
|
|
49
|
+
value.replace('urn:', '')
|
|
50
|
+
.replace('uuid:', '')
|
|
51
|
+
.strip('{}')
|
|
52
|
+
.replace('-', '')
|
|
53
|
+
.lower()
|
|
54
|
+
)
|
|
55
|
+
return str(uuid.UUID(value)).replace('-', '') == formatted_value
|
|
56
|
+
except (TypeError, ValueError, AttributeError):
|
|
57
|
+
return False
|
|
58
|
+
|
|
59
|
+
|
|
35
60
|
class ServerActionEventColumn(columns.FormattableColumn):
|
|
36
61
|
"""Custom formatter for server action events.
|
|
37
62
|
|
|
@@ -119,21 +144,7 @@ class ListServerEvent(command.Lister):
|
|
|
119
144
|
"(supported with --os-compute-api-version 2.66 or above)"
|
|
120
145
|
),
|
|
121
146
|
)
|
|
122
|
-
|
|
123
|
-
'--marker',
|
|
124
|
-
help=_(
|
|
125
|
-
'The last server event ID of the previous page '
|
|
126
|
-
'(supported by --os-compute-api-version 2.58 or above)'
|
|
127
|
-
),
|
|
128
|
-
)
|
|
129
|
-
parser.add_argument(
|
|
130
|
-
'--limit',
|
|
131
|
-
type=int,
|
|
132
|
-
help=_(
|
|
133
|
-
'Maximum number of server events to display '
|
|
134
|
-
'(supported by --os-compute-api-version 2.58 or above)'
|
|
135
|
-
),
|
|
136
|
-
)
|
|
147
|
+
pagination.add_marker_pagination_option_to_parser(parser)
|
|
137
148
|
return parser
|
|
138
149
|
|
|
139
150
|
def take_action(self, parsed_args):
|
|
@@ -202,7 +213,7 @@ class ListServerEvent(command.Lister):
|
|
|
202
213
|
# If we fail to find the resource, it is possible the server is
|
|
203
214
|
# deleted. Try once more using the <server> arg directly if it is a
|
|
204
215
|
# UUID.
|
|
205
|
-
if
|
|
216
|
+
if is_uuid_like(parsed_args.server):
|
|
206
217
|
server_id = parsed_args.server
|
|
207
218
|
else:
|
|
208
219
|
raise
|
|
@@ -275,7 +286,7 @@ class ShowServerEvent(command.ShowOne):
|
|
|
275
286
|
# If we fail to find the resource, it is possible the server is
|
|
276
287
|
# deleted. Try once more using the <server> arg directly if it is a
|
|
277
288
|
# UUID.
|
|
278
|
-
if
|
|
289
|
+
if is_uuid_like(parsed_args.server):
|
|
279
290
|
server_id = parsed_args.server
|
|
280
291
|
else:
|
|
281
292
|
raise
|
|
@@ -24,9 +24,9 @@ from osc_lib.command import command
|
|
|
24
24
|
from osc_lib import exceptions
|
|
25
25
|
from osc_lib import utils
|
|
26
26
|
|
|
27
|
+
from openstackclient.common import pagination
|
|
27
28
|
from openstackclient.i18n import _
|
|
28
29
|
|
|
29
|
-
|
|
30
30
|
LOG = logging.getLogger(__name__)
|
|
31
31
|
|
|
32
32
|
|
|
@@ -191,28 +191,7 @@ class ListServerGroup(command.Lister):
|
|
|
191
191
|
)
|
|
192
192
|
# TODO(stephenfin): This should really be a --marker option, but alas
|
|
193
193
|
# the API doesn't support that for some reason
|
|
194
|
-
|
|
195
|
-
'--offset',
|
|
196
|
-
metavar='<offset>',
|
|
197
|
-
type=int,
|
|
198
|
-
default=None,
|
|
199
|
-
help=_(
|
|
200
|
-
'Index from which to start listing servers. This should '
|
|
201
|
-
'typically be a factor of --limit. Display all servers groups '
|
|
202
|
-
'if not specified.'
|
|
203
|
-
),
|
|
204
|
-
)
|
|
205
|
-
parser.add_argument(
|
|
206
|
-
'--limit',
|
|
207
|
-
metavar='<limit>',
|
|
208
|
-
type=int,
|
|
209
|
-
default=None,
|
|
210
|
-
help=_(
|
|
211
|
-
"Maximum number of server groups to display. "
|
|
212
|
-
"If limit is greater than 'osapi_max_limit' option of Nova "
|
|
213
|
-
"API, 'osapi_max_limit' will be used instead."
|
|
214
|
-
),
|
|
215
|
-
)
|
|
194
|
+
pagination.add_offset_pagination_option_to_parser(parser)
|
|
216
195
|
return parser
|
|
217
196
|
|
|
218
197
|
def take_action(self, parsed_args):
|
|
@@ -19,6 +19,7 @@ from osc_lib.command import command
|
|
|
19
19
|
from osc_lib import exceptions
|
|
20
20
|
from osc_lib import utils
|
|
21
21
|
|
|
22
|
+
from openstackclient.common import pagination
|
|
22
23
|
from openstackclient.i18n import _
|
|
23
24
|
from openstackclient.identity import common as identity_common
|
|
24
25
|
|
|
@@ -54,28 +55,7 @@ class ListMigration(command.Lister):
|
|
|
54
55
|
],
|
|
55
56
|
help=_('Filter migrations by type'),
|
|
56
57
|
)
|
|
57
|
-
|
|
58
|
-
'--marker',
|
|
59
|
-
metavar='<marker>',
|
|
60
|
-
help=_(
|
|
61
|
-
"The last migration of the previous page; displays list "
|
|
62
|
-
"of migrations after 'marker'. Note that the marker is "
|
|
63
|
-
"the migration UUID. "
|
|
64
|
-
"(supported with --os-compute-api-version 2.59 or above)"
|
|
65
|
-
),
|
|
66
|
-
)
|
|
67
|
-
parser.add_argument(
|
|
68
|
-
'--limit',
|
|
69
|
-
metavar='<limit>',
|
|
70
|
-
type=int,
|
|
71
|
-
help=_(
|
|
72
|
-
"Maximum number of migrations to display. Note that there "
|
|
73
|
-
"is a configurable max limit on the server, and the limit "
|
|
74
|
-
"that is used will be the minimum of what is requested "
|
|
75
|
-
"here and what is configured in the server. "
|
|
76
|
-
"(supported with --os-compute-api-version 2.59 or above)"
|
|
77
|
-
),
|
|
78
|
-
)
|
|
58
|
+
pagination.add_marker_pagination_option_to_parser(parser)
|
|
79
59
|
parser.add_argument(
|
|
80
60
|
'--changes-since',
|
|
81
61
|
dest='changes_since',
|
|
@@ -153,7 +153,6 @@ class ListUsage(command.Lister):
|
|
|
153
153
|
)
|
|
154
154
|
|
|
155
155
|
date_cli_format = "%Y-%m-%d"
|
|
156
|
-
date_api_format = "%Y-%m-%dT%H:%M:%S"
|
|
157
156
|
now = datetime.datetime.utcnow()
|
|
158
157
|
|
|
159
158
|
if parsed_args.start:
|
|
@@ -170,8 +169,8 @@ class ListUsage(command.Lister):
|
|
|
170
169
|
|
|
171
170
|
usage_list = list(
|
|
172
171
|
compute_client.usages(
|
|
173
|
-
start=start
|
|
174
|
-
end=end
|
|
172
|
+
start=start,
|
|
173
|
+
end=end,
|
|
175
174
|
detailed=True,
|
|
176
175
|
)
|
|
177
176
|
)
|
|
@@ -239,7 +238,6 @@ class ShowUsage(command.ShowOne):
|
|
|
239
238
|
identity_client = self.app.client_manager.identity
|
|
240
239
|
compute_client = self.app.client_manager.sdk_connection.compute
|
|
241
240
|
date_cli_format = "%Y-%m-%d"
|
|
242
|
-
date_api_format = "%Y-%m-%dT%H:%M:%S"
|
|
243
241
|
now = datetime.datetime.utcnow()
|
|
244
242
|
|
|
245
243
|
if parsed_args.start:
|
|
@@ -265,8 +263,8 @@ class ShowUsage(command.ShowOne):
|
|
|
265
263
|
|
|
266
264
|
usage = compute_client.get_usage(
|
|
267
265
|
project=project,
|
|
268
|
-
start=start
|
|
269
|
-
end=end
|
|
266
|
+
start=start,
|
|
267
|
+
end=end,
|
|
270
268
|
)
|
|
271
269
|
|
|
272
270
|
if parsed_args.formatter == 'table':
|
|
@@ -81,6 +81,21 @@ class _RulesReader(object):
|
|
|
81
81
|
else:
|
|
82
82
|
return rules
|
|
83
83
|
|
|
84
|
+
@staticmethod
|
|
85
|
+
def add_federated_schema_version_option(parser):
|
|
86
|
+
parser.add_argument(
|
|
87
|
+
'--schema-version',
|
|
88
|
+
metavar='<schema_version>',
|
|
89
|
+
required=False,
|
|
90
|
+
default=None,
|
|
91
|
+
help=_(
|
|
92
|
+
"The federated attribute mapping schema version. The "
|
|
93
|
+
"default value on the client side is 'None'; however, that "
|
|
94
|
+
"will lead the backend to set the default according to "
|
|
95
|
+
"'attribute_mapping_default_schema_version' option."
|
|
96
|
+
),
|
|
97
|
+
)
|
|
98
|
+
|
|
84
99
|
|
|
85
100
|
class CreateMapping(command.ShowOne, _RulesReader):
|
|
86
101
|
_description = _("Create new mapping")
|
|
@@ -98,6 +113,7 @@ class CreateMapping(command.ShowOne, _RulesReader):
|
|
|
98
113
|
required=True,
|
|
99
114
|
help=_('Filename that contains a set of mapping rules (required)'),
|
|
100
115
|
)
|
|
116
|
+
_RulesReader.add_federated_schema_version_option(parser)
|
|
101
117
|
return parser
|
|
102
118
|
|
|
103
119
|
def take_action(self, parsed_args):
|
|
@@ -105,7 +121,9 @@ class CreateMapping(command.ShowOne, _RulesReader):
|
|
|
105
121
|
|
|
106
122
|
rules = self._read_rules(parsed_args.rules)
|
|
107
123
|
mapping = identity_client.federation.mappings.create(
|
|
108
|
-
mapping_id=parsed_args.mapping,
|
|
124
|
+
mapping_id=parsed_args.mapping,
|
|
125
|
+
rules=rules,
|
|
126
|
+
schema_version=parsed_args.schema_version,
|
|
109
127
|
)
|
|
110
128
|
|
|
111
129
|
mapping._info.pop('links', None)
|
|
@@ -158,7 +176,7 @@ class ListMapping(command.Lister):
|
|
|
158
176
|
# rules, (s)he should show specific ones.
|
|
159
177
|
identity_client = self.app.client_manager.identity
|
|
160
178
|
data = identity_client.federation.mappings.list()
|
|
161
|
-
columns = ('ID',)
|
|
179
|
+
columns = ('ID', 'schema_version')
|
|
162
180
|
items = [utils.get_item_properties(s, columns) for s in data]
|
|
163
181
|
return (columns, items)
|
|
164
182
|
|
|
@@ -178,6 +196,8 @@ class SetMapping(command.Command, _RulesReader):
|
|
|
178
196
|
metavar='<filename>',
|
|
179
197
|
help=_('Filename that contains a new set of mapping rules'),
|
|
180
198
|
)
|
|
199
|
+
|
|
200
|
+
_RulesReader.add_federated_schema_version_option(parser)
|
|
181
201
|
return parser
|
|
182
202
|
|
|
183
203
|
def take_action(self, parsed_args):
|
|
@@ -186,7 +206,9 @@ class SetMapping(command.Command, _RulesReader):
|
|
|
186
206
|
rules = self._read_rules(parsed_args.rules)
|
|
187
207
|
|
|
188
208
|
mapping = identity_client.federation.mappings.update(
|
|
189
|
-
mapping=parsed_args.mapping,
|
|
209
|
+
mapping=parsed_args.mapping,
|
|
210
|
+
rules=rules,
|
|
211
|
+
schema_version=parsed_args.schema_version,
|
|
190
212
|
)
|
|
191
213
|
|
|
192
214
|
mapping._info.pop('links', None)
|
|
@@ -92,7 +92,9 @@ class DeletePolicy(command.Command):
|
|
|
92
92
|
|
|
93
93
|
if result > 0:
|
|
94
94
|
total = len(parsed_args.policy)
|
|
95
|
-
msg = _(
|
|
95
|
+
msg = _(
|
|
96
|
+
"%(result)s of %(total)s policies failed " "to delete."
|
|
97
|
+
) % {
|
|
96
98
|
'result': result,
|
|
97
99
|
'total': total,
|
|
98
100
|
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Copyright 2023 Red Hat.
|
|
2
|
+
# All Rights Reserved.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
5
|
+
# not use this file except in compliance with the License. You may obtain
|
|
6
|
+
# a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
12
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
13
|
+
# License for the specific language governing permissions and limitations
|
|
14
|
+
# under the License.
|
|
15
|
+
|
|
16
|
+
import copy
|
|
17
|
+
import datetime
|
|
18
|
+
import logging
|
|
19
|
+
|
|
20
|
+
from osc_lib.command import command
|
|
21
|
+
from osc_lib import exceptions
|
|
22
|
+
from osc_lib import utils
|
|
23
|
+
|
|
24
|
+
from openstackclient.i18n import _
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
LOG = logging.getLogger(__name__)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _format_image_cache(cached_images):
|
|
31
|
+
"""Format image cache to make it more consistent with OSC operations."""
|
|
32
|
+
|
|
33
|
+
image_list = []
|
|
34
|
+
for item in cached_images:
|
|
35
|
+
if item == "cached_images":
|
|
36
|
+
for image in cached_images[item]:
|
|
37
|
+
image_obj = copy.deepcopy(image)
|
|
38
|
+
image_obj['state'] = 'cached'
|
|
39
|
+
image_obj[
|
|
40
|
+
'last_accessed'
|
|
41
|
+
] = datetime.datetime.utcfromtimestamp(
|
|
42
|
+
image['last_accessed']
|
|
43
|
+
).isoformat()
|
|
44
|
+
image_obj[
|
|
45
|
+
'last_modified'
|
|
46
|
+
] = datetime.datetime.utcfromtimestamp(
|
|
47
|
+
image['last_modified']
|
|
48
|
+
).isoformat()
|
|
49
|
+
image_list.append(image_obj)
|
|
50
|
+
elif item == "queued_images":
|
|
51
|
+
for image in cached_images[item]:
|
|
52
|
+
image = {'image_id': image}
|
|
53
|
+
image.update(
|
|
54
|
+
{
|
|
55
|
+
'state': 'queued',
|
|
56
|
+
'last_accessed': 'N/A',
|
|
57
|
+
'last_modified': 'N/A',
|
|
58
|
+
'size': 'N/A',
|
|
59
|
+
'hits': 'N/A',
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
image_list.append(image)
|
|
63
|
+
return image_list
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class ListCachedImage(command.Lister):
|
|
67
|
+
_description = _("Get Cache State")
|
|
68
|
+
|
|
69
|
+
def get_parser(self, prog_name):
|
|
70
|
+
parser = super().get_parser(prog_name)
|
|
71
|
+
return parser
|
|
72
|
+
|
|
73
|
+
def take_action(self, parsed_args):
|
|
74
|
+
image_client = self.app.client_manager.image
|
|
75
|
+
|
|
76
|
+
# List of Cache data received
|
|
77
|
+
data = _format_image_cache(dict(image_client.get_image_cache()))
|
|
78
|
+
columns = [
|
|
79
|
+
'image_id',
|
|
80
|
+
'state',
|
|
81
|
+
'last_accessed',
|
|
82
|
+
'last_modified',
|
|
83
|
+
'size',
|
|
84
|
+
'hits',
|
|
85
|
+
]
|
|
86
|
+
column_headers = [
|
|
87
|
+
"ID",
|
|
88
|
+
"State",
|
|
89
|
+
"Last Accessed (UTC)",
|
|
90
|
+
"Last Modified (UTC)",
|
|
91
|
+
"Size",
|
|
92
|
+
"Hits",
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
column_headers,
|
|
97
|
+
(
|
|
98
|
+
utils.get_dict_properties(
|
|
99
|
+
image,
|
|
100
|
+
columns,
|
|
101
|
+
)
|
|
102
|
+
for image in data
|
|
103
|
+
),
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class QueueCachedImage(command.Command):
|
|
108
|
+
_description = _("Queue image(s) for caching.")
|
|
109
|
+
|
|
110
|
+
def get_parser(self, prog_name):
|
|
111
|
+
parser = super().get_parser(prog_name)
|
|
112
|
+
parser.add_argument(
|
|
113
|
+
"images",
|
|
114
|
+
metavar="<image>",
|
|
115
|
+
nargs="+",
|
|
116
|
+
help=_("Image to display (name or ID)"),
|
|
117
|
+
)
|
|
118
|
+
return parser
|
|
119
|
+
|
|
120
|
+
def take_action(self, parsed_args):
|
|
121
|
+
image_client = self.app.client_manager.image
|
|
122
|
+
|
|
123
|
+
failures = 0
|
|
124
|
+
for image in parsed_args.images:
|
|
125
|
+
try:
|
|
126
|
+
image_obj = image_client.find_image(
|
|
127
|
+
image,
|
|
128
|
+
ignore_missing=False,
|
|
129
|
+
)
|
|
130
|
+
image_client.queue_image(image_obj.id)
|
|
131
|
+
except Exception as e:
|
|
132
|
+
failures += 1
|
|
133
|
+
msg = _(
|
|
134
|
+
"Failed to queue image with name or "
|
|
135
|
+
"ID '%(image)s': %(e)s"
|
|
136
|
+
)
|
|
137
|
+
LOG.error(msg, {'image': image, 'e': e})
|
|
138
|
+
|
|
139
|
+
if failures > 0:
|
|
140
|
+
total = len(parsed_args.images)
|
|
141
|
+
msg = _("Failed to queue %(failures)s of %(total)s images") % {
|
|
142
|
+
'failures': failures,
|
|
143
|
+
'total': total,
|
|
144
|
+
}
|
|
145
|
+
raise exceptions.CommandError(msg)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class DeleteCachedImage(command.Command):
|
|
149
|
+
_description = _("Delete image(s) from cache")
|
|
150
|
+
|
|
151
|
+
def get_parser(self, prog_name):
|
|
152
|
+
parser = super().get_parser(prog_name)
|
|
153
|
+
parser.add_argument(
|
|
154
|
+
"images",
|
|
155
|
+
metavar="<image>",
|
|
156
|
+
nargs="+",
|
|
157
|
+
help=_("Image(s) to delete (name or ID)"),
|
|
158
|
+
)
|
|
159
|
+
return parser
|
|
160
|
+
|
|
161
|
+
def take_action(self, parsed_args):
|
|
162
|
+
failures = 0
|
|
163
|
+
image_client = self.app.client_manager.image
|
|
164
|
+
for image in parsed_args.images:
|
|
165
|
+
try:
|
|
166
|
+
image_obj = image_client.find_image(
|
|
167
|
+
image,
|
|
168
|
+
ignore_missing=False,
|
|
169
|
+
)
|
|
170
|
+
image_client.cache_delete_image(image_obj.id)
|
|
171
|
+
except Exception as e:
|
|
172
|
+
failures += 1
|
|
173
|
+
msg = _(
|
|
174
|
+
"Failed to delete image with name or "
|
|
175
|
+
"ID '%(image)s': %(e)s"
|
|
176
|
+
)
|
|
177
|
+
LOG.error(msg, {'image': image, 'e': e})
|
|
178
|
+
|
|
179
|
+
if failures > 0:
|
|
180
|
+
total = len(parsed_args.images)
|
|
181
|
+
msg = _("Failed to delete %(failures)s of %(total)s images.") % {
|
|
182
|
+
'failures': failures,
|
|
183
|
+
'total': total,
|
|
184
|
+
}
|
|
185
|
+
raise exceptions.CommandError(msg)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class ClearCachedImage(command.Command):
|
|
189
|
+
_description = _("Clear all images from cache, queue or both")
|
|
190
|
+
|
|
191
|
+
def get_parser(self, prog_name):
|
|
192
|
+
parser = super().get_parser(prog_name)
|
|
193
|
+
parser.add_argument(
|
|
194
|
+
"--cache",
|
|
195
|
+
action="store_const",
|
|
196
|
+
const="cache",
|
|
197
|
+
dest="target",
|
|
198
|
+
help=_("Clears all the cached images"),
|
|
199
|
+
)
|
|
200
|
+
parser.add_argument(
|
|
201
|
+
"--queue",
|
|
202
|
+
action="store_const",
|
|
203
|
+
const="queue",
|
|
204
|
+
dest="target",
|
|
205
|
+
help=_("Clears all the queued images"),
|
|
206
|
+
)
|
|
207
|
+
return parser
|
|
208
|
+
|
|
209
|
+
def take_action(self, parsed_args):
|
|
210
|
+
image_client = self.app.client_manager.image
|
|
211
|
+
|
|
212
|
+
target = parsed_args.target
|
|
213
|
+
try:
|
|
214
|
+
image_client.clear_cache(target)
|
|
215
|
+
except Exception:
|
|
216
|
+
msg = _("Failed to clear image cache")
|
|
217
|
+
LOG.error(msg)
|
|
218
|
+
raise exceptions.CommandError(msg)
|
|
@@ -31,6 +31,7 @@ from osc_lib.command import command
|
|
|
31
31
|
from osc_lib import exceptions
|
|
32
32
|
from osc_lib import utils
|
|
33
33
|
|
|
34
|
+
from openstackclient.common import pagination
|
|
34
35
|
from openstackclient.common import progressbar
|
|
35
36
|
from openstackclient.i18n import _
|
|
36
37
|
from openstackclient.identity import common as identity_common
|
|
@@ -805,9 +806,9 @@ class ListImage(command.Lister):
|
|
|
805
806
|
default=False,
|
|
806
807
|
help=_('List additional fields in output'),
|
|
807
808
|
)
|
|
808
|
-
|
|
809
809
|
# --page-size has never worked, leave here for silent compatibility
|
|
810
810
|
# We'll implement limit/marker differently later
|
|
811
|
+
# TODO(stephenfin): Remove this in the next major version bump
|
|
811
812
|
parser.add_argument(
|
|
812
813
|
"--page-size",
|
|
813
814
|
metavar="<size>",
|
|
@@ -823,22 +824,7 @@ class ListImage(command.Lister):
|
|
|
823
824
|
"specified separated by comma"
|
|
824
825
|
),
|
|
825
826
|
)
|
|
826
|
-
|
|
827
|
-
"--limit",
|
|
828
|
-
metavar="<num-images>",
|
|
829
|
-
type=int,
|
|
830
|
-
help=_("Maximum number of images to display."),
|
|
831
|
-
)
|
|
832
|
-
parser.add_argument(
|
|
833
|
-
'--marker',
|
|
834
|
-
metavar='<image>',
|
|
835
|
-
default=None,
|
|
836
|
-
help=_(
|
|
837
|
-
"The last image of the previous page. Display "
|
|
838
|
-
"list of images after marker. Display all images if not "
|
|
839
|
-
"specified. (name or ID)"
|
|
840
|
-
),
|
|
841
|
-
)
|
|
827
|
+
pagination.add_marker_pagination_option_to_parser(parser)
|
|
842
828
|
return parser
|
|
843
829
|
|
|
844
830
|
def take_action(self, parsed_args):
|
|
@@ -1006,6 +992,43 @@ class RemoveProjectImage(command.Command):
|
|
|
1006
992
|
image_client.remove_member(member=project_id, image=image.id)
|
|
1007
993
|
|
|
1008
994
|
|
|
995
|
+
class ShowProjectImage(command.ShowOne):
|
|
996
|
+
_description = _("Show a particular project associated with image")
|
|
997
|
+
|
|
998
|
+
def get_parser(self, prog_name):
|
|
999
|
+
parser = super().get_parser(prog_name)
|
|
1000
|
+
parser.add_argument(
|
|
1001
|
+
"image",
|
|
1002
|
+
metavar="<image>",
|
|
1003
|
+
help=_("Image (name or ID)"),
|
|
1004
|
+
)
|
|
1005
|
+
parser.add_argument(
|
|
1006
|
+
"member",
|
|
1007
|
+
metavar="<project>",
|
|
1008
|
+
help=_("Project to show (name or ID)"),
|
|
1009
|
+
)
|
|
1010
|
+
identity_common.add_project_domain_option_to_parser(parser)
|
|
1011
|
+
return parser
|
|
1012
|
+
|
|
1013
|
+
def take_action(self, parsed_args):
|
|
1014
|
+
image_client = self.app.client_manager.image
|
|
1015
|
+
|
|
1016
|
+
image = image_client.find_image(
|
|
1017
|
+
parsed_args.image,
|
|
1018
|
+
ignore_missing=False,
|
|
1019
|
+
)
|
|
1020
|
+
|
|
1021
|
+
obj = image_client.get_member(
|
|
1022
|
+
image=image.id,
|
|
1023
|
+
member=parsed_args.member,
|
|
1024
|
+
)
|
|
1025
|
+
|
|
1026
|
+
display_columns, columns = _get_member_columns(obj)
|
|
1027
|
+
data = utils.get_item_properties(obj, columns, formatters={})
|
|
1028
|
+
|
|
1029
|
+
return (display_columns, data)
|
|
1030
|
+
|
|
1031
|
+
|
|
1009
1032
|
class SaveImage(command.Command):
|
|
1010
1033
|
_description = _("Save an image locally")
|
|
1011
1034
|
|