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
|
@@ -42,6 +42,7 @@ def _format_namespace(namespace):
|
|
|
42
42
|
'owner',
|
|
43
43
|
'protected',
|
|
44
44
|
'schema',
|
|
45
|
+
'updated_at',
|
|
45
46
|
'visibility',
|
|
46
47
|
]
|
|
47
48
|
|
|
@@ -61,7 +62,7 @@ def _format_namespace(namespace):
|
|
|
61
62
|
return info
|
|
62
63
|
|
|
63
64
|
|
|
64
|
-
class
|
|
65
|
+
class CreateMetadefNamespace(command.ShowOne):
|
|
65
66
|
_description = _("Create a metadef namespace")
|
|
66
67
|
|
|
67
68
|
def get_parser(self, prog_name):
|
|
@@ -130,20 +131,21 @@ class CreateMetadefNameSpace(command.ShowOne):
|
|
|
130
131
|
kwargs['visibility'] = parsed_args.visibility
|
|
131
132
|
|
|
132
133
|
data = image_client.create_metadef_namespace(**kwargs)
|
|
134
|
+
info = _format_namespace(data)
|
|
133
135
|
|
|
134
|
-
return zip(*sorted(
|
|
136
|
+
return zip(*sorted(info.items()))
|
|
135
137
|
|
|
136
138
|
|
|
137
|
-
class
|
|
139
|
+
class DeleteMetadefNamespace(command.Command):
|
|
138
140
|
_description = _("Delete metadef namespace")
|
|
139
141
|
|
|
140
142
|
def get_parser(self, prog_name):
|
|
141
143
|
parser = super().get_parser(prog_name)
|
|
142
144
|
parser.add_argument(
|
|
143
|
-
"
|
|
144
|
-
metavar="<
|
|
145
|
+
"namespace",
|
|
146
|
+
metavar="<namespace>",
|
|
145
147
|
nargs="+",
|
|
146
|
-
help=_("
|
|
148
|
+
help=_("Metadef namespace(s) to delete (name)"),
|
|
147
149
|
)
|
|
148
150
|
return parser
|
|
149
151
|
|
|
@@ -151,9 +153,9 @@ class DeleteMetadefNameSpace(command.Command):
|
|
|
151
153
|
image_client = self.app.client_manager.image
|
|
152
154
|
|
|
153
155
|
result = 0
|
|
154
|
-
for
|
|
156
|
+
for ns in parsed_args.namespace:
|
|
155
157
|
try:
|
|
156
|
-
namespace = image_client.get_metadef_namespace(
|
|
158
|
+
namespace = image_client.get_metadef_namespace(ns)
|
|
157
159
|
image_client.delete_metadef_namespace(namespace.id)
|
|
158
160
|
except Exception as e:
|
|
159
161
|
result += 1
|
|
@@ -162,18 +164,18 @@ class DeleteMetadefNameSpace(command.Command):
|
|
|
162
164
|
"Failed to delete namespace with name or "
|
|
163
165
|
"ID '%(namespace)s': %(e)s"
|
|
164
166
|
),
|
|
165
|
-
{'namespace':
|
|
167
|
+
{'namespace': ns, 'e': e},
|
|
166
168
|
)
|
|
167
169
|
|
|
168
170
|
if result > 0:
|
|
169
|
-
total = len(parsed_args.
|
|
171
|
+
total = len(parsed_args.namespace)
|
|
170
172
|
msg = _(
|
|
171
173
|
"%(result)s of %(total)s namespace failed " "to delete."
|
|
172
174
|
) % {'result': result, 'total': total}
|
|
173
175
|
raise exceptions.CommandError(msg)
|
|
174
176
|
|
|
175
177
|
|
|
176
|
-
class
|
|
178
|
+
class ListMetadefNamespace(command.Lister):
|
|
177
179
|
_description = _("List metadef namespaces")
|
|
178
180
|
|
|
179
181
|
def get_parser(self, prog_name):
|
|
@@ -215,7 +217,7 @@ class ListMetadefNameSpaces(command.Lister):
|
|
|
215
217
|
)
|
|
216
218
|
|
|
217
219
|
|
|
218
|
-
class
|
|
220
|
+
class SetMetadefNamespace(command.Command):
|
|
219
221
|
_description = _("Set metadef namespace properties")
|
|
220
222
|
|
|
221
223
|
def get_parser(self, prog_name):
|
|
@@ -223,7 +225,7 @@ class SetMetadefNameSpace(command.Command):
|
|
|
223
225
|
parser.add_argument(
|
|
224
226
|
"namespace",
|
|
225
227
|
metavar="<namespace>",
|
|
226
|
-
help=_("
|
|
228
|
+
help=_("Metadef namespace to modify (name)"),
|
|
227
229
|
)
|
|
228
230
|
parser.add_argument(
|
|
229
231
|
"--display-name",
|
|
@@ -241,14 +243,16 @@ class SetMetadefNameSpace(command.Command):
|
|
|
241
243
|
action="store_const",
|
|
242
244
|
const="public",
|
|
243
245
|
dest="visibility",
|
|
244
|
-
help=_("
|
|
246
|
+
help=_("Metadef namespace is accessible to the public"),
|
|
245
247
|
)
|
|
246
248
|
visibility_group.add_argument(
|
|
247
249
|
"--private",
|
|
248
250
|
action="store_const",
|
|
249
251
|
const="private",
|
|
250
252
|
dest="visibility",
|
|
251
|
-
help=_(
|
|
253
|
+
help=_(
|
|
254
|
+
"Metadef namespace is inaccessible to the public (default)"
|
|
255
|
+
),
|
|
252
256
|
)
|
|
253
257
|
protected_group = parser.add_mutually_exclusive_group()
|
|
254
258
|
protected_group.add_argument(
|
|
@@ -289,24 +293,24 @@ class SetMetadefNameSpace(command.Command):
|
|
|
289
293
|
image_client.update_metadef_namespace(namespace, **kwargs)
|
|
290
294
|
|
|
291
295
|
|
|
292
|
-
class
|
|
296
|
+
class ShowMetadefNamespace(command.ShowOne):
|
|
293
297
|
_description = _("Show a metadef namespace")
|
|
294
298
|
|
|
295
299
|
def get_parser(self, prog_name):
|
|
296
300
|
parser = super().get_parser(prog_name)
|
|
297
301
|
parser.add_argument(
|
|
298
|
-
"
|
|
299
|
-
metavar="<
|
|
300
|
-
help=_("
|
|
302
|
+
"namespace",
|
|
303
|
+
metavar="<namespace>",
|
|
304
|
+
help=_("Metadef namespace to show (name)"),
|
|
301
305
|
)
|
|
302
306
|
return parser
|
|
303
307
|
|
|
304
308
|
def take_action(self, parsed_args):
|
|
305
309
|
image_client = self.app.client_manager.image
|
|
306
310
|
|
|
307
|
-
|
|
311
|
+
namespace = parsed_args.namespace
|
|
308
312
|
|
|
309
|
-
data = image_client.get_metadef_namespace(
|
|
313
|
+
data = image_client.get_metadef_namespace(namespace)
|
|
310
314
|
info = _format_namespace(data)
|
|
311
315
|
|
|
312
316
|
return zip(*sorted(info.items()))
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# Copyright 2023 Red Hat
|
|
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
|
+
|
|
16
|
+
"""Image V2 Action Implementations"""
|
|
17
|
+
|
|
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_object(md_object):
|
|
31
|
+
fields_to_show = (
|
|
32
|
+
'created_at',
|
|
33
|
+
'description',
|
|
34
|
+
'name',
|
|
35
|
+
'namespace_name',
|
|
36
|
+
'properties',
|
|
37
|
+
'required',
|
|
38
|
+
'updated_at',
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
fields_to_show,
|
|
43
|
+
utils.get_item_properties(
|
|
44
|
+
md_object,
|
|
45
|
+
fields_to_show,
|
|
46
|
+
),
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class CreateMetadefObjects(command.ShowOne):
|
|
51
|
+
_description = _("Create a metadef object")
|
|
52
|
+
|
|
53
|
+
def get_parser(self, prog_name):
|
|
54
|
+
parser = super().get_parser(prog_name)
|
|
55
|
+
parser.add_argument(
|
|
56
|
+
"--namespace",
|
|
57
|
+
metavar="<namespace>",
|
|
58
|
+
help=_("Metadef namespace to create the object in (name)"),
|
|
59
|
+
)
|
|
60
|
+
parser.add_argument(
|
|
61
|
+
"name",
|
|
62
|
+
metavar='<metadef-object-name>',
|
|
63
|
+
help=_('New metadef object name'),
|
|
64
|
+
)
|
|
65
|
+
return parser
|
|
66
|
+
|
|
67
|
+
def take_action(self, parsed_args):
|
|
68
|
+
image_client = self.app.client_manager.image
|
|
69
|
+
|
|
70
|
+
namespace = image_client.get_metadef_namespace(
|
|
71
|
+
parsed_args.namespace,
|
|
72
|
+
)
|
|
73
|
+
data = image_client.create_metadef_object(
|
|
74
|
+
namespace=namespace.namespace,
|
|
75
|
+
name=parsed_args.name,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
fields, value = _format_object(data)
|
|
79
|
+
|
|
80
|
+
return fields, value
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class ShowMetadefObjects(command.ShowOne):
|
|
84
|
+
_description = _("Show a particular metadef object")
|
|
85
|
+
|
|
86
|
+
def get_parser(self, prog_name):
|
|
87
|
+
parser = super().get_parser(prog_name)
|
|
88
|
+
parser.add_argument(
|
|
89
|
+
"namespace",
|
|
90
|
+
metavar="<namespace>",
|
|
91
|
+
help=_("Metadef namespace of the object (name)"),
|
|
92
|
+
)
|
|
93
|
+
parser.add_argument(
|
|
94
|
+
"object",
|
|
95
|
+
metavar="<object>",
|
|
96
|
+
help=_("Metadef object to show"),
|
|
97
|
+
)
|
|
98
|
+
return parser
|
|
99
|
+
|
|
100
|
+
def take_action(self, parsed_args):
|
|
101
|
+
image_client = self.app.client_manager.image
|
|
102
|
+
|
|
103
|
+
namespace = parsed_args.namespace
|
|
104
|
+
object = parsed_args.object
|
|
105
|
+
|
|
106
|
+
data = image_client.get_metadef_object(object, namespace)
|
|
107
|
+
|
|
108
|
+
fields, value = _format_object(data)
|
|
109
|
+
|
|
110
|
+
return fields, value
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class DeleteMetadefObject(command.Command):
|
|
114
|
+
_description = _("Delete metadata definitions object(s)")
|
|
115
|
+
|
|
116
|
+
def get_parser(self, prog_name):
|
|
117
|
+
parser = super().get_parser(prog_name)
|
|
118
|
+
parser.add_argument(
|
|
119
|
+
"namespace",
|
|
120
|
+
metavar="<namespace>",
|
|
121
|
+
help=_("Metadef namespace of the object (name)"),
|
|
122
|
+
)
|
|
123
|
+
parser.add_argument(
|
|
124
|
+
"objects",
|
|
125
|
+
metavar="<object>",
|
|
126
|
+
nargs="+",
|
|
127
|
+
help=_("Metadef object(s) to delete (name)"),
|
|
128
|
+
)
|
|
129
|
+
return parser
|
|
130
|
+
|
|
131
|
+
def take_action(self, parsed_args):
|
|
132
|
+
image_client = self.app.client_manager.image
|
|
133
|
+
|
|
134
|
+
namespace = parsed_args.namespace
|
|
135
|
+
|
|
136
|
+
result = 0
|
|
137
|
+
for obj in parsed_args.objects:
|
|
138
|
+
try:
|
|
139
|
+
object = image_client.get_metadef_object(obj, namespace)
|
|
140
|
+
image_client.delete_metadef_object(object, namespace)
|
|
141
|
+
except Exception as e:
|
|
142
|
+
result += 1
|
|
143
|
+
LOG.error(
|
|
144
|
+
_(
|
|
145
|
+
"Failed to delete object with name or "
|
|
146
|
+
"ID '%(object)s': %(e)s"
|
|
147
|
+
),
|
|
148
|
+
{'object': obj, 'e': e},
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
if result > 0:
|
|
152
|
+
total = len(parsed_args.namespace)
|
|
153
|
+
msg = _("%(result)s of %(total)s object failed to delete.") % {
|
|
154
|
+
'result': result,
|
|
155
|
+
'total': total,
|
|
156
|
+
}
|
|
157
|
+
raise exceptions.CommandError(msg)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
class ListMetadefObjects(command.Lister):
|
|
161
|
+
_description = _("List metadef objects inside a specific namespace.")
|
|
162
|
+
|
|
163
|
+
def get_parser(self, prog_name):
|
|
164
|
+
parser = super().get_parser(prog_name)
|
|
165
|
+
parser.add_argument(
|
|
166
|
+
"namespace",
|
|
167
|
+
metavar="<namespace>",
|
|
168
|
+
help=_("Namespace (name) for the namespace"),
|
|
169
|
+
)
|
|
170
|
+
return parser
|
|
171
|
+
|
|
172
|
+
def take_action(self, parsed_args):
|
|
173
|
+
image_client = self.app.client_manager.image
|
|
174
|
+
|
|
175
|
+
namespace = parsed_args.namespace
|
|
176
|
+
columns = ['name', 'description']
|
|
177
|
+
|
|
178
|
+
md_objects = list(image_client.metadef_objects(namespace))
|
|
179
|
+
column_headers = columns
|
|
180
|
+
return (
|
|
181
|
+
column_headers,
|
|
182
|
+
(
|
|
183
|
+
utils.get_item_properties(
|
|
184
|
+
md_object,
|
|
185
|
+
columns,
|
|
186
|
+
)
|
|
187
|
+
for md_object in md_objects
|
|
188
|
+
),
|
|
189
|
+
)
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
# Copyright 2023 Red Hat, Inc.
|
|
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 json
|
|
16
|
+
import logging
|
|
17
|
+
|
|
18
|
+
from osc_lib.command import command
|
|
19
|
+
from osc_lib import exceptions
|
|
20
|
+
from osc_lib import utils
|
|
21
|
+
|
|
22
|
+
from openstackclient.i18n import _
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
LOG = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _format_property(prop):
|
|
29
|
+
prop = prop.to_dict(ignore_none=True, original_names=True)
|
|
30
|
+
return {
|
|
31
|
+
key: prop[key]
|
|
32
|
+
for key in [
|
|
33
|
+
'namespace_name',
|
|
34
|
+
'name',
|
|
35
|
+
'type',
|
|
36
|
+
'title',
|
|
37
|
+
'description',
|
|
38
|
+
'operators',
|
|
39
|
+
'default',
|
|
40
|
+
'is_readonly',
|
|
41
|
+
'minimum',
|
|
42
|
+
'maximum',
|
|
43
|
+
'enum',
|
|
44
|
+
'pattern',
|
|
45
|
+
'min_length',
|
|
46
|
+
'max_length',
|
|
47
|
+
'items',
|
|
48
|
+
'require_unique_items',
|
|
49
|
+
'min_items',
|
|
50
|
+
'max_items',
|
|
51
|
+
'allow_additional_items',
|
|
52
|
+
]
|
|
53
|
+
if key in prop
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class CreateMetadefProperty(command.ShowOne):
|
|
58
|
+
_description = _("Create a metadef property")
|
|
59
|
+
|
|
60
|
+
def get_parser(self, prog_name):
|
|
61
|
+
parser = super().get_parser(prog_name)
|
|
62
|
+
parser.add_argument(
|
|
63
|
+
"--name",
|
|
64
|
+
required=True,
|
|
65
|
+
help=_("Internal name of the property"),
|
|
66
|
+
)
|
|
67
|
+
parser.add_argument(
|
|
68
|
+
"--title",
|
|
69
|
+
required=True,
|
|
70
|
+
help=_("Property name displayed to the user"),
|
|
71
|
+
)
|
|
72
|
+
parser.add_argument(
|
|
73
|
+
"--type",
|
|
74
|
+
required=True,
|
|
75
|
+
help=_("Property type"),
|
|
76
|
+
)
|
|
77
|
+
parser.add_argument(
|
|
78
|
+
"--schema",
|
|
79
|
+
required=True,
|
|
80
|
+
help=_("Valid JSON schema of the property"),
|
|
81
|
+
)
|
|
82
|
+
parser.add_argument(
|
|
83
|
+
"namespace",
|
|
84
|
+
help=_("Name of namespace the property will belong."),
|
|
85
|
+
)
|
|
86
|
+
return parser
|
|
87
|
+
|
|
88
|
+
def take_action(self, parsed_args):
|
|
89
|
+
image_client = self.app.client_manager.image
|
|
90
|
+
|
|
91
|
+
kwargs = {
|
|
92
|
+
'name': parsed_args.name,
|
|
93
|
+
'title': parsed_args.title,
|
|
94
|
+
'type': parsed_args.type,
|
|
95
|
+
}
|
|
96
|
+
try:
|
|
97
|
+
kwargs.update(json.loads(parsed_args.schema))
|
|
98
|
+
except json.JSONDecodeError as e:
|
|
99
|
+
raise exceptions.CommandError(
|
|
100
|
+
_("Failed to load JSON schema: %(e)s")
|
|
101
|
+
% {
|
|
102
|
+
'e': e,
|
|
103
|
+
}
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
data = image_client.create_metadef_property(
|
|
107
|
+
parsed_args.namespace, **kwargs
|
|
108
|
+
)
|
|
109
|
+
info = _format_property(data)
|
|
110
|
+
|
|
111
|
+
return zip(*sorted(info.items()))
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class DeleteMetadefProperty(command.Command):
|
|
115
|
+
_description = _("Delete metadef propert(ies)")
|
|
116
|
+
|
|
117
|
+
def get_parser(self, prog_name):
|
|
118
|
+
parser = super().get_parser(prog_name)
|
|
119
|
+
parser.add_argument(
|
|
120
|
+
"namespace",
|
|
121
|
+
metavar="<namespace>",
|
|
122
|
+
help=_("Metadef namespace of the property (name)"),
|
|
123
|
+
)
|
|
124
|
+
parser.add_argument(
|
|
125
|
+
"properties",
|
|
126
|
+
metavar="<property>",
|
|
127
|
+
nargs="+",
|
|
128
|
+
help=_("Metadef propert(ies) to delete (name)"),
|
|
129
|
+
)
|
|
130
|
+
return parser
|
|
131
|
+
|
|
132
|
+
def take_action(self, parsed_args):
|
|
133
|
+
image_client = self.app.client_manager.image
|
|
134
|
+
|
|
135
|
+
result = 0
|
|
136
|
+
for prop in parsed_args.properties:
|
|
137
|
+
try:
|
|
138
|
+
image_client.delete_metadef_property(
|
|
139
|
+
prop,
|
|
140
|
+
parsed_args.namespace,
|
|
141
|
+
ignore_missing=False,
|
|
142
|
+
)
|
|
143
|
+
except Exception as e:
|
|
144
|
+
result += 1
|
|
145
|
+
LOG.error(
|
|
146
|
+
_(
|
|
147
|
+
"Failed to delete property with name or ID "
|
|
148
|
+
"'%(property)s' from namespace '%(namespace)s': %(e)s"
|
|
149
|
+
),
|
|
150
|
+
{
|
|
151
|
+
'property': prop,
|
|
152
|
+
'namespace': parsed_args.namespace,
|
|
153
|
+
'e': e,
|
|
154
|
+
},
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
if result > 0:
|
|
158
|
+
total = len(parsed_args.namespace)
|
|
159
|
+
msg = _("%(result)s of %(total)s properties failed to delete.") % {
|
|
160
|
+
'result': result,
|
|
161
|
+
'total': total,
|
|
162
|
+
}
|
|
163
|
+
raise exceptions.CommandError(msg)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class ListMetadefProperties(command.Lister):
|
|
167
|
+
_description = _("List metadef properties")
|
|
168
|
+
|
|
169
|
+
def get_parser(self, prog_name):
|
|
170
|
+
parser = super().get_parser(prog_name)
|
|
171
|
+
parser.add_argument(
|
|
172
|
+
"namespace",
|
|
173
|
+
metavar="<namespace>",
|
|
174
|
+
help=_("An identifier (a name) for the namespace"),
|
|
175
|
+
)
|
|
176
|
+
return parser
|
|
177
|
+
|
|
178
|
+
def take_action(self, parsed_args):
|
|
179
|
+
image_client = self.app.client_manager.image
|
|
180
|
+
props = image_client.metadef_properties(parsed_args.namespace)
|
|
181
|
+
columns = ['name', 'title', 'type']
|
|
182
|
+
return (
|
|
183
|
+
columns,
|
|
184
|
+
(
|
|
185
|
+
utils.get_item_properties(
|
|
186
|
+
prop,
|
|
187
|
+
columns,
|
|
188
|
+
)
|
|
189
|
+
for prop in props
|
|
190
|
+
),
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class SetMetadefProperty(command.Command):
|
|
195
|
+
_description = _("Update metadef namespace property")
|
|
196
|
+
|
|
197
|
+
def get_parser(self, prog_name):
|
|
198
|
+
parser = super().get_parser(prog_name)
|
|
199
|
+
parser.add_argument(
|
|
200
|
+
"--name",
|
|
201
|
+
help=_("Internal name of the property"),
|
|
202
|
+
)
|
|
203
|
+
parser.add_argument(
|
|
204
|
+
"--title",
|
|
205
|
+
help=_("Property name displayed to the user"),
|
|
206
|
+
)
|
|
207
|
+
parser.add_argument(
|
|
208
|
+
"--type",
|
|
209
|
+
help=_("Property type"),
|
|
210
|
+
)
|
|
211
|
+
parser.add_argument(
|
|
212
|
+
"--schema",
|
|
213
|
+
help=_("Valid JSON schema of the property"),
|
|
214
|
+
)
|
|
215
|
+
parser.add_argument(
|
|
216
|
+
"namespace",
|
|
217
|
+
help=_("Namespace of the namespace to which the property belongs"),
|
|
218
|
+
)
|
|
219
|
+
parser.add_argument(
|
|
220
|
+
"property",
|
|
221
|
+
help=_("Property to update"),
|
|
222
|
+
)
|
|
223
|
+
return parser
|
|
224
|
+
|
|
225
|
+
def take_action(self, parsed_args):
|
|
226
|
+
image_client = self.app.client_manager.image
|
|
227
|
+
|
|
228
|
+
# We need to pass the values for *all* attributes as kwargs to
|
|
229
|
+
# update_metadef_property(), otherwise the attributes that are not
|
|
230
|
+
# listed will be reset.
|
|
231
|
+
data = image_client.get_metadef_property(
|
|
232
|
+
parsed_args.property,
|
|
233
|
+
parsed_args.namespace,
|
|
234
|
+
)
|
|
235
|
+
kwargs = _format_property(data)
|
|
236
|
+
for key in ['name', 'title', 'type']:
|
|
237
|
+
argument = getattr(parsed_args, key, None)
|
|
238
|
+
if argument is not None:
|
|
239
|
+
kwargs[key] = argument
|
|
240
|
+
|
|
241
|
+
if parsed_args.schema:
|
|
242
|
+
try:
|
|
243
|
+
kwargs.update(json.loads(parsed_args.schema))
|
|
244
|
+
except json.JSONDecodeError as e:
|
|
245
|
+
raise exceptions.CommandError(
|
|
246
|
+
_("Failed to load JSON schema: %(e)s")
|
|
247
|
+
% {
|
|
248
|
+
'e': e,
|
|
249
|
+
}
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
image_client.update_metadef_property(
|
|
253
|
+
parsed_args.property,
|
|
254
|
+
parsed_args.namespace,
|
|
255
|
+
**kwargs,
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
class ShowMetadefProperty(command.ShowOne):
|
|
260
|
+
_description = _("Show a particular metadef property")
|
|
261
|
+
|
|
262
|
+
def get_parser(self, prog_name):
|
|
263
|
+
parser = super().get_parser(prog_name)
|
|
264
|
+
parser.add_argument(
|
|
265
|
+
"namespace",
|
|
266
|
+
metavar="<namespace>",
|
|
267
|
+
help=_("Metadef namespace of the property (name)"),
|
|
268
|
+
)
|
|
269
|
+
parser.add_argument(
|
|
270
|
+
"property",
|
|
271
|
+
metavar="<property>",
|
|
272
|
+
help=_("Property to show"),
|
|
273
|
+
)
|
|
274
|
+
return parser
|
|
275
|
+
|
|
276
|
+
def take_action(self, parsed_args):
|
|
277
|
+
image_client = self.app.client_manager.image
|
|
278
|
+
data = image_client.get_metadef_property(
|
|
279
|
+
parsed_args.property,
|
|
280
|
+
parsed_args.namespace,
|
|
281
|
+
)
|
|
282
|
+
info = _format_property(data)
|
|
283
|
+
|
|
284
|
+
return zip(*sorted(info.items()))
|