python-openstackclient 10.0.0__py3-none-any.whl → 10.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- openstackclient/common/availability_zone.py +1 -1
- openstackclient/common/module.py +21 -27
- openstackclient/common/pagination.py +42 -4
- openstackclient/common/project_cleanup.py +1 -2
- openstackclient/common/quota.py +9 -5
- openstackclient/compute/v2/flavor.py +3 -1
- openstackclient/compute/v2/hypervisor.py +2 -0
- openstackclient/compute/v2/keypair.py +6 -2
- openstackclient/compute/v2/server.py +21 -12
- openstackclient/compute/v2/server_event.py +8 -1
- openstackclient/compute/v2/server_group.py +2 -0
- openstackclient/compute/v2/server_migration.py +3 -0
- openstackclient/compute/v2/server_volume.py +3 -1
- openstackclient/compute/v2/service.py +3 -1
- openstackclient/compute/v2/usage.py +2 -2
- openstackclient/identity/common.py +5 -1
- openstackclient/identity/v3/access_rule.py +6 -0
- openstackclient/identity/v3/application_credential.py +10 -3
- openstackclient/identity/v3/credential.py +4 -2
- openstackclient/identity/v3/domain.py +4 -2
- openstackclient/identity/v3/endpoint.py +57 -45
- openstackclient/identity/v3/federation_protocol.py +7 -5
- openstackclient/identity/v3/group.py +11 -10
- openstackclient/identity/v3/identity_provider.py +4 -1
- openstackclient/identity/v3/limit.py +5 -2
- openstackclient/identity/v3/mapping.py +36 -19
- openstackclient/identity/v3/project.py +18 -5
- openstackclient/identity/v3/region.py +4 -2
- openstackclient/identity/v3/registered_limit.py +3 -2
- openstackclient/identity/v3/role.py +2 -1
- openstackclient/identity/v3/role_assignment.py +3 -2
- openstackclient/identity/v3/service.py +4 -2
- openstackclient/identity/v3/service_provider.py +4 -2
- openstackclient/identity/v3/trust.py +8 -5
- openstackclient/identity/v3/user.py +38 -11
- openstackclient/image/v2/cache.py +2 -2
- openstackclient/image/v2/image.py +15 -9
- openstackclient/image/v2/metadef_namespaces.py +11 -10
- openstackclient/image/v2/metadef_objects.py +5 -5
- openstackclient/image/v2/metadef_properties.py +7 -4
- openstackclient/image/v2/task.py +11 -22
- openstackclient/network/utils.py +0 -41
- openstackclient/network/v2/address_group.py +13 -1
- openstackclient/network/v2/address_scope.py +13 -8
- openstackclient/network/v2/bgpvpn/bgpvpn.py +33 -19
- openstackclient/network/v2/bgpvpn/network_association.py +25 -13
- openstackclient/network/v2/bgpvpn/port_association.py +35 -21
- openstackclient/network/v2/bgpvpn/router_association.py +27 -14
- openstackclient/network/v2/default_security_group_rule.py +14 -6
- openstackclient/network/v2/floating_ip.py +12 -4
- openstackclient/network/v2/floating_ip_port_forwarding.py +12 -2
- openstackclient/network/v2/fwaas/group.py +34 -1
- openstackclient/network/v2/fwaas/rule.py +39 -3
- openstackclient/network/v2/ip_availability.py +13 -4
- openstackclient/network/v2/l3_conntrack_helper.py +14 -1
- openstackclient/network/v2/local_ip.py +4 -1
- openstackclient/network/v2/local_ip_association.py +4 -1
- openstackclient/network/v2/ndp_proxy.py +4 -1
- openstackclient/network/v2/network.py +87 -20
- openstackclient/network/v2/network_agent.py +32 -10
- openstackclient/network/v2/network_auto_allocated_topology.py +6 -5
- openstackclient/network/v2/network_flavor.py +19 -6
- openstackclient/network/v2/network_flavor_profile.py +20 -6
- openstackclient/network/v2/network_meter.py +19 -6
- openstackclient/network/v2/network_meter_rule.py +20 -2
- openstackclient/network/v2/network_qos_policy.py +15 -7
- openstackclient/network/v2/network_qos_rule.py +16 -1
- openstackclient/network/v2/network_qos_rule_type.py +16 -5
- openstackclient/network/v2/network_rbac.py +12 -5
- openstackclient/network/v2/network_segment.py +13 -1
- openstackclient/network/v2/network_segment_range.py +15 -3
- openstackclient/network/v2/network_trunk.py +4 -1
- openstackclient/network/v2/port.py +88 -12
- openstackclient/network/v2/router.py +27 -16
- openstackclient/network/v2/security_group.py +18 -49
- openstackclient/network/v2/security_group_rule.py +18 -5
- openstackclient/network/v2/subnet.py +15 -7
- openstackclient/network/v2/subnet_pool.py +13 -8
- openstackclient/network/v2/taas/tap_flow.py +13 -3
- openstackclient/network/v2/taas/tap_mirror.py +7 -4
- openstackclient/network/v2/taas/tap_service.py +4 -1
- openstackclient/object/v1/container.py +3 -1
- openstackclient/object/v1/object.py +3 -1
- openstackclient/tests/functional/identity/v3/common.py +34 -0
- openstackclient/tests/functional/identity/v3/test_application_credential.py +1 -1
- openstackclient/tests/functional/identity/v3/test_mapping.py +81 -0
- openstackclient/tests/functional/volume/v3/test_volume_group.py +163 -0
- openstackclient/tests/unit/common/test_limits.py +1 -1
- openstackclient/tests/unit/common/test_module.py +77 -44
- openstackclient/tests/unit/common/test_quota.py +9 -0
- openstackclient/tests/unit/compute/v2/fakes.py +1 -57
- openstackclient/tests/unit/compute/v2/test_agent.py +4 -4
- openstackclient/tests/unit/compute/v2/test_aggregate.py +1 -1
- openstackclient/tests/unit/compute/v2/test_console.py +2 -2
- openstackclient/tests/unit/compute/v2/test_console_connection.py +1 -1
- openstackclient/tests/unit/compute/v2/test_flavor.py +1 -1
- openstackclient/tests/unit/compute/v2/test_host.py +3 -3
- openstackclient/tests/unit/compute/v2/test_hypervisor.py +2 -2
- openstackclient/tests/unit/compute/v2/test_hypervisor_stats.py +1 -1
- openstackclient/tests/unit/compute/v2/test_keypair.py +1 -1
- openstackclient/tests/unit/compute/v2/test_server.py +15 -15
- openstackclient/tests/unit/compute/v2/test_server_backup.py +1 -1
- openstackclient/tests/unit/compute/v2/test_server_event.py +2 -2
- openstackclient/tests/unit/compute/v2/test_server_group.py +1 -1
- openstackclient/tests/unit/compute/v2/test_server_image.py +1 -1
- openstackclient/tests/unit/compute/v2/test_server_migration.py +4 -4
- openstackclient/tests/unit/compute/v2/test_server_share.py +4 -4
- openstackclient/tests/unit/compute/v2/test_server_volume.py +2 -2
- openstackclient/tests/unit/compute/v2/test_service.py +3 -3
- openstackclient/tests/unit/compute/v2/test_usage.py +1 -1
- openstackclient/tests/unit/identity/v2_0/fakes.py +3 -7
- openstackclient/tests/unit/identity/v2_0/test_endpoint.py +1 -1
- openstackclient/tests/unit/identity/v2_0/test_project.py +1 -1
- openstackclient/tests/unit/identity/v2_0/test_role.py +1 -1
- openstackclient/tests/unit/identity/v2_0/test_role_assignment.py +1 -1
- openstackclient/tests/unit/identity/v2_0/test_service.py +1 -1
- openstackclient/tests/unit/identity/v2_0/test_token.py +2 -2
- openstackclient/tests/unit/identity/v2_0/test_user.py +1 -1
- openstackclient/tests/unit/identity/v3/fakes.py +5 -38
- openstackclient/tests/unit/identity/v3/test_access_rule.py +3 -3
- openstackclient/tests/unit/identity/v3/test_application_credential.py +4 -4
- openstackclient/tests/unit/identity/v3/test_credential.py +5 -5
- openstackclient/tests/unit/identity/v3/test_domain.py +5 -5
- openstackclient/tests/unit/identity/v3/test_endpoint.py +6 -6
- openstackclient/tests/unit/identity/v3/test_endpoint_group.py +1 -1
- openstackclient/tests/unit/identity/v3/test_group.py +8 -8
- openstackclient/tests/unit/identity/v3/test_implied_role.py +1 -1
- openstackclient/tests/unit/identity/v3/test_limit.py +5 -5
- openstackclient/tests/unit/identity/v3/test_mappings.py +163 -79
- openstackclient/tests/unit/identity/v3/test_project.py +28 -5
- openstackclient/tests/unit/identity/v3/test_protocol.py +3 -3
- openstackclient/tests/unit/identity/v3/test_region.py +5 -5
- openstackclient/tests/unit/identity/v3/test_registered_limit.py +5 -5
- openstackclient/tests/unit/identity/v3/test_role.py +8 -8
- openstackclient/tests/unit/identity/v3/test_role_assignment.py +1 -1
- openstackclient/tests/unit/identity/v3/test_service.py +5 -5
- openstackclient/tests/unit/identity/v3/test_token.py +2 -2
- openstackclient/tests/unit/identity/v3/test_trust.py +4 -4
- openstackclient/tests/unit/identity/v3/test_user.py +73 -6
- openstackclient/tests/unit/network/v2/fakes.py +5 -77
- openstackclient/tests/unit/network/v2/fwaas/test_group.py +28 -2
- openstackclient/tests/unit/network/v2/fwaas/test_rule.py +28 -3
- openstackclient/tests/unit/network/v2/test_address_group.py +24 -0
- openstackclient/tests/unit/network/v2/test_address_scope.py +24 -0
- openstackclient/tests/unit/network/v2/test_floating_ip.py +24 -0
- openstackclient/tests/unit/network/v2/test_floating_ip_port_forwarding.py +24 -0
- openstackclient/tests/unit/network/v2/test_ip_availability.py +25 -0
- openstackclient/tests/unit/network/v2/test_l3_conntrack_helper.py +29 -3
- openstackclient/tests/unit/network/v2/test_network.py +74 -12
- openstackclient/tests/unit/network/v2/test_network_agent.py +50 -1
- openstackclient/tests/unit/network/v2/test_network_flavor.py +24 -0
- openstackclient/tests/unit/network/v2/test_network_flavor_profile.py +24 -0
- openstackclient/tests/unit/network/v2/test_network_meter.py +24 -0
- openstackclient/tests/unit/network/v2/test_network_qos_policy.py +24 -0
- openstackclient/tests/unit/network/v2/test_network_qos_rule_type.py +24 -0
- openstackclient/tests/unit/network/v2/test_network_rbac.py +24 -0
- openstackclient/tests/unit/network/v2/test_network_segment.py +24 -0
- openstackclient/tests/unit/network/v2/test_network_segment_range.py +24 -0
- openstackclient/tests/unit/network/v2/test_port.py +166 -0
- openstackclient/tests/unit/network/v2/test_router.py +28 -7
- openstackclient/tests/unit/network/v2/test_security_group.py +22 -0
- openstackclient/tests/unit/network/v2/test_security_group_rule.py +25 -0
- openstackclient/tests/unit/network/v2/test_subnet.py +28 -4
- openstackclient/tests/unit/network/v2/test_subnet_pool.py +24 -0
- openstackclient/tests/unit/volume/v2/fakes.py +20 -140
- openstackclient/tests/unit/volume/v2/test_volume_backup.py +5 -9
- openstackclient/tests/unit/volume/v2/test_volume_snapshot.py +6 -0
- openstackclient/tests/unit/volume/v3/fakes.py +204 -100
- openstackclient/tests/unit/volume/v3/test_backup_record.py +114 -0
- openstackclient/tests/unit/volume/v3/test_consistency_group.py +720 -0
- openstackclient/tests/unit/volume/v3/test_consistency_group_snapshot.py +354 -0
- openstackclient/tests/unit/volume/v3/test_qos_specs.py +455 -0
- openstackclient/tests/unit/volume/v3/test_volume_attachment.py +2 -0
- openstackclient/tests/unit/volume/v3/test_volume_backend.py +158 -0
- openstackclient/tests/unit/volume/v3/test_volume_backup.py +5 -9
- openstackclient/tests/unit/volume/v3/test_volume_group_type.py +65 -0
- openstackclient/tests/unit/volume/v3/test_volume_host.py +115 -0
- openstackclient/tests/unit/volume/v3/test_volume_snapshot.py +6 -0
- openstackclient/volume/v2/volume.py +4 -2
- openstackclient/volume/v2/volume_backup.py +2 -3
- openstackclient/volume/v2/volume_snapshot.py +3 -4
- openstackclient/volume/v3/backup_record.py +94 -0
- openstackclient/volume/v3/consistency_group.py +400 -0
- openstackclient/volume/v3/consistency_group_snapshot.py +225 -0
- openstackclient/volume/v3/qos_specs.py +389 -0
- openstackclient/volume/v3/volume.py +4 -2
- openstackclient/volume/v3/volume_attachment.py +5 -1
- openstackclient/volume/v3/volume_backend.py +130 -0
- openstackclient/volume/v3/volume_backup.py +2 -3
- openstackclient/volume/v3/volume_group_snapshot.py +4 -6
- openstackclient/volume/v3/volume_group_type.py +1 -1
- openstackclient/volume/v3/volume_host.py +74 -0
- openstackclient/volume/v3/volume_message.py +3 -1
- openstackclient/volume/v3/volume_snapshot.py +2 -1
- {python_openstackclient-10.0.0.dist-info → python_openstackclient-10.1.0.dist-info}/METADATA +3 -4
- {python_openstackclient-10.0.0.dist-info → python_openstackclient-10.1.0.dist-info}/RECORD +202 -188
- {python_openstackclient-10.0.0.dist-info → python_openstackclient-10.1.0.dist-info}/entry_points.txt +24 -24
- {python_openstackclient-10.0.0.dist-info → python_openstackclient-10.1.0.dist-info}/licenses/AUTHORS +5 -0
- python_openstackclient-10.1.0.dist-info/pbr.json +1 -0
- python_openstackclient-10.0.0.dist-info/pbr.json +0 -1
- {python_openstackclient-10.0.0.dist-info → python_openstackclient-10.1.0.dist-info}/WHEEL +0 -0
- {python_openstackclient-10.0.0.dist-info → python_openstackclient-10.1.0.dist-info}/licenses/LICENSE +0 -0
- {python_openstackclient-10.0.0.dist-info → python_openstackclient-10.1.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
# Copyright 2015 iWeb Technologies 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 copy
|
|
16
|
+
from unittest import mock
|
|
17
|
+
from unittest.mock import call
|
|
18
|
+
|
|
19
|
+
from osc_lib.cli import format_columns
|
|
20
|
+
from osc_lib import exceptions
|
|
21
|
+
from osc_lib import utils
|
|
22
|
+
|
|
23
|
+
from openstackclient.tests.unit.volume.v3 import fakes as volume_fakes
|
|
24
|
+
from openstackclient.volume.v3 import qos_specs
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class TestQos(volume_fakes.TestVolume):
|
|
28
|
+
def setUp(self):
|
|
29
|
+
super().setUp()
|
|
30
|
+
|
|
31
|
+
self.qos_mock = self.volume_client.qos_specs
|
|
32
|
+
self.qos_mock.reset_mock()
|
|
33
|
+
|
|
34
|
+
self.types_mock = self.volume_client.volume_types
|
|
35
|
+
self.types_mock.reset_mock()
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class TestQosAssociate(TestQos):
|
|
39
|
+
volume_type = volume_fakes.create_one_volume_type()
|
|
40
|
+
qos_spec = volume_fakes.create_one_qos()
|
|
41
|
+
|
|
42
|
+
def setUp(self):
|
|
43
|
+
super().setUp()
|
|
44
|
+
|
|
45
|
+
self.qos_mock.get.return_value = self.qos_spec
|
|
46
|
+
self.types_mock.get.return_value = self.volume_type
|
|
47
|
+
# Get the command object to test
|
|
48
|
+
self.cmd = qos_specs.AssociateQos(self.app, None)
|
|
49
|
+
|
|
50
|
+
def test_qos_associate(self):
|
|
51
|
+
arglist = [self.qos_spec.id, self.volume_type.id]
|
|
52
|
+
verifylist = [
|
|
53
|
+
('qos_spec', self.qos_spec.id),
|
|
54
|
+
('volume_type', self.volume_type.id),
|
|
55
|
+
]
|
|
56
|
+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
|
57
|
+
|
|
58
|
+
result = self.cmd.take_action(parsed_args)
|
|
59
|
+
|
|
60
|
+
self.qos_mock.associate.assert_called_with(
|
|
61
|
+
self.qos_spec.id, self.volume_type.id
|
|
62
|
+
)
|
|
63
|
+
self.assertIsNone(result)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class TestQosCreate(TestQos):
|
|
67
|
+
columns = ('consumer', 'id', 'name', 'properties')
|
|
68
|
+
|
|
69
|
+
def setUp(self):
|
|
70
|
+
super().setUp()
|
|
71
|
+
|
|
72
|
+
self.new_qos_spec = volume_fakes.create_one_qos()
|
|
73
|
+
self.qos_mock.create.return_value = self.new_qos_spec
|
|
74
|
+
|
|
75
|
+
self.data = (
|
|
76
|
+
self.new_qos_spec.consumer,
|
|
77
|
+
self.new_qos_spec.id,
|
|
78
|
+
self.new_qos_spec.name,
|
|
79
|
+
format_columns.DictColumn(self.new_qos_spec.specs),
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
# Get the command object to test
|
|
83
|
+
self.cmd = qos_specs.CreateQos(self.app, None)
|
|
84
|
+
|
|
85
|
+
def test_qos_create_without_properties(self):
|
|
86
|
+
arglist = [
|
|
87
|
+
self.new_qos_spec.name,
|
|
88
|
+
]
|
|
89
|
+
verifylist = [
|
|
90
|
+
('name', self.new_qos_spec.name),
|
|
91
|
+
]
|
|
92
|
+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
|
93
|
+
|
|
94
|
+
columns, data = self.cmd.take_action(parsed_args)
|
|
95
|
+
|
|
96
|
+
self.qos_mock.create.assert_called_with(
|
|
97
|
+
self.new_qos_spec.name, {'consumer': 'both'}
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
self.assertEqual(self.columns, columns)
|
|
101
|
+
self.assertCountEqual(self.data, data)
|
|
102
|
+
|
|
103
|
+
def test_qos_create_with_consumer(self):
|
|
104
|
+
arglist = [
|
|
105
|
+
'--consumer',
|
|
106
|
+
self.new_qos_spec.consumer,
|
|
107
|
+
self.new_qos_spec.name,
|
|
108
|
+
]
|
|
109
|
+
verifylist = [
|
|
110
|
+
('consumer', self.new_qos_spec.consumer),
|
|
111
|
+
('name', self.new_qos_spec.name),
|
|
112
|
+
]
|
|
113
|
+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
|
114
|
+
|
|
115
|
+
columns, data = self.cmd.take_action(parsed_args)
|
|
116
|
+
|
|
117
|
+
self.qos_mock.create.assert_called_with(
|
|
118
|
+
self.new_qos_spec.name, {'consumer': self.new_qos_spec.consumer}
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
self.assertEqual(self.columns, columns)
|
|
122
|
+
self.assertCountEqual(self.data, data)
|
|
123
|
+
|
|
124
|
+
def test_qos_create_with_properties(self):
|
|
125
|
+
arglist = [
|
|
126
|
+
'--consumer',
|
|
127
|
+
self.new_qos_spec.consumer,
|
|
128
|
+
'--property',
|
|
129
|
+
'foo=bar',
|
|
130
|
+
'--property',
|
|
131
|
+
'iops=9001',
|
|
132
|
+
self.new_qos_spec.name,
|
|
133
|
+
]
|
|
134
|
+
verifylist = [
|
|
135
|
+
('consumer', self.new_qos_spec.consumer),
|
|
136
|
+
('property', self.new_qos_spec.specs),
|
|
137
|
+
('name', self.new_qos_spec.name),
|
|
138
|
+
]
|
|
139
|
+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
|
140
|
+
|
|
141
|
+
columns, data = self.cmd.take_action(parsed_args)
|
|
142
|
+
|
|
143
|
+
self.qos_mock.create.assert_called_with(
|
|
144
|
+
self.new_qos_spec.name,
|
|
145
|
+
{
|
|
146
|
+
'consumer': self.new_qos_spec.consumer,
|
|
147
|
+
'foo': 'bar',
|
|
148
|
+
'iops': '9001',
|
|
149
|
+
},
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
self.assertEqual(self.columns, columns)
|
|
153
|
+
self.assertCountEqual(self.data, data)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class TestQosDelete(TestQos):
|
|
157
|
+
qos_specs = volume_fakes.create_qoses(count=2)
|
|
158
|
+
|
|
159
|
+
def setUp(self):
|
|
160
|
+
super().setUp()
|
|
161
|
+
|
|
162
|
+
self.qos_mock.get = volume_fakes.get_qoses(self.qos_specs)
|
|
163
|
+
# Get the command object to test
|
|
164
|
+
self.cmd = qos_specs.DeleteQos(self.app, None)
|
|
165
|
+
|
|
166
|
+
def test_qos_delete(self):
|
|
167
|
+
arglist = [self.qos_specs[0].id]
|
|
168
|
+
verifylist = [('qos_specs', [self.qos_specs[0].id])]
|
|
169
|
+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
|
170
|
+
|
|
171
|
+
result = self.cmd.take_action(parsed_args)
|
|
172
|
+
|
|
173
|
+
self.qos_mock.delete.assert_called_with(self.qos_specs[0].id, False)
|
|
174
|
+
self.assertIsNone(result)
|
|
175
|
+
|
|
176
|
+
def test_qos_delete_with_force(self):
|
|
177
|
+
arglist = ['--force', self.qos_specs[0].id]
|
|
178
|
+
verifylist = [('force', True), ('qos_specs', [self.qos_specs[0].id])]
|
|
179
|
+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
|
180
|
+
|
|
181
|
+
result = self.cmd.take_action(parsed_args)
|
|
182
|
+
|
|
183
|
+
self.qos_mock.delete.assert_called_with(self.qos_specs[0].id, True)
|
|
184
|
+
self.assertIsNone(result)
|
|
185
|
+
|
|
186
|
+
def test_delete_multiple_qoses(self):
|
|
187
|
+
arglist = []
|
|
188
|
+
for q in self.qos_specs:
|
|
189
|
+
arglist.append(q.id)
|
|
190
|
+
verifylist = [
|
|
191
|
+
('qos_specs', arglist),
|
|
192
|
+
]
|
|
193
|
+
|
|
194
|
+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
|
195
|
+
result = self.cmd.take_action(parsed_args)
|
|
196
|
+
|
|
197
|
+
calls = []
|
|
198
|
+
for q in self.qos_specs:
|
|
199
|
+
calls.append(call(q.id, False))
|
|
200
|
+
self.qos_mock.delete.assert_has_calls(calls)
|
|
201
|
+
self.assertIsNone(result)
|
|
202
|
+
|
|
203
|
+
def test_delete_multiple_qoses_with_exception(self):
|
|
204
|
+
arglist = [
|
|
205
|
+
self.qos_specs[0].id,
|
|
206
|
+
'unexist_qos',
|
|
207
|
+
]
|
|
208
|
+
verifylist = [
|
|
209
|
+
('qos_specs', arglist),
|
|
210
|
+
]
|
|
211
|
+
|
|
212
|
+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
|
213
|
+
|
|
214
|
+
find_mock_result = [self.qos_specs[0], exceptions.CommandError]
|
|
215
|
+
with mock.patch.object(
|
|
216
|
+
utils, 'find_resource', side_effect=find_mock_result
|
|
217
|
+
) as find_mock:
|
|
218
|
+
try:
|
|
219
|
+
self.cmd.take_action(parsed_args)
|
|
220
|
+
self.fail('CommandError should be raised.')
|
|
221
|
+
except exceptions.CommandError as e:
|
|
222
|
+
self.assertEqual(
|
|
223
|
+
'1 of 2 QoS specifications failed to delete.', str(e)
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
find_mock.assert_any_call(self.qos_mock, self.qos_specs[0].id)
|
|
227
|
+
find_mock.assert_any_call(self.qos_mock, 'unexist_qos')
|
|
228
|
+
|
|
229
|
+
self.assertEqual(2, find_mock.call_count)
|
|
230
|
+
self.qos_mock.delete.assert_called_once_with(
|
|
231
|
+
self.qos_specs[0].id, False
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class TestQosDisassociate(TestQos):
|
|
236
|
+
volume_type = volume_fakes.create_one_volume_type()
|
|
237
|
+
qos_spec = volume_fakes.create_one_qos()
|
|
238
|
+
|
|
239
|
+
def setUp(self):
|
|
240
|
+
super().setUp()
|
|
241
|
+
|
|
242
|
+
self.qos_mock.get.return_value = self.qos_spec
|
|
243
|
+
self.types_mock.get.return_value = self.volume_type
|
|
244
|
+
# Get the command object to test
|
|
245
|
+
self.cmd = qos_specs.DisassociateQos(self.app, None)
|
|
246
|
+
|
|
247
|
+
def test_qos_disassociate_with_volume_type(self):
|
|
248
|
+
arglist = [
|
|
249
|
+
'--volume-type',
|
|
250
|
+
self.volume_type.id,
|
|
251
|
+
self.qos_spec.id,
|
|
252
|
+
]
|
|
253
|
+
verifylist = [
|
|
254
|
+
('volume_type', self.volume_type.id),
|
|
255
|
+
('qos_spec', self.qos_spec.id),
|
|
256
|
+
]
|
|
257
|
+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
|
258
|
+
|
|
259
|
+
result = self.cmd.take_action(parsed_args)
|
|
260
|
+
|
|
261
|
+
self.qos_mock.disassociate.assert_called_with(
|
|
262
|
+
self.qos_spec.id, self.volume_type.id
|
|
263
|
+
)
|
|
264
|
+
self.assertIsNone(result)
|
|
265
|
+
|
|
266
|
+
def test_qos_disassociate_with_all_volume_types(self):
|
|
267
|
+
arglist = [
|
|
268
|
+
'--all',
|
|
269
|
+
self.qos_spec.id,
|
|
270
|
+
]
|
|
271
|
+
verifylist = [('qos_spec', self.qos_spec.id)]
|
|
272
|
+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
|
273
|
+
|
|
274
|
+
result = self.cmd.take_action(parsed_args)
|
|
275
|
+
|
|
276
|
+
self.qos_mock.disassociate_all.assert_called_with(self.qos_spec.id)
|
|
277
|
+
self.assertIsNone(result)
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
class TestQosList(TestQos):
|
|
281
|
+
qos_specs = volume_fakes.create_qoses(count=2)
|
|
282
|
+
qos_association = volume_fakes.create_one_qos_association()
|
|
283
|
+
|
|
284
|
+
columns = (
|
|
285
|
+
'ID',
|
|
286
|
+
'Name',
|
|
287
|
+
'Consumer',
|
|
288
|
+
'Associations',
|
|
289
|
+
'Properties',
|
|
290
|
+
)
|
|
291
|
+
data = []
|
|
292
|
+
for q in qos_specs:
|
|
293
|
+
data.append(
|
|
294
|
+
(
|
|
295
|
+
q.id,
|
|
296
|
+
q.name,
|
|
297
|
+
q.consumer,
|
|
298
|
+
format_columns.ListColumn([qos_association.name]),
|
|
299
|
+
format_columns.DictColumn(q.specs),
|
|
300
|
+
)
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
def setUp(self):
|
|
304
|
+
super().setUp()
|
|
305
|
+
|
|
306
|
+
self.qos_mock.list.return_value = self.qos_specs
|
|
307
|
+
self.qos_mock.get_associations.return_value = [self.qos_association]
|
|
308
|
+
|
|
309
|
+
# Get the command object to test
|
|
310
|
+
self.cmd = qos_specs.ListQos(self.app, None)
|
|
311
|
+
|
|
312
|
+
def test_qos_list(self):
|
|
313
|
+
arglist = []
|
|
314
|
+
verifylist = []
|
|
315
|
+
|
|
316
|
+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
|
317
|
+
|
|
318
|
+
columns, data = self.cmd.take_action(parsed_args)
|
|
319
|
+
self.qos_mock.list.assert_called_with()
|
|
320
|
+
|
|
321
|
+
self.assertEqual(self.columns, columns)
|
|
322
|
+
self.assertCountEqual(self.data, list(data))
|
|
323
|
+
|
|
324
|
+
def test_qos_list_no_association(self):
|
|
325
|
+
self.qos_mock.reset_mock()
|
|
326
|
+
self.qos_mock.get_associations.side_effect = [
|
|
327
|
+
[self.qos_association],
|
|
328
|
+
exceptions.NotFound("NotFound"),
|
|
329
|
+
]
|
|
330
|
+
|
|
331
|
+
arglist = []
|
|
332
|
+
verifylist = []
|
|
333
|
+
|
|
334
|
+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
|
335
|
+
|
|
336
|
+
columns, data = self.cmd.take_action(parsed_args)
|
|
337
|
+
self.qos_mock.list.assert_called_with()
|
|
338
|
+
|
|
339
|
+
self.assertEqual(self.columns, columns)
|
|
340
|
+
|
|
341
|
+
ex_data = copy.deepcopy(self.data)
|
|
342
|
+
ex_data[1] = (
|
|
343
|
+
self.qos_specs[1].id,
|
|
344
|
+
self.qos_specs[1].name,
|
|
345
|
+
self.qos_specs[1].consumer,
|
|
346
|
+
format_columns.ListColumn(None),
|
|
347
|
+
format_columns.DictColumn(self.qos_specs[1].specs),
|
|
348
|
+
)
|
|
349
|
+
self.assertCountEqual(ex_data, list(data))
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
class TestQosSet(TestQos):
|
|
353
|
+
qos_spec = volume_fakes.create_one_qos()
|
|
354
|
+
|
|
355
|
+
def setUp(self):
|
|
356
|
+
super().setUp()
|
|
357
|
+
|
|
358
|
+
self.qos_mock.get.return_value = self.qos_spec
|
|
359
|
+
# Get the command object to test
|
|
360
|
+
self.cmd = qos_specs.SetQos(self.app, None)
|
|
361
|
+
|
|
362
|
+
def test_qos_set_with_properties_with_id(self):
|
|
363
|
+
arglist = [
|
|
364
|
+
'--no-property',
|
|
365
|
+
'--property',
|
|
366
|
+
'a=b',
|
|
367
|
+
'--property',
|
|
368
|
+
'c=d',
|
|
369
|
+
self.qos_spec.id,
|
|
370
|
+
]
|
|
371
|
+
new_property = {"a": "b", "c": "d"}
|
|
372
|
+
verifylist = [
|
|
373
|
+
('no_property', True),
|
|
374
|
+
('property', new_property),
|
|
375
|
+
('qos_spec', self.qos_spec.id),
|
|
376
|
+
]
|
|
377
|
+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
|
378
|
+
|
|
379
|
+
result = self.cmd.take_action(parsed_args)
|
|
380
|
+
|
|
381
|
+
self.qos_mock.unset_keys.assert_called_with(
|
|
382
|
+
self.qos_spec.id,
|
|
383
|
+
list(self.qos_spec.specs.keys()),
|
|
384
|
+
)
|
|
385
|
+
self.qos_mock.set_keys.assert_called_with(
|
|
386
|
+
self.qos_spec.id, {"a": "b", "c": "d"}
|
|
387
|
+
)
|
|
388
|
+
self.assertIsNone(result)
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
class TestQosShow(TestQos):
|
|
392
|
+
qos_spec = volume_fakes.create_one_qos()
|
|
393
|
+
qos_association = volume_fakes.create_one_qos_association()
|
|
394
|
+
|
|
395
|
+
columns = ('associations', 'consumer', 'id', 'name', 'properties')
|
|
396
|
+
data = (
|
|
397
|
+
format_columns.ListColumn([qos_association.name]),
|
|
398
|
+
qos_spec.consumer,
|
|
399
|
+
qos_spec.id,
|
|
400
|
+
qos_spec.name,
|
|
401
|
+
format_columns.DictColumn(qos_spec.specs),
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
def setUp(self):
|
|
405
|
+
super().setUp()
|
|
406
|
+
|
|
407
|
+
self.qos_mock.get.return_value = self.qos_spec
|
|
408
|
+
self.qos_mock.get_associations.return_value = [self.qos_association]
|
|
409
|
+
|
|
410
|
+
# Get the command object to test
|
|
411
|
+
self.cmd = qos_specs.ShowQos(self.app, None)
|
|
412
|
+
|
|
413
|
+
def test_qos_show(self):
|
|
414
|
+
arglist = [self.qos_spec.id]
|
|
415
|
+
verifylist = [('qos_spec', self.qos_spec.id)]
|
|
416
|
+
|
|
417
|
+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
|
418
|
+
|
|
419
|
+
columns, data = self.cmd.take_action(parsed_args)
|
|
420
|
+
self.qos_mock.get.assert_called_with(self.qos_spec.id)
|
|
421
|
+
|
|
422
|
+
self.assertEqual(self.columns, columns)
|
|
423
|
+
self.assertCountEqual(self.data, tuple(data))
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
class TestQosUnset(TestQos):
|
|
427
|
+
qos_spec = volume_fakes.create_one_qos()
|
|
428
|
+
|
|
429
|
+
def setUp(self):
|
|
430
|
+
super().setUp()
|
|
431
|
+
|
|
432
|
+
self.qos_mock.get.return_value = self.qos_spec
|
|
433
|
+
# Get the command object to test
|
|
434
|
+
self.cmd = qos_specs.UnsetQos(self.app, None)
|
|
435
|
+
|
|
436
|
+
def test_qos_unset_with_properties(self):
|
|
437
|
+
arglist = [
|
|
438
|
+
'--property',
|
|
439
|
+
'iops',
|
|
440
|
+
'--property',
|
|
441
|
+
'foo',
|
|
442
|
+
self.qos_spec.id,
|
|
443
|
+
]
|
|
444
|
+
verifylist = [
|
|
445
|
+
('property', ['iops', 'foo']),
|
|
446
|
+
('qos_spec', self.qos_spec.id),
|
|
447
|
+
]
|
|
448
|
+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
|
449
|
+
|
|
450
|
+
result = self.cmd.take_action(parsed_args)
|
|
451
|
+
|
|
452
|
+
self.qos_mock.unset_keys.assert_called_with(
|
|
453
|
+
self.qos_spec.id, ['iops', 'foo']
|
|
454
|
+
)
|
|
455
|
+
self.assertIsNone(result)
|
|
@@ -495,6 +495,7 @@ class TestVolumeAttachmentList(TestVolumeAttachment):
|
|
|
495
495
|
},
|
|
496
496
|
marker=None,
|
|
497
497
|
limit=None,
|
|
498
|
+
max_items=None,
|
|
498
499
|
)
|
|
499
500
|
self.assertEqual(self.columns, columns)
|
|
500
501
|
self.assertCountEqual(tuple(self.data), data)
|
|
@@ -535,6 +536,7 @@ class TestVolumeAttachmentList(TestVolumeAttachment):
|
|
|
535
536
|
},
|
|
536
537
|
marker='volume-attachment-id',
|
|
537
538
|
limit=2,
|
|
539
|
+
max_items=None,
|
|
538
540
|
)
|
|
539
541
|
self.assertEqual(self.columns, columns)
|
|
540
542
|
self.assertCountEqual(tuple(self.data), data)
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
3
|
+
# not use this file except in compliance with the License. You may obtain
|
|
4
|
+
# a copy of the License at
|
|
5
|
+
#
|
|
6
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
#
|
|
8
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
10
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
11
|
+
# License for the specific language governing permissions and limitations
|
|
12
|
+
# under the License.
|
|
13
|
+
#
|
|
14
|
+
|
|
15
|
+
from osc_lib.cli import format_columns
|
|
16
|
+
|
|
17
|
+
from openstackclient.tests.unit.volume.v3 import fakes as volume_fakes
|
|
18
|
+
from openstackclient.volume.v3 import volume_backend
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class TestShowVolumeCapability(volume_fakes.TestVolume):
|
|
22
|
+
"""Test backend capability functionality."""
|
|
23
|
+
|
|
24
|
+
# The capability to be listed
|
|
25
|
+
capability = volume_fakes.create_one_capability()
|
|
26
|
+
|
|
27
|
+
def setUp(self):
|
|
28
|
+
super().setUp()
|
|
29
|
+
|
|
30
|
+
# Assign return value to capabilities mock
|
|
31
|
+
self.volume_sdk_client.get_capabilities.return_value = self.capability
|
|
32
|
+
|
|
33
|
+
# Get the command object to test
|
|
34
|
+
self.cmd = volume_backend.ShowCapability(self.app, None)
|
|
35
|
+
|
|
36
|
+
def test_capability_show(self):
|
|
37
|
+
self.set_volume_api_version('3.0')
|
|
38
|
+
|
|
39
|
+
arglist = [
|
|
40
|
+
'fake',
|
|
41
|
+
]
|
|
42
|
+
verifylist = [
|
|
43
|
+
('host', 'fake'),
|
|
44
|
+
]
|
|
45
|
+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
|
46
|
+
|
|
47
|
+
# In base command class Lister in cliff, abstract method take_action()
|
|
48
|
+
# returns a tuple containing the column names and an iterable
|
|
49
|
+
# containing the data to be listed.
|
|
50
|
+
columns, data = self.cmd.take_action(parsed_args)
|
|
51
|
+
|
|
52
|
+
expected_columns = [
|
|
53
|
+
'Title',
|
|
54
|
+
'Key',
|
|
55
|
+
'Type',
|
|
56
|
+
'Description',
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
# confirming if all expected columns are present in the result.
|
|
60
|
+
self.assertEqual(expected_columns, columns)
|
|
61
|
+
|
|
62
|
+
capabilities = [
|
|
63
|
+
'Compression',
|
|
64
|
+
'Replication',
|
|
65
|
+
'QoS',
|
|
66
|
+
'Thin Provisioning',
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
# confirming if all expected values are present in the result.
|
|
70
|
+
for cap in data:
|
|
71
|
+
self.assertIn(cap[0], capabilities)
|
|
72
|
+
|
|
73
|
+
# checking if proper call was made to get capabilities
|
|
74
|
+
self.volume_sdk_client.get_capabilities.assert_called_with(
|
|
75
|
+
'fake',
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class TestListVolumePool(volume_fakes.TestVolume):
|
|
80
|
+
"""Tests for volume backend pool listing."""
|
|
81
|
+
|
|
82
|
+
# The pool to be listed
|
|
83
|
+
pools = volume_fakes.create_one_pool()
|
|
84
|
+
|
|
85
|
+
def setUp(self):
|
|
86
|
+
super().setUp()
|
|
87
|
+
|
|
88
|
+
self.volume_sdk_client.backend_pools.return_value = [self.pools]
|
|
89
|
+
|
|
90
|
+
# Get the command object to test
|
|
91
|
+
self.cmd = volume_backend.ListPool(self.app, None)
|
|
92
|
+
|
|
93
|
+
def test_pool_list(self):
|
|
94
|
+
self.set_volume_api_version('3.0')
|
|
95
|
+
|
|
96
|
+
arglist = []
|
|
97
|
+
verifylist = []
|
|
98
|
+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
|
99
|
+
|
|
100
|
+
# In base command class Lister in cliff, abstract method take_action()
|
|
101
|
+
# returns a tuple containing the column names and an iterable
|
|
102
|
+
# containing the data to be listed.
|
|
103
|
+
columns, data = self.cmd.take_action(parsed_args)
|
|
104
|
+
|
|
105
|
+
expected_columns = [
|
|
106
|
+
'Name',
|
|
107
|
+
]
|
|
108
|
+
|
|
109
|
+
# confirming if all expected columns are present in the result.
|
|
110
|
+
self.assertEqual(expected_columns, columns)
|
|
111
|
+
|
|
112
|
+
datalist = ((self.pools.name,),)
|
|
113
|
+
|
|
114
|
+
# confirming if all expected values are present in the result.
|
|
115
|
+
self.assertEqual(datalist, tuple(data))
|
|
116
|
+
|
|
117
|
+
# checking if proper call was made to list pools
|
|
118
|
+
self.volume_sdk_client.backend_pools.assert_called_with(
|
|
119
|
+
detailed=False,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
# checking if long columns are present in output
|
|
123
|
+
self.assertNotIn("total_volumes", columns)
|
|
124
|
+
self.assertNotIn("storage_protocol", columns)
|
|
125
|
+
|
|
126
|
+
def test_service_list_with_long_option(self):
|
|
127
|
+
self.set_volume_api_version('3.0')
|
|
128
|
+
|
|
129
|
+
arglist = ['--long']
|
|
130
|
+
verifylist = [('long', True)]
|
|
131
|
+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
|
132
|
+
|
|
133
|
+
# In base command class Lister in cliff, abstract method take_action()
|
|
134
|
+
# returns a tuple containing the column names and an iterable
|
|
135
|
+
# containing the data to be listed.
|
|
136
|
+
columns, data = self.cmd.take_action(parsed_args)
|
|
137
|
+
|
|
138
|
+
expected_columns = [
|
|
139
|
+
'Name',
|
|
140
|
+
'Capabilities',
|
|
141
|
+
]
|
|
142
|
+
|
|
143
|
+
# confirming if all expected columns are present in the result.
|
|
144
|
+
self.assertEqual(expected_columns, columns)
|
|
145
|
+
|
|
146
|
+
datalist = (
|
|
147
|
+
(
|
|
148
|
+
self.pools.name,
|
|
149
|
+
format_columns.DictColumn(self.pools.capabilities),
|
|
150
|
+
),
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
# confirming if all expected values are present in the result.
|
|
154
|
+
self.assertEqual(datalist, tuple(data))
|
|
155
|
+
|
|
156
|
+
self.volume_sdk_client.backend_pools.assert_called_with(
|
|
157
|
+
detailed=True,
|
|
158
|
+
)
|
|
@@ -393,6 +393,7 @@ class TestBackupList(volume_fakes.TestVolume):
|
|
|
393
393
|
all_tenants=False,
|
|
394
394
|
marker=None,
|
|
395
395
|
limit=None,
|
|
396
|
+
max_items=None,
|
|
396
397
|
project_id=None,
|
|
397
398
|
)
|
|
398
399
|
self.assertEqual(self.columns, columns)
|
|
@@ -444,6 +445,7 @@ class TestBackupList(volume_fakes.TestVolume):
|
|
|
444
445
|
all_tenants=True,
|
|
445
446
|
marker=self.backups[0].id,
|
|
446
447
|
limit=3,
|
|
448
|
+
max_items=None,
|
|
447
449
|
project_id=project.id,
|
|
448
450
|
)
|
|
449
451
|
self.assertEqual(self.columns_long, columns)
|
|
@@ -494,9 +496,7 @@ class TestBackupRestore(volume_fakes.TestVolume):
|
|
|
494
496
|
|
|
495
497
|
columns, data = self.cmd.take_action(parsed_args)
|
|
496
498
|
self.volume_sdk_client.restore_backup.assert_called_with(
|
|
497
|
-
self.backup.id,
|
|
498
|
-
volume_id=None,
|
|
499
|
-
name=None,
|
|
499
|
+
self.backup.id, volume=None, name=None
|
|
500
500
|
)
|
|
501
501
|
|
|
502
502
|
self.assertEqual(self.columns, columns)
|
|
@@ -518,9 +518,7 @@ class TestBackupRestore(volume_fakes.TestVolume):
|
|
|
518
518
|
|
|
519
519
|
columns, data = self.cmd.take_action(parsed_args)
|
|
520
520
|
self.volume_sdk_client.restore_backup.assert_called_with(
|
|
521
|
-
self.backup.id,
|
|
522
|
-
volume_id=None,
|
|
523
|
-
name=self.backup.volume_id,
|
|
521
|
+
self.backup.id, volume=None, name=self.backup.volume_id
|
|
524
522
|
)
|
|
525
523
|
|
|
526
524
|
self.assertEqual(self.columns, columns)
|
|
@@ -541,9 +539,7 @@ class TestBackupRestore(volume_fakes.TestVolume):
|
|
|
541
539
|
|
|
542
540
|
columns, data = self.cmd.take_action(parsed_args)
|
|
543
541
|
self.volume_sdk_client.restore_backup.assert_called_with(
|
|
544
|
-
self.backup.id,
|
|
545
|
-
volume_id=self.volume.id,
|
|
546
|
-
name=None,
|
|
542
|
+
self.backup.id, volume=self.volume.id, name=None
|
|
547
543
|
)
|
|
548
544
|
|
|
549
545
|
self.assertEqual(self.columns, columns)
|