Skip to content

Commit 423f203

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "volume: Add v3 volume backend support"
2 parents 2545dc5 + 59e8676 commit 423f203

4 files changed

Lines changed: 292 additions & 2 deletions

File tree

openstackclient/tests/unit/volume/v3/fakes.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ def setUp(self):
140140

141141

142142
# TODO(stephenfin): Check if the responses are actually the same
143+
create_one_capability = volume_v2_fakes.create_one_capability
144+
create_one_pool = volume_v2_fakes.create_one_pool
143145
create_one_snapshot = volume_v2_fakes.create_one_snapshot
144146
create_one_service = volume_v2_fakes.create_one_service
145147

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
)
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
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+
"""Storage backend action implementations"""
16+
17+
import argparse
18+
from collections.abc import Iterable, Sequence
19+
from typing import Any
20+
21+
from openstack import utils as sdk_utils
22+
from osc_lib.cli import format_columns
23+
from osc_lib import utils
24+
25+
from openstackclient import command
26+
from openstackclient.i18n import _
27+
28+
29+
class ShowCapability(command.Lister):
30+
_description = _("Show capability command")
31+
32+
def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
33+
parser = super().get_parser(prog_name)
34+
parser.add_argument(
35+
"host",
36+
metavar="<host>",
37+
help=_("List capabilities of specified host (host@backend-name)"),
38+
)
39+
return parser
40+
41+
def take_action(
42+
self, parsed_args: argparse.Namespace
43+
) -> tuple[Sequence[str], Iterable[tuple[Any, ...]]]:
44+
volume_client = sdk_utils.ensure_service_version(
45+
self.app.client_manager.sdk_connection.volume, '3'
46+
)
47+
48+
columns = [
49+
'Title',
50+
'Key',
51+
'Type',
52+
'Description',
53+
]
54+
55+
data = volume_client.get_capabilities(parsed_args.host)
56+
57+
# The get capabilities API is... interesting. We only want the names of
58+
# the capabilities that can set for a backend through extra specs, so
59+
# we need to extract out that part of the mess that is returned.
60+
print_data = []
61+
keys = data.properties
62+
for key in keys:
63+
# Stuff the key into the details to make it easier to output
64+
capability_data = data.properties[key]
65+
capability_data['key'] = key
66+
print_data.append(capability_data)
67+
68+
return (
69+
columns,
70+
(
71+
utils.get_dict_properties(
72+
s,
73+
columns,
74+
)
75+
for s in print_data
76+
),
77+
)
78+
79+
80+
class ListPool(command.Lister):
81+
_description = _("List pool command")
82+
83+
def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
84+
parser = super().get_parser(prog_name)
85+
parser.add_argument(
86+
"--long",
87+
action="store_true",
88+
default=False,
89+
help=_("Show detailed information about pools."),
90+
)
91+
# TODO(smcginnis): Starting with Cinder microversion 3.33, user is also
92+
# able to pass in --filters with a <key>=<value> pair to filter on.
93+
return parser
94+
95+
def take_action(
96+
self, parsed_args: argparse.Namespace
97+
) -> tuple[Sequence[str], Iterable[tuple[Any, ...]]]:
98+
volume_client = sdk_utils.ensure_service_version(
99+
self.app.client_manager.sdk_connection.volume, '3'
100+
)
101+
102+
if parsed_args.long:
103+
columns = [
104+
'name',
105+
'capabilities',
106+
]
107+
108+
headers = [
109+
'Name',
110+
'Capabilities',
111+
]
112+
else:
113+
columns = [
114+
'Name',
115+
]
116+
headers = columns
117+
118+
data = volume_client.backend_pools(detailed=parsed_args.long)
119+
formatters = {'capabilities': format_columns.DictColumn}
120+
return (
121+
headers,
122+
(
123+
utils.get_item_properties(
124+
s,
125+
columns,
126+
formatters=formatters,
127+
)
128+
for s in data
129+
),
130+
)

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -717,8 +717,8 @@ volume_backup_restore = "openstackclient.volume.v3.volume_backup:RestoreVolumeBa
717717
volume_backup_set = "openstackclient.volume.v3.volume_backup:SetVolumeBackup"
718718
volume_backup_unset = "openstackclient.volume.v3.volume_backup:UnsetVolumeBackup"
719719
volume_backup_show = "openstackclient.volume.v3.volume_backup:ShowVolumeBackup"
720-
volume_backend_capability_show = "openstackclient.volume.v2.volume_backend:ShowCapability"
721-
volume_backend_pool_list = "openstackclient.volume.v2.volume_backend:ListPool"
720+
volume_backend_capability_show = "openstackclient.volume.v3.volume_backend:ShowCapability"
721+
volume_backend_pool_list = "openstackclient.volume.v3.volume_backend:ListPool"
722722
volume_backup_record_export = "openstackclient.volume.v2.backup_record:ExportBackupRecord"
723723
volume_backup_record_import = "openstackclient.volume.v2.backup_record:ImportBackupRecord"
724724
volume_group_create = "openstackclient.volume.v3.volume_group:CreateVolumeGroup"

0 commit comments

Comments
 (0)