summaryrefslogtreecommitdiff
path: root/openstackclient
diff options
context:
space:
mode:
Diffstat (limited to 'openstackclient')
-rw-r--r--openstackclient/identity/v2_0/project.py9
-rw-r--r--openstackclient/identity/v3/group.py15
-rw-r--r--openstackclient/identity/v3/project.py9
-rw-r--r--openstackclient/network/sdk_utils.py23
-rw-r--r--openstackclient/network/v2/network_agent.py8
-rw-r--r--openstackclient/network/v2/subnet.py10
-rw-r--r--openstackclient/tests/functional/network/v2/test_router.py17
-rw-r--r--openstackclient/tests/functional/network/v2/test_subnet.py33
-rw-r--r--openstackclient/tests/unit/identity/v2_0/test_project.py36
-rw-r--r--openstackclient/tests/unit/identity/v3/fakes.py17
-rw-r--r--openstackclient/tests/unit/identity/v3/test_group.py17
-rw-r--r--openstackclient/tests/unit/identity/v3/test_project.py37
12 files changed, 197 insertions, 34 deletions
diff --git a/openstackclient/identity/v2_0/project.py b/openstackclient/identity/v2_0/project.py
index ca565d4d..04d422ec 100644
--- a/openstackclient/identity/v2_0/project.py
+++ b/openstackclient/identity/v2_0/project.py
@@ -150,6 +150,13 @@ class ListProject(command.Lister):
default=False,
help=_('List additional fields in output'),
)
+ parser.add_argument(
+ '--sort',
+ metavar='<key>[:<direction>]',
+ help=_('Sort output by selected keys and directions (asc or desc) '
+ '(default: asc), repeat this option to specify multiple '
+ 'keys and directions.'),
+ )
return parser
def take_action(self, parsed_args):
@@ -158,6 +165,8 @@ class ListProject(command.Lister):
else:
columns = ('ID', 'Name')
data = self.app.client_manager.identity.tenants.list()
+ if parsed_args.sort:
+ data = utils.sort_items(data, parsed_args.sort)
return (columns,
(utils.get_item_properties(
s, columns,
diff --git a/openstackclient/identity/v3/group.py b/openstackclient/identity/v3/group.py
index 2afdabc1..b5f5d8ad 100644
--- a/openstackclient/identity/v3/group.py
+++ b/openstackclient/identity/v3/group.py
@@ -102,12 +102,15 @@ class CheckUserInGroup(command.Command):
try:
identity_client.users.check_in_group(user_id, group_id)
- except Exception:
- msg = _("%(user)s not in group %(group)s\n") % {
- 'user': parsed_args.user,
- 'group': parsed_args.group,
- }
- sys.stderr.write(msg)
+ except ks_exc.http.HTTPClientError as e:
+ if e.http_status == 403 or e.http_status == 404:
+ msg = _("%(user)s not in group %(group)s\n") % {
+ 'user': parsed_args.user,
+ 'group': parsed_args.group,
+ }
+ sys.stderr.write(msg)
+ else:
+ raise e
else:
msg = _("%(user)s in group %(group)s\n") % {
'user': parsed_args.user,
diff --git a/openstackclient/identity/v3/project.py b/openstackclient/identity/v3/project.py
index 43eca2b5..473dda1a 100644
--- a/openstackclient/identity/v3/project.py
+++ b/openstackclient/identity/v3/project.py
@@ -194,6 +194,13 @@ class ListProject(command.Lister):
default=False,
help=_('List additional fields in output'),
)
+ parser.add_argument(
+ '--sort',
+ metavar='<key>[:<direction>]',
+ help=_('Sort output by selected keys and directions (asc or desc) '
+ '(default: asc), repeat this option to specify multiple '
+ 'keys and directions.'),
+ )
return parser
def take_action(self, parsed_args):
@@ -222,6 +229,8 @@ class ListProject(command.Lister):
kwargs['user'] = user_id
data = identity_client.projects.list(**kwargs)
+ if parsed_args.sort:
+ data = utils.sort_items(data, parsed_args.sort)
return (columns,
(utils.get_item_properties(
s, columns,
diff --git a/openstackclient/network/sdk_utils.py b/openstackclient/network/sdk_utils.py
index 7bd54e46..04f168be 100644
--- a/openstackclient/network/sdk_utils.py
+++ b/openstackclient/network/sdk_utils.py
@@ -13,8 +13,24 @@
import six
-# Get the OSC show command display and attribute columns for an SDK resource.
-def get_osc_show_columns_for_sdk_resource(sdk_resource, osc_column_map):
+def get_osc_show_columns_for_sdk_resource(
+ sdk_resource,
+ osc_column_map,
+ invisible_columns=[]
+):
+ """Get and filter the display and attribute columns for an SDK resource.
+
+ Common utility function for preparing the output of an OSC show command.
+ Some of the columns may need to get renamed, others made invisible.
+
+ :param sdk_resource: An SDK resource
+ :param osc_column_map: A hash of mappings for display column names
+ :param invisible_columns: A list of invisible column names
+
+ :returns: Two tuples containing the names of the display and attribute
+ columns
+ """
+
if getattr(sdk_resource, 'allow_get', None) is not None:
resource_dict = sdk_resource.to_dict(
body=True, headers=False, ignore_none=False)
@@ -24,6 +40,9 @@ def get_osc_show_columns_for_sdk_resource(sdk_resource, osc_column_map):
# Build the OSC column names to display for the SDK resource.
attr_map = {}
display_columns = list(resource_dict.keys())
+ for col_name in invisible_columns:
+ if col_name in display_columns:
+ display_columns.remove(col_name)
for sdk_attr, osc_attr in six.iteritems(osc_column_map):
if sdk_attr in display_columns:
attr_map[osc_attr] = sdk_attr
diff --git a/openstackclient/network/v2/network_agent.py b/openstackclient/network/v2/network_agent.py
index d429fa08..37ad9f06 100644
--- a/openstackclient/network/v2/network_agent.py
+++ b/openstackclient/network/v2/network_agent.py
@@ -89,10 +89,11 @@ class ListNetworkAgent(command.Lister):
parser.add_argument(
'--agent-type',
metavar='<agent-type>',
- choices=["dhcp", "open-vswitch", "linux-bridge", "ofa", "l3",
- "loadbalancer", "metering", "metadata", "macvtap", "nic"],
+ choices=["bgp", "dhcp", "open-vswitch", "linux-bridge", "ofa",
+ "l3", "loadbalancer", "metering", "metadata", "macvtap",
+ "nic"],
help=_("List only agents with the specified agent type. "
- "The supported agent types are: dhcp, open-vswitch, "
+ "The supported agent types are: bgp, dhcp, open-vswitch, "
"linux-bridge, ofa, l3, loadbalancer, metering, "
"metadata, macvtap, nic.")
)
@@ -125,6 +126,7 @@ class ListNetworkAgent(command.Lister):
)
key_value = {
+ 'bgp': 'BGP dynamic routing agent',
'dhcp': 'DHCP agent',
'open-vswitch': 'Open vSwitch agent',
'linux-bridge': 'Linux bridge agent',
diff --git a/openstackclient/network/v2/subnet.py b/openstackclient/network/v2/subnet.py
index 2771858b..403b4cd2 100644
--- a/openstackclient/network/v2/subnet.py
+++ b/openstackclient/network/v2/subnet.py
@@ -132,7 +132,13 @@ def _get_columns(item):
'subnet_pool_id': 'subnetpool_id',
'tenant_id': 'project_id',
}
- return sdk_utils.get_osc_show_columns_for_sdk_resource(item, column_map)
+ # Do not show this column when displaying a subnet
+ invisible_columns = ['use_default_subnetpool']
+ return sdk_utils.get_osc_show_columns_for_sdk_resource(
+ item,
+ column_map,
+ invisible_columns=invisible_columns
+ )
def convert_entries_to_nexthop(entries):
@@ -179,7 +185,7 @@ def _get_attrs(client_manager, parsed_args, is_create=True):
ignore_missing=False)
attrs['subnetpool_id'] = subnet_pool.id
if parsed_args.use_default_subnet_pool:
- attrs['use_default_subnetpool'] = True
+ attrs['use_default_subnet_pool'] = True
if parsed_args.prefix_length is not None:
attrs['prefixlen'] = parsed_args.prefix_length
if parsed_args.subnet_range is not None:
diff --git a/openstackclient/tests/functional/network/v2/test_router.py b/openstackclient/tests/functional/network/v2/test_router.py
index 443f68b2..aa708e0a 100644
--- a/openstackclient/tests/functional/network/v2/test_router.py
+++ b/openstackclient/tests/functional/network/v2/test_router.py
@@ -20,7 +20,7 @@ class RouterTests(base.TestCase):
"""Functional tests for router. """
def test_router_create_and_delete(self):
- """Test create options, delete"""
+ """Test create options, delete multiple"""
name1 = uuid.uuid4().hex
name2 = uuid.uuid4().hex
cmd_output = json.loads(self.openstack(
@@ -75,6 +75,8 @@ class RouterTests(base.TestCase):
'--disable ' +
name1
))
+
+ self.addCleanup(self.openstack, 'router delete ' + name1)
self.assertEqual(
name1,
cmd_output["name"],
@@ -92,6 +94,8 @@ class RouterTests(base.TestCase):
'--project ' + demo_project_id +
' ' + name2
))
+
+ self.addCleanup(self.openstack, 'router delete ' + name2)
self.assertEqual(
name2,
cmd_output["name"],
@@ -141,12 +145,8 @@ class RouterTests(base.TestCase):
self.assertIn(name1, names)
self.assertIn(name2, names)
- del_output = self.openstack(
- 'router delete ' + name1 + ' ' + name2)
- self.assertOutput('', del_output)
-
def test_router_set_show_unset(self):
- """Tests create router, set, unset, show, delete"""
+ """Tests create router, set, unset, show"""
name = uuid.uuid4().hex
new_name = name + "_"
@@ -155,6 +155,7 @@ class RouterTests(base.TestCase):
'--description aaaa ' +
name
))
+ self.addCleanup(self.openstack, 'router delete ' + new_name)
self.assertEqual(
name,
cmd_output["name"],
@@ -221,7 +222,3 @@ class RouterTests(base.TestCase):
new_name
))
self.assertIsNone(cmd_output["external_gateway_info"])
-
- del_output = self.openstack(
- 'router delete ' + new_name)
- self.assertOutput('', del_output)
diff --git a/openstackclient/tests/functional/network/v2/test_subnet.py b/openstackclient/tests/functional/network/v2/test_subnet.py
index 995a4979..61cffcde 100644
--- a/openstackclient/tests/functional/network/v2/test_subnet.py
+++ b/openstackclient/tests/functional/network/v2/test_subnet.py
@@ -37,7 +37,7 @@ class SubnetTests(base.TestCase):
cls.assertOutput('', raw_output)
def test_subnet_create_and_delete(self):
- """Test create, delete"""
+ """Test create, delete multiple"""
name1 = uuid.uuid4().hex
cmd = ('subnet create -f json --network ' +
self.NETWORK_NAME +
@@ -51,9 +51,22 @@ class SubnetTests(base.TestCase):
self.NETWORK_ID,
cmd_output["network_id"],
)
+ name2 = uuid.uuid4().hex
+ cmd = ('subnet create -f json --network ' +
+ self.NETWORK_NAME +
+ ' --subnet-range')
+ cmd_output = self._subnet_create(cmd, name2)
+ self.assertEqual(
+ name2,
+ cmd_output["name"],
+ )
+ self.assertEqual(
+ self.NETWORK_ID,
+ cmd_output["network_id"],
+ )
del_output = self.openstack(
- 'subnet delete ' + name1)
+ 'subnet delete ' + name1 + ' ' + name2)
self.assertOutput('', del_output)
def test_subnet_list(self):
@@ -64,6 +77,8 @@ class SubnetTests(base.TestCase):
'--network ' + self.NETWORK_NAME +
' --dhcp --subnet-range')
cmd_output = self._subnet_create(cmd, name1)
+
+ self.addCleanup(self.openstack, 'subnet delete ' + name1)
self.assertEqual(
name1,
cmd_output["name"],
@@ -86,6 +101,8 @@ class SubnetTests(base.TestCase):
' --ip-version 6 --no-dhcp ' +
'--subnet-range')
cmd_output = self._subnet_create(cmd, name2, is_type_ipv4=False)
+
+ self.addCleanup(self.openstack, 'subnet delete ' + name2)
self.assertEqual(
name2,
cmd_output["name"],
@@ -148,12 +165,8 @@ class SubnetTests(base.TestCase):
self.assertNotIn(name1, names)
self.assertIn(name2, names)
- del_output = self.openstack(
- 'subnet delete ' + name1 + ' ' + name2)
- self.assertOutput('', del_output)
-
def test_subnet_set_show_unset(self):
- """Test create subnet, set, unset, show, delete"""
+ """Test create subnet, set, unset, show"""
name = uuid.uuid4().hex
new_name = name + "_"
@@ -161,6 +174,8 @@ class SubnetTests(base.TestCase):
'--network ' + self.NETWORK_NAME +
' --description aaaa --subnet-range')
cmd_output = self._subnet_create(cmd, name)
+
+ self.addCleanup(self.openstack, 'subnet delete ' + new_name)
self.assertEqual(
name,
cmd_output["name"],
@@ -224,10 +239,6 @@ class SubnetTests(base.TestCase):
cmd_output["service_types"],
)
- del_output = self.openstack(
- 'subnet delete ' + new_name)
- self.assertOutput('', del_output)
-
def _subnet_create(self, cmd, name, is_type_ipv4=True):
# Try random subnet range for subnet creating
# Because we can not determine ahead of time what subnets are already
diff --git a/openstackclient/tests/unit/identity/v2_0/test_project.py b/openstackclient/tests/unit/identity/v2_0/test_project.py
index 4e1077db..c726f2a6 100644
--- a/openstackclient/tests/unit/identity/v2_0/test_project.py
+++ b/openstackclient/tests/unit/identity/v2_0/test_project.py
@@ -26,6 +26,7 @@ from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes
class TestProject(identity_fakes.TestIdentityv2):
fake_project = identity_fakes.FakeProject.create_one_project()
+ fake_projects = identity_fakes.FakeProject.create_projects()
columns = (
'description',
@@ -39,6 +40,12 @@ class TestProject(identity_fakes.TestIdentityv2):
fake_project.id,
fake_project.name,
)
+ datalists = (
+ (fake_projects[0].description, True,
+ fake_projects[0].id, fake_projects[0].name,),
+ (fake_projects[1].description, True,
+ fake_projects[1].id, fake_projects[1].name,),
+ )
def setUp(self):
super(TestProject, self).setUp()
@@ -386,6 +393,35 @@ class TestProjectList(TestProject):
), )
self.assertEqual(datalist, tuple(data))
+ def test_project_list_sort(self):
+ self.projects_mock.list.return_value = self.fake_projects
+
+ arglist = ['--sort', 'name:asc', ]
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ (columns, data) = self.cmd.take_action(parsed_args)
+ self.projects_mock.list.assert_called_with()
+
+ collist = ('ID', 'Name')
+ self.assertEqual(collist, columns)
+
+ if self.fake_projects[0].name > self.fake_projects[1].name:
+ datalists = (
+ (self.fake_projects[1].id, self.fake_projects[1].name),
+ (self.fake_projects[0].id, self.fake_projects[0].name),
+ )
+ else:
+ datalists = (
+ (self.fake_projects[0].id, self.fake_projects[0].name),
+ (self.fake_projects[1].id, self.fake_projects[1].name),
+ )
+
+ self.assertEqual(datalists, tuple(data))
+
class TestProjectSet(TestProject):
diff --git a/openstackclient/tests/unit/identity/v3/fakes.py b/openstackclient/tests/unit/identity/v3/fakes.py
index 75065e65..01b5dede 100644
--- a/openstackclient/tests/unit/identity/v3/fakes.py
+++ b/openstackclient/tests/unit/identity/v3/fakes.py
@@ -622,6 +622,23 @@ class FakeProject(object):
loaded=True)
return project
+ @staticmethod
+ def create_projects(attrs=None, count=2):
+ """Create multiple fake projects.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of projects to fake
+ :return:
+ A list of FakeResource objects faking the projects
+ """
+
+ projects = []
+ for i in range(0, count):
+ projects.append(FakeProject.create_one_project(attrs))
+ return projects
+
class FakeDomain(object):
"""Fake one or more domain."""
diff --git a/openstackclient/tests/unit/identity/v3/test_group.py b/openstackclient/tests/unit/identity/v3/test_group.py
index 00bd217d..5870e1db 100644
--- a/openstackclient/tests/unit/identity/v3/test_group.py
+++ b/openstackclient/tests/unit/identity/v3/test_group.py
@@ -115,6 +115,23 @@ class TestGroupCheckUser(TestGroup):
self.user.id, self.group.id)
self.assertIsNone(result)
+ def test_group_check_user_server_error(self):
+ def server_error(*args):
+ raise ks_exc.http.InternalServerError
+ self.users_mock.check_in_group.side_effect = server_error
+ arglist = [
+ self.group.name,
+ self.user.name,
+ ]
+ verifylist = [
+ ('group', self.group.name),
+ ('user', self.user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(ks_exc.http.InternalServerError,
+ self.cmd.take_action, parsed_args)
+
class TestGroupCreate(TestGroup):
diff --git a/openstackclient/tests/unit/identity/v3/test_project.py b/openstackclient/tests/unit/identity/v3/test_project.py
index b99eaf85..a27bf2a5 100644
--- a/openstackclient/tests/unit/identity/v3/test_project.py
+++ b/openstackclient/tests/unit/identity/v3/test_project.py
@@ -479,6 +479,7 @@ class TestProjectList(TestProject):
domain = identity_fakes.FakeDomain.create_one_domain()
project = identity_fakes.FakeProject.create_one_project(
attrs={'domain_id': domain.id})
+ projects = identity_fakes.FakeProject.create_projects()
columns = (
'ID',
@@ -490,6 +491,12 @@ class TestProjectList(TestProject):
project.name,
),
)
+ datalists = (
+ (projects[0].description, True,
+ projects[0].id, projects[0].name,),
+ (projects[1].description, True,
+ projects[1].id, projects[1].name,),
+ )
def setUp(self):
super(TestProjectList, self).setUp()
@@ -580,6 +587,36 @@ class TestProjectList(TestProject):
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
+ def test_project_list_sort(self):
+ self.projects_mock.list.return_value = self.projects
+
+ arglist = ['--sort', 'name:asc', ]
+ verifylist = []
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ (columns, data) = self.cmd.take_action(parsed_args)
+ self.projects_mock.list.assert_called_with()
+
+ collist = ('ID', 'Name')
+ self.assertEqual(collist, columns)
+
+ if self.projects[0].name > self.projects[1].name:
+ datalists = (
+ (self.projects[1].id, self.projects[1].name),
+ (self.projects[0].id, self.projects[0].name),
+ )
+ else:
+ datalists = (
+ (self.projects[0].id, self.projects[0].name),
+ (self.projects[1].id, self.projects[1].name),
+ )
+
+ self.assertEqual(datalists, tuple(data))
+
class TestProjectSet(TestProject):