Merge "Add parent field to project creation"

This commit is contained in:
Jenkins
2015-04-30 03:16:20 +00:00
committed by Gerrit Code Review
4 changed files with 129 additions and 2 deletions

View File

@@ -25,6 +25,12 @@ Create new project
.. versionadded:: 3 .. versionadded:: 3
.. option:: --parent <project>
Parent of the project (name or ID)
.. versionadded:: 3
.. option:: --description <description> .. option:: --description <description>
Project description Project description

View File

@@ -46,6 +46,11 @@ class CreateProject(show.ShowOne):
metavar='<domain>', metavar='<domain>',
help='Domain owning the project (name or ID)', help='Domain owning the project (name or ID)',
) )
parser.add_argument(
'--parent',
metavar='<project>',
help='Parent of the project (name or ID)',
)
parser.add_argument( parser.add_argument(
'--description', '--description',
metavar='<description>', metavar='<description>',
@@ -85,6 +90,13 @@ class CreateProject(show.ShowOne):
domain = common.find_domain(identity_client, domain = common.find_domain(identity_client,
parsed_args.domain).id parsed_args.domain).id
parent = None
if parsed_args.parent:
parent = utils.find_resource(
identity_client.projects,
parsed_args.parent,
).id
enabled = True enabled = True
if parsed_args.disable: if parsed_args.disable:
enabled = False enabled = False
@@ -96,6 +108,7 @@ class CreateProject(show.ShowOne):
project = identity_client.projects.create( project = identity_client.projects.create(
name=parsed_args.name, name=parsed_args.name,
domain=domain, domain=domain,
parent=parent,
description=parsed_args.description, description=parsed_args.description,
enabled=enabled, enabled=enabled,
**kwargs **kwargs
@@ -110,8 +123,6 @@ class CreateProject(show.ShowOne):
raise e raise e
project._info.pop('links') project._info.pop('links')
# TODO(stevemar): Remove the line below when we support multitenancy
project._info.pop('parent_id', None)
return zip(*sorted(six.iteritems(project._info))) return zip(*sorted(six.iteritems(project._info)))

View File

@@ -135,6 +135,16 @@ REGION = {
'links': base_url + 'regions/' + region_id, 'links': base_url + 'regions/' + region_id,
} }
PROJECT_WITH_PARENT = {
'id': project_id + '-with-parent',
'name': project_name + ' and their parents',
'description': project_description + ' plus another four',
'enabled': True,
'domain_id': domain_id,
'parent_id': project_id,
'links': base_url + 'projects/' + (project_id + '-with-parent'),
}
role_id = 'r1' role_id = 'r1'
role_name = 'roller' role_name = 'roller'

View File

@@ -16,6 +16,7 @@
import copy import copy
import mock import mock
from openstackclient.common import exceptions
from openstackclient.identity.v3 import project from openstackclient.identity.v3 import project
from openstackclient.tests import fakes from openstackclient.tests import fakes
from openstackclient.tests.identity.v3 import fakes as identity_fakes from openstackclient.tests.identity.v3 import fakes as identity_fakes
@@ -60,6 +61,7 @@ class TestProjectCreate(TestProject):
identity_fakes.project_name, identity_fakes.project_name,
] ]
verifylist = [ verifylist = [
('parent', None),
('enable', False), ('enable', False),
('disable', False), ('disable', False),
('name', identity_fakes.project_name), ('name', identity_fakes.project_name),
@@ -75,6 +77,7 @@ class TestProjectCreate(TestProject):
'domain': None, 'domain': None,
'description': None, 'description': None,
'enabled': True, 'enabled': True,
'parent': None,
} }
# ProjectManager.create(name=, domain=, description=, # ProjectManager.create(name=, domain=, description=,
# enabled=, **kwargs) # enabled=, **kwargs)
@@ -103,6 +106,7 @@ class TestProjectCreate(TestProject):
('enable', False), ('enable', False),
('disable', False), ('disable', False),
('name', identity_fakes.project_name), ('name', identity_fakes.project_name),
('parent', None),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -115,6 +119,7 @@ class TestProjectCreate(TestProject):
'domain': None, 'domain': None,
'description': 'new desc', 'description': 'new desc',
'enabled': True, 'enabled': True,
'parent': None,
} }
# ProjectManager.create(name=, domain=, description=, # ProjectManager.create(name=, domain=, description=,
# enabled=, **kwargs) # enabled=, **kwargs)
@@ -143,6 +148,7 @@ class TestProjectCreate(TestProject):
('enable', False), ('enable', False),
('disable', False), ('disable', False),
('name', identity_fakes.project_name), ('name', identity_fakes.project_name),
('parent', None),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -155,6 +161,7 @@ class TestProjectCreate(TestProject):
'domain': identity_fakes.domain_id, 'domain': identity_fakes.domain_id,
'description': None, 'description': None,
'enabled': True, 'enabled': True,
'parent': None,
} }
# ProjectManager.create(name=, domain=, description=, # ProjectManager.create(name=, domain=, description=,
# enabled=, **kwargs) # enabled=, **kwargs)
@@ -183,6 +190,7 @@ class TestProjectCreate(TestProject):
('enable', False), ('enable', False),
('disable', False), ('disable', False),
('name', identity_fakes.project_name), ('name', identity_fakes.project_name),
('parent', None),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
mocker = mock.Mock() mocker = mock.Mock()
@@ -197,6 +205,7 @@ class TestProjectCreate(TestProject):
'domain': identity_fakes.domain_id, 'domain': identity_fakes.domain_id,
'description': None, 'description': None,
'enabled': True, 'enabled': True,
'parent': None,
} }
self.projects_mock.create.assert_called_with( self.projects_mock.create.assert_called_with(
**kwargs **kwargs
@@ -221,6 +230,7 @@ class TestProjectCreate(TestProject):
('enable', True), ('enable', True),
('disable', False), ('disable', False),
('name', identity_fakes.project_name), ('name', identity_fakes.project_name),
('parent', None),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -233,6 +243,7 @@ class TestProjectCreate(TestProject):
'domain': None, 'domain': None,
'description': None, 'description': None,
'enabled': True, 'enabled': True,
'parent': None,
} }
# ProjectManager.create(name=, domain=, description=, # ProjectManager.create(name=, domain=, description=,
# enabled=, **kwargs) # enabled=, **kwargs)
@@ -260,6 +271,7 @@ class TestProjectCreate(TestProject):
('enable', False), ('enable', False),
('disable', True), ('disable', True),
('name', identity_fakes.project_name), ('name', identity_fakes.project_name),
('parent', None),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -272,6 +284,7 @@ class TestProjectCreate(TestProject):
'domain': None, 'domain': None,
'description': None, 'description': None,
'enabled': False, 'enabled': False,
'parent': None,
} }
# ProjectManager.create(name=, domain=, # ProjectManager.create(name=, domain=,
# description=, enabled=, **kwargs) # description=, enabled=, **kwargs)
@@ -311,6 +324,7 @@ class TestProjectCreate(TestProject):
'domain': None, 'domain': None,
'description': None, 'description': None,
'enabled': True, 'enabled': True,
'parent': None,
'fee': 'fi', 'fee': 'fi',
'fo': 'fum', 'fo': 'fum',
} }
@@ -331,6 +345,92 @@ class TestProjectCreate(TestProject):
) )
self.assertEqual(datalist, data) self.assertEqual(datalist, data)
def test_project_create_parent(self):
self.projects_mock.get.return_value = fakes.FakeResource(
None,
copy.deepcopy(identity_fakes.PROJECT),
loaded=True,
)
self.projects_mock.create.return_value = fakes.FakeResource(
None,
copy.deepcopy(identity_fakes.PROJECT_WITH_PARENT),
loaded=True,
)
arglist = [
'--domain', identity_fakes.PROJECT_WITH_PARENT['domain_id'],
'--parent', identity_fakes.PROJECT['name'],
identity_fakes.PROJECT_WITH_PARENT['name'],
]
verifylist = [
('domain', identity_fakes.PROJECT_WITH_PARENT['domain_id']),
('parent', identity_fakes.PROJECT['name']),
('enable', False),
('disable', False),
('name', identity_fakes.PROJECT_WITH_PARENT['name']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
kwargs = {
'name': identity_fakes.PROJECT_WITH_PARENT['name'],
'domain': identity_fakes.PROJECT_WITH_PARENT['domain_id'],
'parent': identity_fakes.PROJECT['id'],
'description': None,
'enabled': True,
}
self.projects_mock.create.assert_called_with(
**kwargs
)
collist = (
'description',
'domain_id',
'enabled',
'id',
'name',
'parent_id',
)
self.assertEqual(columns, collist)
datalist = (
identity_fakes.PROJECT_WITH_PARENT['description'],
identity_fakes.PROJECT_WITH_PARENT['domain_id'],
identity_fakes.PROJECT_WITH_PARENT['enabled'],
identity_fakes.PROJECT_WITH_PARENT['id'],
identity_fakes.PROJECT_WITH_PARENT['name'],
identity_fakes.PROJECT['id'],
)
self.assertEqual(data, datalist)
def test_project_create_invalid_parent(self):
self.projects_mock.resource_class.__name__ = 'Project'
self.projects_mock.get.side_effect = exceptions.NotFound(
'Invalid parent')
self.projects_mock.find.side_effect = exceptions.NotFound(
'Invalid parent')
arglist = [
'--domain', identity_fakes.domain_name,
'--parent', 'invalid',
identity_fakes.project_name,
]
verifylist = [
('domain', identity_fakes.domain_name),
('parent', 'invalid'),
('enable', False),
('disable', False),
('name', identity_fakes.project_name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.assertRaises(
exceptions.CommandError,
self.cmd.take_action,
parsed_args,
)
class TestProjectDelete(TestProject): class TestProjectDelete(TestProject):