Migrate 'extension list' to SDK
Migrate the block storage aspects of this command to SDK. This means the 'extension list' command, like the 'availability zone list' command previously, is now using SDK entirely. While we're here, we also make some fixes to the unit tests for the network and compute aspects of the command. While we migrated the network and compute extension commands from neutronclient and novaclient respectively some time back, we never fully updated the tests. Do this now. Change-Id: I631a6a09dfd9d614b1dd7b322dcee8490a52cc43 Signed-off-by: Stephen Finucane <stephenfin@redhat.com> Depends-On: https://review.opendev.org/c/openstack/openstacksdk/+/885132
This commit is contained in:
parent
44cf963d8e
commit
b87b57551b
@ -22,15 +22,24 @@ from osc_lib import utils
|
||||
|
||||
from openstackclient.i18n import _
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _get_extension_columns(item):
|
||||
column_map = {
|
||||
'updated': 'updated_at',
|
||||
}
|
||||
hidden_columns = ['id', 'links', 'location']
|
||||
return utils.get_osc_show_columns_for_sdk_resource(
|
||||
item, column_map, hidden_columns
|
||||
)
|
||||
|
||||
|
||||
class ListExtension(command.Lister):
|
||||
_description = _("List API extensions")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListExtension, self).get_parser(prog_name)
|
||||
parser = super().get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--compute',
|
||||
action='store_true',
|
||||
@ -70,7 +79,7 @@ class ListExtension(command.Lister):
|
||||
'Alias',
|
||||
'Description',
|
||||
'Namespace',
|
||||
'Updated',
|
||||
'Updated At',
|
||||
'Links',
|
||||
)
|
||||
else:
|
||||
@ -105,12 +114,12 @@ class ListExtension(command.Lister):
|
||||
LOG.warning(message)
|
||||
|
||||
if parsed_args.volume or show_all:
|
||||
volume_client = self.app.client_manager.volume
|
||||
volume_client = self.app.client_manager.sdk_connection.volume
|
||||
try:
|
||||
data += volume_client.list_extensions.show_all()
|
||||
data += volume_client.extensions()
|
||||
except Exception:
|
||||
message = _(
|
||||
"Extensions list not supported by " "Block Storage API"
|
||||
"Extensions list not supported by Block Storage API"
|
||||
)
|
||||
LOG.warning(message)
|
||||
|
||||
@ -120,7 +129,7 @@ class ListExtension(command.Lister):
|
||||
data += network_client.extensions()
|
||||
except Exception:
|
||||
message = _(
|
||||
"Failed to retrieve extensions list " "from Network API"
|
||||
"Failed to retrieve extensions list from Network API"
|
||||
)
|
||||
LOG.warning(message)
|
||||
|
||||
@ -153,7 +162,12 @@ class ShowExtension(command.ShowOne):
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = self.app.client_manager.network
|
||||
ext = str(parsed_args.extension)
|
||||
obj = client.find_extension(ext, ignore_missing=False).to_dict()
|
||||
|
||||
return zip(*sorted(obj.items()))
|
||||
extension = client.find_extension(
|
||||
parsed_args.extension,
|
||||
ignore_missing=False,
|
||||
)
|
||||
|
||||
display_columns, columns = _get_extension_columns(extension)
|
||||
data = utils.get_dict_properties(extension, columns)
|
||||
return display_columns, data
|
||||
|
@ -20,7 +20,7 @@ from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes
|
||||
from openstackclient.tests.unit.network.v2 import fakes as network_fakes
|
||||
from openstackclient.tests.unit import utils
|
||||
from openstackclient.tests.unit import utils as tests_utils
|
||||
from openstackclient.tests.unit.volume.v2 import fakes as volume_fakes
|
||||
from openstackclient.tests.unit.volume.v3 import fakes as volume_fakes
|
||||
|
||||
|
||||
class TestExtension(utils.TestCommand):
|
||||
@ -37,26 +37,16 @@ class TestExtension(utils.TestCommand):
|
||||
|
||||
sdk_connection = mock.Mock()
|
||||
self.app.client_manager.sdk_connection = sdk_connection
|
||||
|
||||
self.compute_extensions_mock = sdk_connection.compute.extensions
|
||||
self.compute_extensions_mock.reset_mock()
|
||||
|
||||
volume_client = volume_fakes.FakeVolumeClient(
|
||||
endpoint=fakes.AUTH_URL,
|
||||
token=fakes.AUTH_TOKEN,
|
||||
)
|
||||
self.app.client_manager.volume = volume_client
|
||||
volume_client.list_extensions = mock.Mock()
|
||||
self.volume_extensions_mock = volume_client.list_extensions
|
||||
self.volume_extensions_mock = sdk_connection.volume.extensions
|
||||
self.volume_extensions_mock.reset_mock()
|
||||
|
||||
network_client = network_fakes.FakeNetworkV2Client(
|
||||
endpoint=fakes.AUTH_URL,
|
||||
token=fakes.AUTH_TOKEN,
|
||||
)
|
||||
self.app.client_manager.network = network_client
|
||||
network_client.extensions = mock.Mock()
|
||||
self.network_extensions_mock = network_client.extensions
|
||||
self.network_extensions_mock.reset_mock()
|
||||
self.app.client_manager.network = mock.Mock()
|
||||
self.network_client = self.app.client_manager.network
|
||||
self.network_client.extensions = mock.Mock()
|
||||
|
||||
|
||||
class TestExtensionList(TestExtension):
|
||||
@ -66,14 +56,14 @@ class TestExtensionList(TestExtension):
|
||||
'Alias',
|
||||
'Description',
|
||||
'Namespace',
|
||||
'Updated',
|
||||
'Updated At',
|
||||
'Links',
|
||||
)
|
||||
|
||||
volume_extension = volume_fakes.create_one_extension()
|
||||
identity_extension = identity_fakes.FakeExtension.create_one_extension()
|
||||
compute_extension = compute_fakes.create_one_extension()
|
||||
network_extension = network_fakes.FakeExtension.create_one_extension()
|
||||
network_extension = network_fakes.create_one_extension()
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
@ -82,10 +72,8 @@ class TestExtensionList(TestExtension):
|
||||
self.identity_extension
|
||||
]
|
||||
self.compute_extensions_mock.return_value = [self.compute_extension]
|
||||
self.volume_extensions_mock.show_all.return_value = [
|
||||
self.volume_extension
|
||||
]
|
||||
self.network_extensions_mock.return_value = [self.network_extension]
|
||||
self.volume_extensions_mock.return_value = [self.volume_extension]
|
||||
self.network_client.extensions.return_value = [self.network_extension]
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = extension.ListExtension(self.app, None)
|
||||
@ -134,8 +122,8 @@ class TestExtensionList(TestExtension):
|
||||
self._test_extension_list_helper(arglist, verifylist, datalist)
|
||||
self.identity_extensions_mock.list.assert_called_with()
|
||||
self.compute_extensions_mock.assert_called_with()
|
||||
self.volume_extensions_mock.show_all.assert_called_with()
|
||||
self.network_extensions_mock.assert_called_with()
|
||||
self.volume_extensions_mock.assert_called_with()
|
||||
self.network_client.extensions.assert_called_with()
|
||||
|
||||
def test_extension_list_long(self):
|
||||
arglist = [
|
||||
@ -150,7 +138,7 @@ class TestExtensionList(TestExtension):
|
||||
self.identity_extension.alias,
|
||||
self.identity_extension.description,
|
||||
self.identity_extension.namespace,
|
||||
self.identity_extension.updated,
|
||||
'',
|
||||
self.identity_extension.links,
|
||||
),
|
||||
(
|
||||
@ -158,31 +146,31 @@ class TestExtensionList(TestExtension):
|
||||
self.compute_extension.alias,
|
||||
self.compute_extension.description,
|
||||
self.compute_extension.namespace,
|
||||
self.compute_extension.updated,
|
||||
self.compute_extension.updated_at,
|
||||
self.compute_extension.links,
|
||||
),
|
||||
(
|
||||
self.volume_extension.name,
|
||||
self.volume_extension.alias,
|
||||
self.volume_extension.description,
|
||||
self.volume_extension.namespace,
|
||||
self.volume_extension.updated,
|
||||
'',
|
||||
self.volume_extension.updated_at,
|
||||
self.volume_extension.links,
|
||||
),
|
||||
(
|
||||
self.network_extension.name,
|
||||
self.network_extension.alias,
|
||||
self.network_extension.description,
|
||||
self.network_extension.namespace,
|
||||
self.network_extension.updated,
|
||||
'',
|
||||
self.network_extension.updated_at,
|
||||
self.network_extension.links,
|
||||
),
|
||||
)
|
||||
self._test_extension_list_helper(arglist, verifylist, datalist, True)
|
||||
self.identity_extensions_mock.list.assert_called_with()
|
||||
self.compute_extensions_mock.assert_called_with()
|
||||
self.volume_extensions_mock.show_all.assert_called_with()
|
||||
self.network_extensions_mock.assert_called_with()
|
||||
self.volume_extensions_mock.assert_called_with()
|
||||
self.network_client.extensions.assert_called_with()
|
||||
|
||||
def test_extension_list_identity(self):
|
||||
arglist = [
|
||||
@ -216,7 +204,7 @@ class TestExtensionList(TestExtension):
|
||||
),
|
||||
)
|
||||
self._test_extension_list_helper(arglist, verifylist, datalist)
|
||||
self.network_extensions_mock.assert_called_with()
|
||||
self.network_client.extensions.assert_called_with()
|
||||
|
||||
def test_extension_list_network_with_long(self):
|
||||
arglist = [
|
||||
@ -232,15 +220,15 @@ class TestExtensionList(TestExtension):
|
||||
self.network_extension.name,
|
||||
self.network_extension.alias,
|
||||
self.network_extension.description,
|
||||
self.network_extension.namespace,
|
||||
self.network_extension.updated,
|
||||
'',
|
||||
self.network_extension.updated_at,
|
||||
self.network_extension.links,
|
||||
),
|
||||
)
|
||||
self._test_extension_list_helper(
|
||||
arglist, verifylist, datalist, long=True
|
||||
)
|
||||
self.network_extensions_mock.assert_called_with()
|
||||
self.network_client.extensions.assert_called_with()
|
||||
|
||||
def test_extension_list_compute(self):
|
||||
arglist = [
|
||||
@ -282,7 +270,7 @@ class TestExtensionList(TestExtension):
|
||||
)
|
||||
self._test_extension_list_helper(arglist, verifylist, datalist)
|
||||
self.compute_extensions_mock.assert_called_with()
|
||||
self.network_extensions_mock.assert_called_with()
|
||||
self.network_client.extensions.assert_called_with()
|
||||
|
||||
def test_extension_list_volume(self):
|
||||
arglist = [
|
||||
@ -299,28 +287,24 @@ class TestExtensionList(TestExtension):
|
||||
),
|
||||
)
|
||||
self._test_extension_list_helper(arglist, verifylist, datalist)
|
||||
self.volume_extensions_mock.show_all.assert_called_with()
|
||||
self.volume_extensions_mock.assert_called_with()
|
||||
|
||||
|
||||
class TestExtensionShow(TestExtension):
|
||||
extension_details = network_fakes.FakeExtension.create_one_extension()
|
||||
extension_details = network_fakes.create_one_extension()
|
||||
|
||||
columns = (
|
||||
'alias',
|
||||
'description',
|
||||
'links',
|
||||
'name',
|
||||
'namespace',
|
||||
'updated',
|
||||
'updated_at',
|
||||
)
|
||||
|
||||
data = (
|
||||
extension_details.alias,
|
||||
extension_details.description,
|
||||
extension_details.links,
|
||||
extension_details.name,
|
||||
extension_details.namespace,
|
||||
extension_details.updated,
|
||||
extension_details.updated_at,
|
||||
)
|
||||
|
||||
def setUp(self):
|
||||
|
@ -21,6 +21,7 @@ import uuid
|
||||
from novaclient import api_versions
|
||||
from openstack.compute.v2 import aggregate as _aggregate
|
||||
from openstack.compute.v2 import availability_zone as _availability_zone
|
||||
from openstack.compute.v2 import extension as _extension
|
||||
from openstack.compute.v2 import flavor as _flavor
|
||||
from openstack.compute.v2 import hypervisor as _hypervisor
|
||||
from openstack.compute.v2 import keypair as _keypair
|
||||
@ -288,35 +289,33 @@ def create_agents(attrs=None, count=2):
|
||||
def create_one_extension(attrs=None):
|
||||
"""Create a fake extension.
|
||||
|
||||
:param dict attrs:
|
||||
A dictionary with all attributes
|
||||
:return:
|
||||
A FakeResource object with name, namespace, etc.
|
||||
:param dict attrs: A dictionary with all attributes
|
||||
:return: A fake openstack.compute.v2.extension.Extension object
|
||||
"""
|
||||
attrs = attrs or {}
|
||||
|
||||
# Set default attributes.
|
||||
extension_info = {
|
||||
'alias': 'NMN',
|
||||
'description': 'description-' + uuid.uuid4().hex,
|
||||
'links': [
|
||||
{
|
||||
"href": "https://github.com/openstack/compute-api",
|
||||
"type": "text/html",
|
||||
"rel": "describedby",
|
||||
}
|
||||
],
|
||||
'name': 'name-' + uuid.uuid4().hex,
|
||||
'namespace': (
|
||||
'http://docs.openstack.org/compute/ext/multinic/api/v1.1'
|
||||
),
|
||||
'description': 'description-' + uuid.uuid4().hex,
|
||||
'updated': '2014-01-07T12:00:0-00:00',
|
||||
'alias': 'NMN',
|
||||
'links': (
|
||||
'[{"href":'
|
||||
'"https://github.com/openstack/compute-api", "type":'
|
||||
' "text/html", "rel": "describedby"}]'
|
||||
),
|
||||
'updated_at': '2014-01-07T12:00:0-00:00',
|
||||
}
|
||||
|
||||
# Overwrite default attributes.
|
||||
extension_info.update(attrs)
|
||||
|
||||
extension = fakes.FakeResource(
|
||||
info=copy.deepcopy(extension_info), loaded=True
|
||||
)
|
||||
extension = _extension.Extension(**extension_info)
|
||||
return extension
|
||||
|
||||
|
||||
|
@ -23,6 +23,7 @@ from openstack.network.v2 import address_scope as _address_scope
|
||||
from openstack.network.v2 import agent as network_agent
|
||||
from openstack.network.v2 import auto_allocated_topology as allocated_topology
|
||||
from openstack.network.v2 import availability_zone as _availability_zone
|
||||
from openstack.network.v2 import extension as _extension
|
||||
from openstack.network.v2 import flavor as _flavor
|
||||
from openstack.network.v2 import local_ip as _local_ip
|
||||
from openstack.network.v2 import local_ip_association as _local_ip_association
|
||||
@ -101,21 +102,12 @@ class FakeNetworkV2Client(object):
|
||||
|
||||
class TestNetworkV2(utils.TestCommand):
|
||||
def setUp(self):
|
||||
super(TestNetworkV2, self).setUp()
|
||||
super().setUp()
|
||||
|
||||
self.namespace = argparse.Namespace()
|
||||
|
||||
self.app.client_manager.session = mock.Mock()
|
||||
|
||||
self.app.client_manager.network = FakeNetworkV2Client(
|
||||
endpoint=fakes.AUTH_URL,
|
||||
token=fakes.AUTH_TOKEN,
|
||||
)
|
||||
|
||||
self.app.client_manager.sdk_connection = mock.Mock()
|
||||
self.app.client_manager.sdk_connection.network = (
|
||||
self.app.client_manager.network
|
||||
)
|
||||
self.app.client_manager.network = mock.Mock()
|
||||
|
||||
self.app.client_manager.identity = (
|
||||
identity_fakes_v3.FakeIdentityv3Client(
|
||||
@ -125,37 +117,30 @@ class TestNetworkV2(utils.TestCommand):
|
||||
)
|
||||
|
||||
|
||||
class FakeExtension(object):
|
||||
"""Fake one or more extension."""
|
||||
def create_one_extension(attrs=None):
|
||||
"""Create a fake extension.
|
||||
|
||||
@staticmethod
|
||||
def create_one_extension(attrs=None):
|
||||
"""Create a fake extension.
|
||||
:param Dictionary attrs:
|
||||
A dictionary with all attributes
|
||||
:return:
|
||||
An Extension object with name, namespace, etc.
|
||||
"""
|
||||
attrs = attrs or {}
|
||||
|
||||
:param Dictionary attrs:
|
||||
A dictionary with all attributes
|
||||
:return:
|
||||
A FakeResource object with name, namespace, etc.
|
||||
"""
|
||||
attrs = attrs or {}
|
||||
# Set default attributes.
|
||||
extension_info = {
|
||||
'name': 'name-' + uuid.uuid4().hex,
|
||||
'description': 'description-' + uuid.uuid4().hex,
|
||||
'alias': 'Dystopian',
|
||||
'links': [],
|
||||
'updated_at': '2013-07-09T12:00:0-00:00',
|
||||
}
|
||||
|
||||
# Set default attributes.
|
||||
extension_info = {
|
||||
'name': 'name-' + uuid.uuid4().hex,
|
||||
'namespace': 'http://docs.openstack.org/network/',
|
||||
'description': 'description-' + uuid.uuid4().hex,
|
||||
'updated': '2013-07-09T12:00:0-00:00',
|
||||
'alias': 'Dystopian',
|
||||
'links': '[{"href":' '"https://github.com/os/network", "type"}]',
|
||||
}
|
||||
# Overwrite default attributes.
|
||||
extension_info.update(attrs)
|
||||
|
||||
# Overwrite default attributes.
|
||||
extension_info.update(attrs)
|
||||
|
||||
extension = fakes.FakeResource(
|
||||
info=copy.deepcopy(extension_info), loaded=True
|
||||
)
|
||||
return extension
|
||||
extension = _extension.Extension(**extension_info)
|
||||
return extension
|
||||
|
||||
|
||||
class FakeNetworkQosPolicy(object):
|
||||
|
@ -485,7 +485,7 @@ class TestDeleteRouter(TestRouter):
|
||||
class TestListRouter(TestRouter):
|
||||
# The routers going to be listed up.
|
||||
routers = network_fakes.FakeRouter.create_routers(count=3)
|
||||
_extensions = network_fakes.FakeExtension.create_one_extension()
|
||||
extensions = network_fakes.create_one_extension()
|
||||
|
||||
columns = (
|
||||
'ID',
|
||||
@ -572,7 +572,7 @@ class TestListRouter(TestRouter):
|
||||
return_value=self.routers
|
||||
)
|
||||
self.network.routers = mock.Mock(return_value=self.routers)
|
||||
self.network.find_extension = mock.Mock(return_value=self._extensions)
|
||||
self.network.find_extension = mock.Mock(return_value=self.extensions)
|
||||
self.network.find_router = mock.Mock(return_value=self.routers[0])
|
||||
self._testagent = network_fakes.create_one_network_agent()
|
||||
self.network.get_agent = mock.Mock(return_value=self._testagent)
|
||||
|
@ -56,8 +56,6 @@ class FakeVolumeClient:
|
||||
self.cgsnapshots.resource_class = fakes.FakeResource(None, {})
|
||||
self.consistencygroups = mock.Mock()
|
||||
self.consistencygroups.resource_class = fakes.FakeResource(None, {})
|
||||
self.extensions = mock.Mock()
|
||||
self.extensions.resource_class = fakes.FakeResource(None, {})
|
||||
self.limits = mock.Mock()
|
||||
self.limits.resource_class = fakes.FakeResource(None, {})
|
||||
self.pools = mock.Mock()
|
||||
@ -727,42 +725,6 @@ def get_consistency_group_snapshots(snapshots=None, count=2):
|
||||
return mock.Mock(side_effect=snapshots)
|
||||
|
||||
|
||||
def create_one_extension(attrs=None):
|
||||
"""Create a fake extension.
|
||||
|
||||
:param dict attrs:
|
||||
A dictionary with all attributes
|
||||
:return:
|
||||
A FakeResource object with name, namespace, etc.
|
||||
"""
|
||||
attrs = attrs or {}
|
||||
|
||||
# Set default attributes.
|
||||
extension_info = {
|
||||
'name': 'name-' + uuid.uuid4().hex,
|
||||
'namespace': (
|
||||
'http://docs.openstack.org/'
|
||||
'block-service/ext/scheduler-hints/api/v2'
|
||||
),
|
||||
'description': 'description-' + uuid.uuid4().hex,
|
||||
'updated': '2013-04-18T00:00:00+00:00',
|
||||
'alias': 'OS-SCH-HNT',
|
||||
'links': (
|
||||
'[{"href":'
|
||||
'"https://github.com/openstack/block-api", "type":'
|
||||
' "text/html", "rel": "describedby"}]'
|
||||
),
|
||||
}
|
||||
|
||||
# Overwrite default attributes.
|
||||
extension_info.update(attrs)
|
||||
|
||||
extension = fakes.FakeResource(
|
||||
info=copy.deepcopy(extension_info), loaded=True
|
||||
)
|
||||
return extension
|
||||
|
||||
|
||||
def create_one_qos(attrs=None):
|
||||
"""Create a fake Qos specification.
|
||||
|
||||
|
@ -17,6 +17,7 @@ import uuid
|
||||
from cinderclient import api_versions
|
||||
from openstack.block_storage.v3 import availability_zone as _availability_zone
|
||||
from openstack.block_storage.v3 import block_storage_summary as _summary
|
||||
from openstack.block_storage.v3 import extension as _extension
|
||||
|
||||
from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes
|
||||
from openstackclient.tests.unit import fakes
|
||||
@ -116,6 +117,37 @@ def create_availability_zones(attrs=None, count=2):
|
||||
return availability_zones
|
||||
|
||||
|
||||
def create_one_extension(attrs=None):
|
||||
"""Create a fake extension.
|
||||
|
||||
:param dict attrs: A dictionary with all attributes
|
||||
:return: A fake
|
||||
openstack.block_storage.v3.extension.Extension object
|
||||
"""
|
||||
attrs = attrs or {}
|
||||
|
||||
# Set default attributes.
|
||||
extension_info = {
|
||||
'alias': 'OS-SCH-HNT',
|
||||
'description': 'description-' + uuid.uuid4().hex,
|
||||
'links': [
|
||||
{
|
||||
"href": "https://github.com/openstack/block-api",
|
||||
"type": "text/html",
|
||||
"rel": "describedby",
|
||||
}
|
||||
],
|
||||
'name': 'name-' + uuid.uuid4().hex,
|
||||
'updated_at': '2013-04-18T00:00:00+00:00',
|
||||
}
|
||||
|
||||
# Overwrite default attributes.
|
||||
extension_info.update(attrs)
|
||||
|
||||
extension = _extension.Extension(**extension_info)
|
||||
return extension
|
||||
|
||||
|
||||
def create_one_cluster(attrs=None):
|
||||
"""Create a fake service cluster.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user