Skip to content

Commit 504cbd2

Browse files
committed
volume: Migrate 'volume create' to SDK
We need a shim for consistency group support, which we may eventually port to SDK but have not yet. Otherwise, this is rather straightforward. Change-Id: Ic880b7a64cde2148c266d549c4768c669ba3f501 Signed-off-by: Stephen Finucane <stephenfin@redhat.com> Depends-on: https://review.opendev.org/c/openstack/openstacksdk/+/943800
1 parent 51ecb5f commit 504cbd2

File tree

10 files changed

+1032
-689
lines changed

10 files changed

+1032
-689
lines changed

openstackclient/api/compute_v2.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def list_security_groups(compute_client, all_projects=None):
6464

6565

6666
def find_security_group(compute_client, name_or_id):
67-
"""Find the name for a given security group name or ID
67+
"""Find the security group for a given name or ID
6868
6969
https://docs.openstack.org/api-ref/compute/#show-security-group-details
7070
@@ -240,7 +240,7 @@ def list_networks(compute_client):
240240

241241

242242
def find_network(compute_client, name_or_id):
243-
"""Find the ID for a given network name or ID
243+
"""Find the network for a given name or ID
244244
245245
https://docs.openstack.org/api-ref/compute/#show-network-details
246246

openstackclient/api/volume_v2.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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+
"""Volume v2 API Library
14+
15+
A collection of wrappers for deprecated Block Storage v2 APIs that are not
16+
intentionally supported by SDK.
17+
"""
18+
19+
import http
20+
21+
from openstack import exceptions as sdk_exceptions
22+
from osc_lib import exceptions
23+
24+
25+
# consistency groups
26+
27+
28+
def find_consistency_group(compute_client, name_or_id):
29+
"""Find the consistency group for a given name or ID
30+
31+
https://docs.openstack.org/api-ref/block-storage/v3/#show-a-consistency-group-s-details
32+
33+
:param volume_client: A volume client
34+
:param name_or_id: The name or ID of the consistency group to look up
35+
:returns: A consistency group object
36+
:raises exception.NotFound: If a matching consistency group could not be
37+
found or more than one match was found
38+
"""
39+
response = compute_client.get(f'/consistencygroups/{name_or_id}')
40+
if response.status_code != http.HTTPStatus.NOT_FOUND:
41+
# there might be other, non-404 errors
42+
sdk_exceptions.raise_from_response(response)
43+
return response.json()['consistencygroup']
44+
45+
response = compute_client.get('/consistencygroups')
46+
sdk_exceptions.raise_from_response(response)
47+
found = None
48+
consistency_groups = response.json()['consistencygroups']
49+
for consistency_group in consistency_groups:
50+
if consistency_group['name'] == name_or_id:
51+
if found:
52+
raise exceptions.NotFound(
53+
f'multiple matches found for {name_or_id}'
54+
)
55+
found = consistency_group
56+
57+
if not found:
58+
raise exceptions.NotFound(f'{name_or_id} not found')
59+
60+
return found

openstackclient/api/volume_v3.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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+
"""Volume v3 API Library
14+
15+
A collection of wrappers for deprecated Block Storage v3 APIs that are not
16+
intentionally supported by SDK.
17+
"""
18+
19+
import http
20+
21+
from openstack import exceptions as sdk_exceptions
22+
from osc_lib import exceptions
23+
24+
25+
# consistency groups
26+
27+
28+
def find_consistency_group(compute_client, name_or_id):
29+
"""Find the consistency group for a given name or ID
30+
31+
https://docs.openstack.org/api-ref/block-storage/v3/#show-a-consistency-group-s-details
32+
33+
:param volume_client: A volume client
34+
:param name_or_id: The name or ID of the consistency group to look up
35+
:returns: A consistency group object
36+
:raises exception.NotFound: If a matching consistency group could not be
37+
found or more than one match was found
38+
"""
39+
response = compute_client.get(f'/consistencygroups/{name_or_id}')
40+
if response.status_code != http.HTTPStatus.NOT_FOUND:
41+
# there might be other, non-404 errors
42+
sdk_exceptions.raise_from_response(response)
43+
return response.json()['consistencygroup']
44+
45+
response = compute_client.get('/consistencygroups')
46+
sdk_exceptions.raise_from_response(response)
47+
found = None
48+
consistency_groups = response.json()['consistencygroups']
49+
for consistency_group in consistency_groups:
50+
if consistency_group['name'] == name_or_id:
51+
if found:
52+
raise exceptions.NotFound(
53+
f'multiple matches found for {name_or_id}'
54+
)
55+
found = consistency_group
56+
57+
if not found:
58+
raise exceptions.NotFound(f'{name_or_id} not found')
59+
60+
return found

openstackclient/tests/functional/volume/v3/test_volume.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def test_volume_set_and_unset(self):
124124
cmd_output["properties"],
125125
)
126126
self.assertEqual(
127-
'false',
127+
False,
128128
cmd_output["bootable"],
129129
)
130130
self.wait_for_status("volume", name, "available")
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
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+
14+
"""Volume v2 API Library Tests"""
15+
16+
import http
17+
from unittest import mock
18+
import uuid
19+
20+
from openstack.block_storage.v2 import _proxy
21+
from osc_lib import exceptions as osc_lib_exceptions
22+
23+
from openstackclient.api import volume_v2 as volume
24+
from openstackclient.tests.unit import fakes
25+
from openstackclient.tests.unit import utils
26+
27+
28+
class TestConsistencyGroup(utils.TestCase):
29+
def setUp(self):
30+
super().setUp()
31+
32+
self.volume_sdk_client = mock.Mock(_proxy.Proxy)
33+
34+
def test_find_consistency_group_by_id(self):
35+
cg_id = uuid.uuid4().hex
36+
cg_name = 'name-' + uuid.uuid4().hex
37+
data = {
38+
'consistencygroup': {
39+
'id': cg_id,
40+
'name': cg_name,
41+
'status': 'available',
42+
'availability_zone': 'az1',
43+
'created_at': '2015-09-16T09:28:52.000000',
44+
'description': 'description-' + uuid.uuid4().hex,
45+
'volume_types': ['123456'],
46+
}
47+
}
48+
self.volume_sdk_client.get.side_effect = [
49+
fakes.FakeResponse(data=data),
50+
]
51+
52+
result = volume.find_consistency_group(self.volume_sdk_client, cg_id)
53+
54+
self.volume_sdk_client.get.assert_has_calls(
55+
[
56+
mock.call(f'/consistencygroups/{cg_id}'),
57+
]
58+
)
59+
self.assertEqual(data['consistencygroup'], result)
60+
61+
def test_find_consistency_group_by_name(self):
62+
cg_id = uuid.uuid4().hex
63+
cg_name = 'name-' + uuid.uuid4().hex
64+
data = {
65+
'consistencygroups': [
66+
{
67+
'id': cg_id,
68+
'name': cg_name,
69+
}
70+
],
71+
}
72+
self.volume_sdk_client.get.side_effect = [
73+
fakes.FakeResponse(status_code=http.HTTPStatus.NOT_FOUND),
74+
fakes.FakeResponse(data=data),
75+
]
76+
77+
result = volume.find_consistency_group(self.volume_sdk_client, cg_name)
78+
79+
self.volume_sdk_client.get.assert_has_calls(
80+
[
81+
mock.call(f'/consistencygroups/{cg_name}'),
82+
mock.call('/consistencygroups'),
83+
]
84+
)
85+
self.assertEqual(data['consistencygroups'][0], result)
86+
87+
def test_find_consistency_group_not_found(self):
88+
data = {'consistencygroups': []}
89+
self.volume_sdk_client.get.side_effect = [
90+
fakes.FakeResponse(status_code=http.HTTPStatus.NOT_FOUND),
91+
fakes.FakeResponse(data=data),
92+
]
93+
self.assertRaises(
94+
osc_lib_exceptions.NotFound,
95+
volume.find_consistency_group,
96+
self.volume_sdk_client,
97+
'invalid-cg',
98+
)
99+
100+
def test_find_consistency_group_by_name_duplicate(self):
101+
cg_name = 'name-' + uuid.uuid4().hex
102+
data = {
103+
'consistencygroups': [
104+
{
105+
'id': uuid.uuid4().hex,
106+
'name': cg_name,
107+
},
108+
{
109+
'id': uuid.uuid4().hex,
110+
'name': cg_name,
111+
},
112+
],
113+
}
114+
self.volume_sdk_client.get.side_effect = [
115+
fakes.FakeResponse(status_code=http.HTTPStatus.NOT_FOUND),
116+
fakes.FakeResponse(data=data),
117+
]
118+
119+
self.assertRaises(
120+
osc_lib_exceptions.NotFound,
121+
volume.find_consistency_group,
122+
self.volume_sdk_client,
123+
cg_name,
124+
)
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
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+
14+
"""Volume v3 API Library Tests"""
15+
16+
import http
17+
from unittest import mock
18+
import uuid
19+
20+
from openstack.block_storage.v3 import _proxy
21+
from osc_lib import exceptions as osc_lib_exceptions
22+
23+
from openstackclient.api import volume_v3 as volume
24+
from openstackclient.tests.unit import fakes
25+
from openstackclient.tests.unit import utils
26+
27+
28+
class TestConsistencyGroup(utils.TestCase):
29+
def setUp(self):
30+
super().setUp()
31+
32+
self.volume_sdk_client = mock.Mock(_proxy.Proxy)
33+
34+
def test_find_consistency_group_by_id(self):
35+
cg_id = uuid.uuid4().hex
36+
cg_name = 'name-' + uuid.uuid4().hex
37+
data = {
38+
'consistencygroup': {
39+
'id': cg_id,
40+
'name': cg_name,
41+
'status': 'available',
42+
'availability_zone': 'az1',
43+
'created_at': '2015-09-16T09:28:52.000000',
44+
'description': 'description-' + uuid.uuid4().hex,
45+
'volume_types': ['123456'],
46+
}
47+
}
48+
self.volume_sdk_client.get.side_effect = [
49+
fakes.FakeResponse(data=data),
50+
]
51+
52+
result = volume.find_consistency_group(self.volume_sdk_client, cg_id)
53+
54+
self.volume_sdk_client.get.assert_has_calls(
55+
[
56+
mock.call(f'/consistencygroups/{cg_id}'),
57+
]
58+
)
59+
self.assertEqual(data['consistencygroup'], result)
60+
61+
def test_find_consistency_group_by_name(self):
62+
cg_id = uuid.uuid4().hex
63+
cg_name = 'name-' + uuid.uuid4().hex
64+
data = {
65+
'consistencygroups': [
66+
{
67+
'id': cg_id,
68+
'name': cg_name,
69+
}
70+
],
71+
}
72+
self.volume_sdk_client.get.side_effect = [
73+
fakes.FakeResponse(status_code=http.HTTPStatus.NOT_FOUND),
74+
fakes.FakeResponse(data=data),
75+
]
76+
77+
result = volume.find_consistency_group(self.volume_sdk_client, cg_name)
78+
79+
self.volume_sdk_client.get.assert_has_calls(
80+
[
81+
mock.call(f'/consistencygroups/{cg_name}'),
82+
mock.call('/consistencygroups'),
83+
]
84+
)
85+
self.assertEqual(data['consistencygroups'][0], result)
86+
87+
def test_find_consistency_group_not_found(self):
88+
data = {'consistencygroups': []}
89+
self.volume_sdk_client.get.side_effect = [
90+
fakes.FakeResponse(status_code=http.HTTPStatus.NOT_FOUND),
91+
fakes.FakeResponse(data=data),
92+
]
93+
self.assertRaises(
94+
osc_lib_exceptions.NotFound,
95+
volume.find_consistency_group,
96+
self.volume_sdk_client,
97+
'invalid-cg',
98+
)
99+
100+
def test_find_consistency_group_by_name_duplicate(self):
101+
cg_name = 'name-' + uuid.uuid4().hex
102+
data = {
103+
'consistencygroups': [
104+
{
105+
'id': uuid.uuid4().hex,
106+
'name': cg_name,
107+
},
108+
{
109+
'id': uuid.uuid4().hex,
110+
'name': cg_name,
111+
},
112+
],
113+
}
114+
self.volume_sdk_client.get.side_effect = [
115+
fakes.FakeResponse(status_code=http.HTTPStatus.NOT_FOUND),
116+
fakes.FakeResponse(data=data),
117+
]
118+
119+
self.assertRaises(
120+
osc_lib_exceptions.NotFound,
121+
volume.find_consistency_group,
122+
self.volume_sdk_client,
123+
cg_name,
124+
)

0 commit comments

Comments
 (0)