summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2016-01-04 19:09:31 +0000
committerGerrit Code Review <review@openstack.org>2016-01-04 19:09:31 +0000
commit774201b696a5348119f9cc059bc5ecfc4421752e (patch)
tree7c5fd9fa35c3c9fc1f1d30e3745056d8540e0f75
parent1b916da1a053c886c218bdb50516764613119784 (diff)
parenta2a63f19bf1d21c437f1b980aa209277fc947a89 (diff)
downloadpython-openstackclient-774201b696a5348119f9cc059bc5ecfc4421752e.tar.gz
Merge "Implementation for project unset cmd for python-openstackclient."
-rw-r--r--doc/source/command-objects/project.rst24
-rw-r--r--functional/tests/identity/v2/test_project.py8
-rw-r--r--openstackclient/identity/v2_0/project.py56
-rw-r--r--openstackclient/tests/identity/v2_0/test_project.py48
-rw-r--r--setup.cfg1
5 files changed, 133 insertions, 4 deletions
diff --git a/doc/source/command-objects/project.rst b/doc/source/command-objects/project.rst
index a342115d..f76f79ff 100644
--- a/doc/source/command-objects/project.rst
+++ b/doc/source/command-objects/project.rst
@@ -156,6 +156,8 @@ Set project properties
Set a property on :ref:`\<project\> <project_set-project>`
(repeat option to set multiple properties)
+ *Identity version 2 only*
+
.. _project_set-project:
.. describe:: <project>
@@ -195,3 +197,25 @@ Display project details
.. describe:: <project>
Project to display (name or ID)
+
+project unset
+-------------
+
+Unset project properties
+
+*Identity version 2 only*
+
+.. program:: project unset
+.. code:: bash
+
+ os project unset
+ --property <key> [--property <key> ...]
+ <project>
+
+.. option:: --property <key>
+
+ Property key to remove from project (repeat option to remove multiple properties)
+
+.. describe:: <project>
+
+ Project to modify (name or ID)
diff --git a/functional/tests/identity/v2/test_project.py b/functional/tests/identity/v2/test_project.py
index 88b282ef..3a5e8e81 100644
--- a/functional/tests/identity/v2/test_project.py
+++ b/functional/tests/identity/v2/test_project.py
@@ -68,12 +68,12 @@ class ProjectTests(test_identity.IdentityTests):
)
items = self.parse_show(raw_output)
fields = list(self.PROJECT_FIELDS)
- fields.extend(['k0'])
+ fields.extend(['properties'])
self.assert_show_fields(items, fields)
project = self.parse_show_as_object(raw_output)
self.assertEqual(new_project_name, project['name'])
self.assertEqual('False', project['enabled'])
- self.assertEqual('v0', project['k0'])
+ self.assertEqual("k0='v0'", project['properties'])
def test_project_show(self):
project_name = self._create_dummy_project()
@@ -81,4 +81,6 @@ class ProjectTests(test_identity.IdentityTests):
'project show %s' % project_name
)
items = self.parse_show(raw_output)
- self.assert_show_fields(items, self.PROJECT_FIELDS)
+ fields = list(self.PROJECT_FIELDS)
+ fields.extend(['properties'])
+ self.assert_show_fields(items, fields)
diff --git a/openstackclient/identity/v2_0/project.py b/openstackclient/identity/v2_0/project.py
index 065f0adf..4330c79c 100644
--- a/openstackclient/identity/v2_0/project.py
+++ b/openstackclient/identity/v2_0/project.py
@@ -282,4 +282,60 @@ class ShowProject(show.ShowOne):
# TODO(stevemar): Remove the line below when we support multitenancy
info.pop('parent_id', None)
+
+ # NOTE(stevemar): Property handling isn't really supported in Keystone
+ # and needs a lot of extra handling. Let's reserve the properties that
+ # the API has and handle the extra top level properties.
+ reserved = ('name', 'id', 'enabled', 'description')
+ properties = {}
+ for k, v in info.items():
+ if k not in reserved:
+ # If a key is not in `reserved` it's a property, pop it
+ info.pop(k)
+ # If a property has been "unset" it's `None`, so don't show it
+ if v is not None:
+ properties[k] = v
+
+ info['properties'] = utils.format_dict(properties)
return zip(*sorted(six.iteritems(info)))
+
+
+class UnsetProject(command.Command):
+ """Unset project properties"""
+
+ log = logging.getLogger(__name__ + '.UnsetProject')
+
+ def get_parser(self, prog_name):
+ parser = super(UnsetProject, self).get_parser(prog_name)
+ parser.add_argument(
+ 'project',
+ metavar='<project>',
+ help=_('Project to modify (name or ID)'),
+ )
+ parser.add_argument(
+ '--property',
+ metavar='<key>',
+ action='append',
+ default=[],
+ help=_('Unset a project property '
+ '(repeat option to unset multiple properties)'),
+ required=True,
+ )
+ return parser
+
+ @utils.log_method(log)
+ def take_action(self, parsed_args):
+ identity_client = self.app.client_manager.identity
+ project = utils.find_resource(
+ identity_client.tenants,
+ parsed_args.project,
+ )
+ if not parsed_args.property:
+ self.app.log.error("No changes requested\n")
+ else:
+ kwargs = project._info
+ for key in parsed_args.property:
+ if key in kwargs:
+ kwargs[key] = None
+ identity_client.tenants.update(project.id, **kwargs)
+ return
diff --git a/openstackclient/tests/identity/v2_0/test_project.py b/openstackclient/tests/identity/v2_0/test_project.py
index 16ab1957..e2100cd2 100644
--- a/openstackclient/tests/identity/v2_0/test_project.py
+++ b/openstackclient/tests/identity/v2_0/test_project.py
@@ -592,12 +592,58 @@ class TestProjectShow(TestProject):
identity_fakes.project_id,
)
- collist = ('description', 'enabled', 'id', 'name')
+ collist = ('description', 'enabled', 'id', 'name', 'properties')
self.assertEqual(collist, columns)
datalist = (
identity_fakes.project_description,
True,
identity_fakes.project_id,
identity_fakes.project_name,
+ '',
)
self.assertEqual(datalist, data)
+
+
+class TestProjectUnset(TestProject):
+
+ def setUp(self):
+ super(TestProjectUnset, self).setUp()
+
+ project_dict = {'fee': 'fi', 'fo': 'fum'}
+ project_dict.update(identity_fakes.PROJECT)
+ self.projects_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(project_dict),
+ loaded=True,
+ )
+
+ # Get the command object to test
+ self.cmd = project.UnsetProject(self.app, None)
+
+ def test_project_unset_key(self):
+ arglist = [
+ '--property', 'fee',
+ '--property', 'fo',
+ identity_fakes.project_name,
+ ]
+ verifylist = [
+ ('property', ['fee', 'fo']),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.run(parsed_args)
+ # Set expected values
+ kwargs = {
+ 'description': identity_fakes.project_description,
+ 'enabled': True,
+ 'fee': None,
+ 'fo': None,
+ 'id': identity_fakes.project_id,
+ 'name': identity_fakes.project_name,
+ }
+
+ self.projects_mock.update.assert_called_with(
+ identity_fakes.project_id,
+ **kwargs
+ )
diff --git a/setup.cfg b/setup.cfg
index 7f54fb1f..986a0771 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -163,6 +163,7 @@ openstack.identity.v2 =
project_list = openstackclient.identity.v2_0.project:ListProject
project_set = openstackclient.identity.v2_0.project:SetProject
project_show = openstackclient.identity.v2_0.project:ShowProject
+ project_unset = openstackclient.identity.v2_0.project:UnsetProject
role_add = openstackclient.identity.v2_0.role:AddRole
role_create = openstackclient.identity.v2_0.role:CreateRole