Merge "Add parent field to project creation"
This commit is contained in:
commit
634004f33e
doc/source/command-objects
openstackclient
@ -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
|
||||||
|
@ -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)))
|
||||||
|
|
||||||
|
|
||||||
|
@ -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'
|
||||||
|
|
||||||
|
@ -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):
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user