diff options
Diffstat (limited to 'openstackclient')
| -rw-r--r-- | openstackclient/compute/v2/security_group.py | 5 | ||||
| -rw-r--r-- | openstackclient/identity/common.py | 97 | ||||
| -rw-r--r-- | openstackclient/shell.py | 18 | ||||
| -rw-r--r-- | openstackclient/tests/compute/v2/fakes.py | 6 | ||||
| -rw-r--r-- | openstackclient/tests/compute/v2/test_security_group.py | 197 | ||||
| -rw-r--r-- | openstackclient/volume/v1/backup.py | 2 |
6 files changed, 255 insertions, 70 deletions
diff --git a/openstackclient/compute/v2/security_group.py b/openstackclient/compute/v2/security_group.py index d4643438..55405810 100644 --- a/openstackclient/compute/v2/security_group.py +++ b/openstackclient/compute/v2/security_group.py @@ -81,9 +81,11 @@ class CreateSecurityGroup(show.ShowOne): compute_client = self.app.client_manager.compute + description = parsed_args.description or parsed_args.name + data = compute_client.security_groups.create( parsed_args.name, - parsed_args.description, + description, ) info = {} @@ -290,6 +292,7 @@ class CreateSecurityGroupRule(show.ShowOne): parser.add_argument( "--dst-port", metavar="<port-range>", + default=(0, 0), action=parseractions.RangeAction, help="Destination port, may be a range: 137:139 (default: 0; " "only required for proto tcp and udp)", diff --git a/openstackclient/identity/common.py b/openstackclient/identity/common.py index a1b46cb4..2cc68c8d 100644 --- a/openstackclient/identity/common.py +++ b/openstackclient/identity/common.py @@ -20,6 +20,7 @@ from keystoneclient.v3 import domains from keystoneclient.v3 import groups from keystoneclient.v3 import projects from keystoneclient.v3 import users + from openstackclient.common import exceptions from openstackclient.common import utils @@ -43,74 +44,58 @@ def find_service(identity_client, name_type_or_id): def find_domain(identity_client, name_or_id): - """Find a domain. + return _find_identity_resource(identity_client.domains, name_or_id, + domains.Domain) - If the user does not have permissions to access the v3 domain API, e.g., - if the user is a project admin, assume that the domain given is the id - rather than the name. This method is used by the project list command, - so errors accessing the domain will be ignored and if the user has - access to the project API, everything will work fine. - Closes bugs #1317478 and #1317485. - """ - try: - dom = utils.find_resource(identity_client.domains, name_or_id) - if dom is not None: - return dom - except identity_exc.Forbidden: - pass - return domains.Domain(None, {'id': name_or_id, 'name': name_or_id}) +def find_group(identity_client, name_or_id): + return _find_identity_resource(identity_client.groups, name_or_id, + groups.Group) -def find_group(identity_client, name_or_id): - """Find a group. +def find_project(identity_client, name_or_id): + return _find_identity_resource(identity_client.projects, name_or_id, + projects.Project) - If the user does not have permissions to to perform a list groups call, - e.g., if the user is a project admin, assume that the group given is the - id rather than the name. This method is used by the role add command to - allow a role to be assigned to a group by a project admin who does not - have permission to list groups. - """ - try: - group = utils.find_resource(identity_client.groups, name_or_id) - if group is not None: - return group - except identity_exc.Forbidden: - pass - return groups.Group(None, {'id': name_or_id, 'name': name_or_id}) +def find_user(identity_client, name_or_id): + return _find_identity_resource(identity_client.users, name_or_id, + users.User) -def find_project(identity_client, name_or_id): - """Find a project. - If the user does not have permissions to to perform a list projects - call, e.g., if the user is a project admin, assume that the project - given is the id rather than the name. This method is used by the role - add command to allow a role to be assigned to a user by a project admin - who does not have permission to list projects. - """ - try: - project = utils.find_resource(identity_client.projects, name_or_id) - if project is not None: - return project - except identity_exc.Forbidden: - pass - return projects.Project(None, {'id': name_or_id, 'name': name_or_id}) +def _find_identity_resource(identity_client_manager, name_or_id, + resource_type): + """Find a specific identity resource. + Using keystoneclient's manager, attempt to find a specific resource by its + name or ID. If Forbidden to find the resource (a common case if the user + does not have permission), then return the resource by creating a local + instance of keystoneclient's Resource. -def find_user(identity_client, name_or_id): - """Find a user. + The parameter identity_client_manager is a keystoneclient manager, + for example: keystoneclient.v3.users or keystoneclient.v3.projects. + + The parameter resource_type is a keystoneclient resource, for example: + keystoneclient.v3.users.User or keystoneclient.v3.projects.Project. + + :param identity_client_manager: the manager that contains the resource + :type identity_client_manager: `keystoneclient.base.CrudManager` + :param name_or_id: the resources's name or ID + :type name_or_id: string + :param resource_type: class that represents the resource type + :type resource_type: `keystoneclient.base.Resource` + + :returns: the resource in question + :rtype: `keystoneclient.base.Resource` - If the user does not have permissions to to perform a list users call, - e.g., if the user is a project admin, assume that the user given is the - id rather than the name. This method is used by the role add command to - allow a role to be assigned to a user by a project admin who does not - have permission to list users. """ + try: - user = utils.find_resource(identity_client.users, name_or_id) - if user is not None: - return user + identity_resource = utils.find_resource(identity_client_manager, + name_or_id) + if identity_resource is not None: + return identity_resource except identity_exc.Forbidden: pass - return users.User(None, {'id': name_or_id, 'name': name_or_id}) + + return resource_type(None, {'id': name_or_id, 'name': name_or_id}) diff --git a/openstackclient/shell.py b/openstackclient/shell.py index 00f4a3c9..5e291021 100644 --- a/openstackclient/shell.py +++ b/openstackclient/shell.py @@ -24,6 +24,7 @@ import warnings from cliff import app from cliff import command +from cliff import complete from cliff import help import openstackclient @@ -76,6 +77,7 @@ class OpenStackShell(app.App): # Some commands do not need authentication help.HelpCommand.auth_required = False + complete.CompleteCommand.auth_required = False super(OpenStackShell, self).__init__( description=__doc__.strip(), @@ -137,12 +139,11 @@ class OpenStackShell(app.App): # --debug forces traceback self.dump_stack_trace = True requests_log.setLevel(logging.DEBUG) - cliff_log.setLevel(logging.DEBUG) else: self.dump_stack_trace = False requests_log.setLevel(logging.ERROR) - cliff_log.setLevel(logging.ERROR) + cliff_log.setLevel(logging.ERROR) stevedore_log.setLevel(logging.ERROR) iso8601_log.setLevel(logging.ERROR) @@ -318,19 +319,12 @@ class OpenStackShell(app.App): cmd.__class__.__name__, ) if cmd.auth_required: - try: - # Trigger the Identity client to initialize - self.client_manager.auth_ref - except Exception as e: - self.log.warning("Possible error authenticating: " + str(e)) - pass + # Trigger the Identity client to initialize + self.client_manager.auth_ref return def clean_up(self, cmd, result, err): - self.log.debug('clean_up %s', cmd.__class__.__name__) - - if err: - self.log.debug('got an error: %s', err) + self.log.debug('clean_up %s: %s', cmd.__class__.__name__, err or '') # Process collected timing data if self.options.timing: diff --git a/openstackclient/tests/compute/v2/fakes.py b/openstackclient/tests/compute/v2/fakes.py index a22c1ce0..c18dea7e 100644 --- a/openstackclient/tests/compute/v2/fakes.py +++ b/openstackclient/tests/compute/v2/fakes.py @@ -16,6 +16,7 @@ import mock from openstackclient.tests import fakes +from openstackclient.tests.identity.v2_0 import fakes as identity_fakes from openstackclient.tests.image.v2 import fakes as image_fakes from openstackclient.tests.network.v2 import fakes as network_fakes from openstackclient.tests import utils @@ -85,6 +86,11 @@ class TestComputev2(utils.TestCommand): token=fakes.AUTH_TOKEN, ) + self.app.client_manager.identity = identity_fakes.FakeIdentityv2Client( + endpoint=fakes.AUTH_URL, + token=fakes.AUTH_TOKEN, + ) + self.app.client_manager.image = image_fakes.FakeImagev2Client( endpoint=fakes.AUTH_URL, token=fakes.AUTH_TOKEN, diff --git a/openstackclient/tests/compute/v2/test_security_group.py b/openstackclient/tests/compute/v2/test_security_group.py new file mode 100644 index 00000000..fdb659a8 --- /dev/null +++ b/openstackclient/tests/compute/v2/test_security_group.py @@ -0,0 +1,197 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import copy +import mock + +from openstackclient.compute.v2 import security_group +from openstackclient.tests.compute.v2 import fakes as compute_fakes +from openstackclient.tests import fakes +from openstackclient.tests.identity.v2_0 import fakes as identity_fakes + + +security_group_id = '11' +security_group_name = 'wide-open' +security_group_description = 'nothing but net' + +SECURITY_GROUP = { + 'id': security_group_id, + 'name': security_group_name, + 'description': security_group_description, + 'tenant_id': identity_fakes.project_id, +} + + +class FakeSecurityGroupResource(fakes.FakeResource): + + def get_keys(self): + return {'property': 'value'} + + +class TestSecurityGroup(compute_fakes.TestComputev2): + + def setUp(self): + super(TestSecurityGroup, self).setUp() + + self.secgroups_mock = mock.Mock() + self.secgroups_mock.resource_class = fakes.FakeResource(None, {}) + self.app.client_manager.compute.security_groups = self.secgroups_mock + self.secgroups_mock.reset_mock() + + self.projects_mock = mock.Mock() + self.projects_mock.resource_class = fakes.FakeResource(None, {}) + self.app.client_manager.identity.projects = self.projects_mock + self.projects_mock.reset_mock() + + +class TestSecurityGroupCreate(TestSecurityGroup): + + def setUp(self): + super(TestSecurityGroupCreate, self).setUp() + + self.secgroups_mock.create.return_value = FakeSecurityGroupResource( + None, + copy.deepcopy(SECURITY_GROUP), + loaded=True, + ) + + # Get the command object to test + self.cmd = security_group.CreateSecurityGroup(self.app, None) + + def test_security_group_create_no_options(self): + arglist = [ + security_group_name, + ] + verifylist = [ + ('name', security_group_name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + # SecurityGroupManager.create(name, description) + self.secgroups_mock.create.assert_called_with( + security_group_name, + security_group_name, + ) + + collist = ( + 'description', + 'id', + 'name', + 'tenant_id', + ) + self.assertEqual(collist, columns) + datalist = ( + security_group_description, + security_group_id, + security_group_name, + identity_fakes.project_id, + ) + self.assertEqual(datalist, data) + + def test_security_group_create_description(self): + arglist = [ + security_group_name, + '--description', security_group_description, + ] + verifylist = [ + ('name', security_group_name), + ('description', security_group_description), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + # SecurityGroupManager.create(name, description) + self.secgroups_mock.create.assert_called_with( + security_group_name, + security_group_description, + ) + + collist = ( + 'description', + 'id', + 'name', + 'tenant_id', + ) + self.assertEqual(collist, columns) + datalist = ( + security_group_description, + security_group_id, + security_group_name, + identity_fakes.project_id, + ) + self.assertEqual(datalist, data) + + +class TestSecurityGroupList(TestSecurityGroup): + + def setUp(self): + super(TestSecurityGroupList, self).setUp() + + self.secgroups_mock.list.return_value = [ + FakeSecurityGroupResource( + None, + copy.deepcopy(SECURITY_GROUP), + loaded=True, + ), + ] + + # Get the command object to test + self.cmd = security_group.ListSecurityGroup(self.app, None) + + def test_security_group_list_no_options(self): + self.projects_mock.list.return_value = [ + fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.PROJECT), + loaded=True, + ), + ] + + arglist = [] + verifylist = [ + ('all_projects', False), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + # Set expected values + kwargs = { + 'search_opts': { + 'all_tenants': False, + }, + } + + self.secgroups_mock.list.assert_called_with( + **kwargs + ) + + collist = ( + 'ID', + 'Name', + 'Description', + ) + self.assertEqual(collist, columns) + datalist = (( + security_group_id, + security_group_name, + security_group_description, + ), ) + self.assertEqual(datalist, tuple(data)) diff --git a/openstackclient/volume/v1/backup.py b/openstackclient/volume/v1/backup.py index 71c8ed38..03c63a05 100644 --- a/openstackclient/volume/v1/backup.py +++ b/openstackclient/volume/v1/backup.py @@ -64,7 +64,7 @@ class CreateBackup(show.ShowOne): parsed_args.volume).id backup = volume_client.backups.create( volume_id, - parsed_args.volume, + parsed_args.container, parsed_args.name, parsed_args.description ) |
