python-openstackclient 8.2.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.
- openstackclient/api/object_store_v1.py +4 -1
- openstackclient/command.py +27 -0
- openstackclient/common/availability_zone.py +1 -1
- openstackclient/common/clientmanager.py +59 -21
- openstackclient/common/configuration.py +1 -1
- openstackclient/common/extension.py +1 -1
- openstackclient/common/limits.py +1 -1
- openstackclient/common/module.py +4 -2
- openstackclient/common/project_cleanup.py +10 -8
- openstackclient/common/quota.py +23 -6
- openstackclient/common/versions.py +1 -2
- openstackclient/compute/v2/agent.py +1 -1
- openstackclient/compute/v2/aggregate.py +6 -5
- openstackclient/compute/v2/console.py +5 -3
- openstackclient/compute/v2/console_connection.py +1 -1
- openstackclient/compute/v2/flavor.py +1 -1
- openstackclient/compute/v2/host.py +1 -1
- openstackclient/compute/v2/hypervisor.py +1 -1
- openstackclient/compute/v2/hypervisor_stats.py +1 -1
- openstackclient/compute/v2/keypair.py +1 -1
- openstackclient/compute/v2/server.py +76 -27
- openstackclient/compute/v2/server_backup.py +1 -1
- openstackclient/compute/v2/server_event.py +1 -1
- openstackclient/compute/v2/server_group.py +4 -2
- openstackclient/compute/v2/server_image.py +1 -1
- openstackclient/compute/v2/server_migration.py +1 -1
- openstackclient/compute/v2/server_volume.py +1 -1
- openstackclient/compute/v2/service.py +1 -1
- openstackclient/compute/v2/usage.py +6 -4
- openstackclient/identity/common.py +2 -1
- openstackclient/identity/v2_0/catalog.py +3 -2
- openstackclient/identity/v2_0/ec2creds.py +1 -1
- openstackclient/identity/v2_0/endpoint.py +1 -1
- openstackclient/identity/v2_0/project.py +17 -7
- openstackclient/identity/v2_0/role.py +1 -1
- openstackclient/identity/v2_0/role_assignment.py +3 -3
- openstackclient/identity/v2_0/service.py +1 -1
- openstackclient/identity/v2_0/token.py +1 -1
- openstackclient/identity/v2_0/user.py +2 -2
- openstackclient/identity/v3/access_rule.py +16 -4
- openstackclient/identity/v3/application_credential.py +30 -10
- openstackclient/identity/v3/catalog.py +3 -3
- openstackclient/identity/v3/consumer.py +1 -1
- openstackclient/identity/v3/credential.py +1 -1
- openstackclient/identity/v3/domain.py +10 -4
- openstackclient/identity/v3/ec2creds.py +1 -1
- openstackclient/identity/v3/endpoint.py +33 -12
- openstackclient/identity/v3/endpoint_group.py +1 -1
- openstackclient/identity/v3/federation_protocol.py +1 -1
- openstackclient/identity/v3/group.py +11 -5
- openstackclient/identity/v3/identity_provider.py +12 -10
- openstackclient/identity/v3/implied_role.py +1 -1
- openstackclient/identity/v3/limit.py +1 -1
- openstackclient/identity/v3/mapping.py +1 -1
- openstackclient/identity/v3/policy.py +1 -1
- openstackclient/identity/v3/project.py +10 -3
- openstackclient/identity/v3/region.py +1 -1
- openstackclient/identity/v3/registered_limit.py +16 -11
- openstackclient/identity/v3/role.py +20 -39
- openstackclient/identity/v3/role_assignment.py +12 -23
- openstackclient/identity/v3/service.py +1 -1
- openstackclient/identity/v3/service_provider.py +1 -1
- openstackclient/identity/v3/tag.py +3 -2
- openstackclient/identity/v3/token.py +3 -2
- openstackclient/identity/v3/trust.py +4 -2
- openstackclient/identity/v3/unscoped_saml.py +1 -1
- openstackclient/identity/v3/user.py +22 -13
- openstackclient/image/v1/image.py +19 -16
- openstackclient/image/v2/cache.py +1 -1
- openstackclient/image/v2/image.py +14 -11
- openstackclient/image/v2/info.py +1 -1
- openstackclient/image/v2/metadef_namespaces.py +1 -1
- openstackclient/image/v2/metadef_objects.py +1 -1
- openstackclient/image/v2/metadef_properties.py +3 -2
- openstackclient/image/v2/metadef_resource_type_association.py +1 -1
- openstackclient/image/v2/metadef_resource_types.py +1 -1
- openstackclient/image/v2/task.py +1 -1
- openstackclient/network/common.py +10 -9
- openstackclient/network/v2/address_group.py +4 -3
- openstackclient/network/v2/address_scope.py +8 -6
- openstackclient/network/v2/default_security_group_rule.py +9 -8
- openstackclient/network/v2/floating_ip.py +16 -9
- openstackclient/network/v2/floating_ip_port_forwarding.py +9 -6
- openstackclient/network/v2/ip_availability.py +7 -4
- openstackclient/network/v2/l3_conntrack_helper.py +11 -4
- openstackclient/network/v2/local_ip.py +13 -7
- openstackclient/network/v2/local_ip_association.py +7 -4
- openstackclient/network/v2/ndp_proxy.py +13 -6
- openstackclient/network/v2/network.py +33 -16
- openstackclient/network/v2/network_agent.py +5 -5
- openstackclient/network/v2/network_auto_allocated_topology.py +1 -1
- openstackclient/network/v2/network_flavor.py +1 -1
- openstackclient/network/v2/network_flavor_profile.py +1 -1
- openstackclient/network/v2/network_meter.py +1 -1
- openstackclient/network/v2/network_meter_rule.py +1 -1
- openstackclient/network/v2/network_qos_policy.py +7 -5
- openstackclient/network/v2/network_qos_rule.py +1 -1
- openstackclient/network/v2/network_qos_rule_type.py +1 -1
- openstackclient/network/v2/network_rbac.py +8 -5
- openstackclient/network/v2/network_segment.py +2 -2
- openstackclient/network/v2/network_segment_range.py +13 -6
- openstackclient/network/v2/network_service_provider.py +1 -1
- openstackclient/network/v2/network_trunk.py +65 -42
- openstackclient/network/v2/port.py +22 -20
- openstackclient/network/v2/router.py +19 -8
- openstackclient/network/v2/security_group.py +10 -6
- openstackclient/network/v2/security_group_rule.py +11 -5
- openstackclient/network/v2/subnet.py +17 -18
- openstackclient/network/v2/subnet_pool.py +11 -9
- openstackclient/network/v2/taas/__init__.py +0 -0
- openstackclient/network/v2/taas/tap_flow.py +245 -0
- openstackclient/network/v2/taas/tap_mirror.py +237 -0
- openstackclient/network/v2/taas/tap_service.py +211 -0
- openstackclient/object/v1/account.py +1 -1
- openstackclient/object/v1/container.py +1 -1
- openstackclient/object/v1/object.py +1 -1
- openstackclient/shell.py +18 -8
- openstackclient/tests/functional/identity/v3/test_catalog.py +42 -23
- openstackclient/tests/functional/identity/v3/test_role_assignment.py +174 -0
- openstackclient/tests/functional/image/v2/test_cache.py +54 -0
- openstackclient/tests/functional/image/v2/test_metadef_resource_type.py +55 -0
- openstackclient/tests/unit/common/test_command.py +1 -1
- openstackclient/tests/unit/common/test_extension.py +2 -3
- openstackclient/tests/unit/common/test_module.py +14 -7
- openstackclient/tests/unit/common/test_quota.py +20 -0
- openstackclient/tests/unit/compute/v2/test_aggregate.py +5 -3
- openstackclient/tests/unit/compute/v2/test_console.py +1 -4
- openstackclient/tests/unit/compute/v2/test_flavor.py +1 -3
- openstackclient/tests/unit/compute/v2/test_hypervisor_stats.py +1 -9
- openstackclient/tests/unit/compute/v2/test_server.py +364 -30
- openstackclient/tests/unit/compute/v2/test_server_backup.py +1 -3
- openstackclient/tests/unit/compute/v2/test_service.py +1 -3
- openstackclient/tests/unit/fakes.py +35 -134
- openstackclient/tests/unit/identity/test_common.py +100 -0
- openstackclient/tests/unit/identity/v2_0/test_project.py +4 -4
- openstackclient/tests/unit/identity/v3/fakes.py +10 -2
- openstackclient/tests/unit/identity/v3/test_application_credential.py +3 -3
- openstackclient/tests/unit/identity/v3/test_domain.py +1 -1
- openstackclient/tests/unit/identity/v3/test_endpoint.py +1 -1
- openstackclient/tests/unit/identity/v3/test_group.py +4 -2
- openstackclient/tests/unit/identity/v3/test_identity_provider.py +10 -10
- openstackclient/tests/unit/identity/v3/test_oauth.py +1 -1
- openstackclient/tests/unit/identity/v3/test_project.py +1 -1
- openstackclient/tests/unit/identity/v3/test_registered_limit.py +2 -2
- openstackclient/tests/unit/identity/v3/test_role.py +1 -82
- openstackclient/tests/unit/identity/v3/test_user.py +7 -51
- openstackclient/tests/unit/image/v2/test_image.py +111 -0
- openstackclient/tests/unit/network/test_common.py +9 -13
- openstackclient/tests/unit/network/v2/taas/__init__.py +0 -0
- openstackclient/tests/unit/network/v2/taas/test_osc_tap_flow.py +276 -0
- openstackclient/tests/unit/network/v2/taas/test_osc_tap_mirror.py +288 -0
- openstackclient/tests/unit/network/v2/taas/test_osc_tap_service.py +271 -0
- openstackclient/tests/unit/network/v2/test_address_group.py +19 -22
- openstackclient/tests/unit/network/v2/test_address_scope.py +10 -15
- openstackclient/tests/unit/network/v2/test_default_security_group_rule.py +38 -49
- openstackclient/tests/unit/network/v2/test_floating_ip_network.py +21 -27
- openstackclient/tests/unit/network/v2/test_floating_ip_port_forwarding.py +21 -18
- openstackclient/tests/unit/network/v2/test_ip_availability.py +6 -8
- openstackclient/tests/unit/network/v2/test_l3_conntrack_helper.py +6 -15
- openstackclient/tests/unit/network/v2/test_local_ip.py +12 -23
- openstackclient/tests/unit/network/v2/test_local_ip_association.py +13 -18
- openstackclient/tests/unit/network/v2/test_ndp_proxy.py +11 -21
- openstackclient/tests/unit/network/v2/test_network.py +41 -37
- openstackclient/tests/unit/network/v2/test_network_agent.py +13 -20
- openstackclient/tests/unit/network/v2/test_network_auto_allocated_topology.py +5 -8
- openstackclient/tests/unit/network/v2/test_network_flavor.py +14 -26
- openstackclient/tests/unit/network/v2/test_network_flavor_profile.py +14 -17
- openstackclient/tests/unit/network/v2/test_network_meter.py +7 -17
- openstackclient/tests/unit/network/v2/test_network_meter_rule.py +10 -20
- openstackclient/tests/unit/network/v2/test_network_qos_policy.py +7 -13
- openstackclient/tests/unit/network/v2/test_network_qos_rule.py +44 -54
- openstackclient/tests/unit/network/v2/test_network_qos_rule_type.py +2 -7
- openstackclient/tests/unit/network/v2/test_network_rbac.py +21 -36
- openstackclient/tests/unit/network/v2/test_network_segment.py +13 -29
- openstackclient/tests/unit/network/v2/test_network_segment_range.py +20 -19
- openstackclient/tests/unit/network/v2/test_network_service_provider.py +1 -4
- openstackclient/tests/unit/network/v2/test_network_trunk.py +52 -47
- openstackclient/tests/unit/network/v2/test_port.py +75 -86
- openstackclient/tests/unit/network/v2/test_router.py +104 -126
- openstackclient/tests/unit/network/v2/test_security_group_network.py +19 -26
- openstackclient/tests/unit/network/v2/test_security_group_rule_network.py +17 -18
- openstackclient/tests/unit/network/v2/test_subnet.py +35 -46
- openstackclient/tests/unit/network/v2/test_subnet_pool.py +21 -33
- openstackclient/tests/unit/volume/test_find_resource.py +4 -13
- openstackclient/tests/unit/volume/v2/test_volume_backup.py +3 -1
- openstackclient/tests/unit/volume/v3/test_volume.py +4 -0
- openstackclient/tests/unit/volume/v3/test_volume_backup.py +9 -0
- openstackclient/volume/client.py +7 -17
- openstackclient/volume/v2/backup_record.py +1 -1
- openstackclient/volume/v2/consistency_group.py +1 -1
- openstackclient/volume/v2/consistency_group_snapshot.py +1 -1
- openstackclient/volume/v2/qos_specs.py +1 -1
- openstackclient/volume/v2/service.py +1 -1
- openstackclient/volume/v2/volume.py +2 -2
- openstackclient/volume/v2/volume_backend.py +1 -1
- openstackclient/volume/v2/volume_backup.py +5 -3
- openstackclient/volume/v2/volume_host.py +1 -2
- openstackclient/volume/v2/volume_snapshot.py +2 -2
- openstackclient/volume/v2/volume_transfer_request.py +1 -1
- openstackclient/volume/v2/volume_type.py +11 -6
- openstackclient/volume/v3/block_storage_cleanup.py +1 -1
- openstackclient/volume/v3/block_storage_cluster.py +1 -1
- openstackclient/volume/v3/block_storage_log_level.py +1 -1
- openstackclient/volume/v3/block_storage_manage.py +1 -1
- openstackclient/volume/v3/block_storage_resource_filter.py +1 -1
- openstackclient/volume/v3/service.py +1 -1
- openstackclient/volume/v3/volume.py +2 -2
- openstackclient/volume/v3/volume_attachment.py +6 -5
- openstackclient/volume/v3/volume_backup.py +18 -3
- openstackclient/volume/v3/volume_group.py +1 -1
- openstackclient/volume/v3/volume_group_snapshot.py +1 -1
- openstackclient/volume/v3/volume_group_type.py +1 -1
- openstackclient/volume/v3/volume_message.py +1 -1
- openstackclient/volume/v3/volume_snapshot.py +2 -2
- openstackclient/volume/v3/volume_transfer_request.py +1 -1
- openstackclient/volume/v3/volume_type.py +15 -9
- {python_openstackclient-8.2.0.dist-info → python_openstackclient-8.3.0.dist-info}/METADATA +15 -13
- {python_openstackclient-8.2.0.dist-info → python_openstackclient-8.3.0.dist-info}/RECORD +224 -213
- {python_openstackclient-8.2.0.dist-info → python_openstackclient-8.3.0.dist-info}/WHEEL +1 -1
- {python_openstackclient-8.2.0.dist-info → python_openstackclient-8.3.0.dist-info}/entry_points.txt +15 -0
- {python_openstackclient-8.2.0.dist-info → python_openstackclient-8.3.0.dist-info/licenses}/AUTHORS +10 -0
- python_openstackclient-8.3.0.dist-info/pbr.json +1 -0
- openstackclient/tests/unit/common/test_logs.py +0 -221
- python_openstackclient-8.2.0.dist-info/pbr.json +0 -1
- {python_openstackclient-8.2.0.dist-info → python_openstackclient-8.3.0.dist-info/licenses}/LICENSE +0 -0
- {python_openstackclient-8.2.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
|
|
@@ -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=
|
|
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(
|
|
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)
|
|
@@ -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
|
-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
44
|
-
|
|
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)
|
|
@@ -0,0 +1,55 @@
|
|
|
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 ImageMetadefResourceTypeTests(base.BaseImageTests):
|
|
19
|
+
"""Functional tests for image metadef resource type commands."""
|
|
20
|
+
|
|
21
|
+
def setUp(self):
|
|
22
|
+
super().setUp()
|
|
23
|
+
|
|
24
|
+
# Create unique namespace name using UUID
|
|
25
|
+
self.namespace_name = 'test-mdef-ns-' + uuid.uuid4().hex
|
|
26
|
+
self.resource_type_name = 'test-mdef-rt-' + uuid.uuid4().hex
|
|
27
|
+
|
|
28
|
+
# Create namespace
|
|
29
|
+
self.openstack('image metadef namespace create ' + self.namespace_name)
|
|
30
|
+
self.addCleanup(
|
|
31
|
+
self.openstack,
|
|
32
|
+
'image metadef namespace delete ' + self.namespace_name,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
def test_metadef_resource_type(self):
|
|
36
|
+
"""Test image metadef resource type commands"""
|
|
37
|
+
|
|
38
|
+
self.openstack(
|
|
39
|
+
'image metadef resource type association create '
|
|
40
|
+
f'{self.namespace_name} {self.resource_type_name}',
|
|
41
|
+
)
|
|
42
|
+
self.addCleanup(
|
|
43
|
+
self.openstack,
|
|
44
|
+
'image metadef resource type association delete '
|
|
45
|
+
f'{self.namespace_name} {self.resource_type_name}',
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
output = self.openstack(
|
|
49
|
+
'image metadef resource type list',
|
|
50
|
+
parse_output=True,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
self.assertIn(
|
|
54
|
+
self.resource_type_name, [item['Name'] for item in output]
|
|
55
|
+
)
|