summaryrefslogtreecommitdiff
path: root/openstackclient
diff options
context:
space:
mode:
Diffstat (limited to 'openstackclient')
-rw-r--r--openstackclient/identity/common.py24
-rw-r--r--openstackclient/identity/v3/domain.py9
-rw-r--r--openstackclient/identity/v3/project.py9
-rw-r--r--openstackclient/identity/v3/role.py10
-rw-r--r--openstackclient/tests/unit/identity/v3/test_domain.py110
-rw-r--r--openstackclient/tests/unit/identity/v3/test_project.py161
-rw-r--r--openstackclient/tests/unit/identity/v3/test_role.py162
7 files changed, 474 insertions, 11 deletions
diff --git a/openstackclient/identity/common.py b/openstackclient/identity/common.py
index 7be2a17b..e70d87d2 100644
--- a/openstackclient/identity/common.py
+++ b/openstackclient/identity/common.py
@@ -213,6 +213,15 @@ def _find_identity_resource(identity_client_manager, name_or_id,
return resource_type(None, {'id': name_or_id, 'name': name_or_id})
+def get_immutable_options(parsed_args):
+ options = {}
+ if parsed_args.immutable:
+ options['immutable'] = True
+ if parsed_args.no_immutable:
+ options['immutable'] = False
+ return options
+
+
def add_user_domain_option_to_parser(parser):
parser.add_argument(
'--user-domain',
@@ -261,3 +270,18 @@ def add_inherited_option_to_parser(parser):
help=_('Specifies if the role grant is inheritable to the sub '
'projects'),
)
+
+
+def add_resource_option_to_parser(parser):
+ enable_group = parser.add_mutually_exclusive_group()
+ enable_group.add_argument(
+ '--immutable',
+ action='store_true',
+ help=_('Make resource immutable. An immutable project may not '
+ 'be deleted or modified except to remove the immutable flag'),
+ )
+ enable_group.add_argument(
+ '--no-immutable',
+ action='store_true',
+ help=_('Make resource mutable (default)'),
+ )
diff --git a/openstackclient/identity/v3/domain.py b/openstackclient/identity/v3/domain.py
index dbcc97f6..e33fce05 100644
--- a/openstackclient/identity/v3/domain.py
+++ b/openstackclient/identity/v3/domain.py
@@ -60,6 +60,7 @@ class CreateDomain(command.ShowOne):
action='store_true',
help=_('Return existing domain'),
)
+ common.add_resource_option_to_parser(parser)
return parser
def take_action(self, parsed_args):
@@ -69,10 +70,13 @@ class CreateDomain(command.ShowOne):
if parsed_args.disable:
enabled = False
+ options = common.get_immutable_options(parsed_args)
+
try:
domain = identity_client.domains.create(
name=parsed_args.name,
description=parsed_args.description,
+ options=options,
enabled=enabled,
)
except ks_exc.Conflict:
@@ -163,6 +167,7 @@ class SetDomain(command.Command):
action='store_true',
help=_('Disable domain'),
)
+ common.add_resource_option_to_parser(parser)
return parser
def take_action(self, parsed_args):
@@ -180,6 +185,10 @@ class SetDomain(command.Command):
if parsed_args.disable:
kwargs['enabled'] = False
+ options = common.get_immutable_options(parsed_args)
+ if options:
+ kwargs['options'] = options
+
identity_client.domains.update(domain.id, **kwargs)
diff --git a/openstackclient/identity/v3/project.py b/openstackclient/identity/v3/project.py
index 9ecc70ef..e32da165 100644
--- a/openstackclient/identity/v3/project.py
+++ b/openstackclient/identity/v3/project.py
@@ -78,6 +78,7 @@ class CreateProject(command.ShowOne):
action='store_true',
help=_('Return existing project'),
)
+ common.add_resource_option_to_parser(parser)
tag.add_tag_option_to_parser_for_create(parser, _('project'))
return parser
@@ -99,6 +100,9 @@ class CreateProject(command.ShowOne):
enabled = True
if parsed_args.disable:
enabled = False
+
+ options = common.get_immutable_options(parsed_args)
+
kwargs = {}
if parsed_args.property:
kwargs = parsed_args.property.copy()
@@ -111,6 +115,7 @@ class CreateProject(command.ShowOne):
parent=parent,
description=parsed_args.description,
enabled=enabled,
+ options=options,
**kwargs
)
except ks_exc.Conflict:
@@ -317,6 +322,7 @@ class SetProject(command.Command):
help=_('Set a property on <project> '
'(repeat option to set multiple properties)'),
)
+ common.add_resource_option_to_parser(parser)
tag.add_tag_option_to_parser_for_set(parser, _('project'))
return parser
@@ -336,6 +342,9 @@ class SetProject(command.Command):
kwargs['enabled'] = True
if parsed_args.disable:
kwargs['enabled'] = False
+ options = common.get_immutable_options(parsed_args)
+ if options:
+ kwargs['options'] = options
if parsed_args.property:
kwargs.update(parsed_args.property)
tag.update_tags_in_args(parsed_args, project, kwargs)
diff --git a/openstackclient/identity/v3/role.py b/openstackclient/identity/v3/role.py
index 36f3f938..980ebf11 100644
--- a/openstackclient/identity/v3/role.py
+++ b/openstackclient/identity/v3/role.py
@@ -191,6 +191,7 @@ class CreateRole(command.ShowOne):
action='store_true',
help=_('Return existing role'),
)
+ common.add_resource_option_to_parser(parser)
return parser
def take_action(self, parsed_args):
@@ -201,10 +202,12 @@ class CreateRole(command.ShowOne):
domain_id = common.find_domain(identity_client,
parsed_args.domain).id
+ options = common.get_immutable_options(parsed_args)
+
try:
role = identity_client.roles.create(
name=parsed_args.name, domain=domain_id,
- description=parsed_args.description)
+ description=parsed_args.description, options=options)
except ks_exc.Conflict:
if parsed_args.or_show:
@@ -366,6 +369,7 @@ class SetRole(command.Command):
metavar='<name>',
help=_('Set role name'),
)
+ common.add_resource_option_to_parser(parser)
return parser
def take_action(self, parsed_args):
@@ -376,12 +380,14 @@ class SetRole(command.Command):
domain_id = common.find_domain(identity_client,
parsed_args.domain).id
+ options = common.get_immutable_options(parsed_args)
role = utils.find_resource(identity_client.roles,
parsed_args.role,
domain_id=domain_id)
identity_client.roles.update(role.id, name=parsed_args.name,
- description=parsed_args.description)
+ description=parsed_args.description,
+ options=options)
class ShowRole(command.ShowOne):
diff --git a/openstackclient/tests/unit/identity/v3/test_domain.py b/openstackclient/tests/unit/identity/v3/test_domain.py
index 014986e5..46f389e8 100644
--- a/openstackclient/tests/unit/identity/v3/test_domain.py
+++ b/openstackclient/tests/unit/identity/v3/test_domain.py
@@ -68,6 +68,7 @@ class TestDomainCreate(TestDomain):
kwargs = {
'name': self.domain.name,
'description': None,
+ 'options': {},
'enabled': True,
}
self.domains_mock.create.assert_called_with(
@@ -97,6 +98,7 @@ class TestDomainCreate(TestDomain):
kwargs = {
'name': self.domain.name,
'description': 'new desc',
+ 'options': {},
'enabled': True,
}
self.domains_mock.create.assert_called_with(
@@ -126,6 +128,7 @@ class TestDomainCreate(TestDomain):
kwargs = {
'name': self.domain.name,
'description': None,
+ 'options': {},
'enabled': True,
}
self.domains_mock.create.assert_called_with(
@@ -155,6 +158,7 @@ class TestDomainCreate(TestDomain):
kwargs = {
'name': self.domain.name,
'description': None,
+ 'options': {},
'enabled': False,
}
self.domains_mock.create.assert_called_with(
@@ -164,6 +168,66 @@ class TestDomainCreate(TestDomain):
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
+ def test_domain_create_with_immutable(self):
+ arglist = [
+ '--immutable',
+ self.domain.name,
+ ]
+ verifylist = [
+ ('immutable', True),
+ ('name', self.domain.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.domain.name,
+ 'description': None,
+ 'options': {'immutable': True},
+ 'enabled': True,
+ }
+ self.domains_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_domain_create_with_no_immutable(self):
+ arglist = [
+ '--no-immutable',
+ self.domain.name,
+ ]
+ verifylist = [
+ ('no_immutable', True),
+ ('name', self.domain.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.domain.name,
+ 'description': None,
+ 'options': {'immutable': False},
+ 'enabled': True,
+ }
+ self.domains_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
class TestDomainDelete(TestDomain):
@@ -354,6 +418,52 @@ class TestDomainSet(TestDomain):
)
self.assertIsNone(result)
+ def test_domain_set_immutable_option(self):
+ arglist = [
+ '--immutable',
+ self.domain.id,
+ ]
+ verifylist = [
+ ('immutable', True),
+ ('domain', self.domain.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'options': {'immutable': True},
+ }
+ self.domains_mock.update.assert_called_with(
+ self.domain.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_domain_set_no_immutable_option(self):
+ arglist = [
+ '--no-immutable',
+ self.domain.id,
+ ]
+ verifylist = [
+ ('no_immutable', True),
+ ('domain', self.domain.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'options': {'immutable': False},
+ }
+ self.domains_mock.update.assert_called_with(
+ self.domain.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
class TestDomainShow(TestDomain):
diff --git a/openstackclient/tests/unit/identity/v3/test_project.py b/openstackclient/tests/unit/identity/v3/test_project.py
index 466bea18..8852aa8e 100644
--- a/openstackclient/tests/unit/identity/v3/test_project.py
+++ b/openstackclient/tests/unit/identity/v3/test_project.py
@@ -98,7 +98,8 @@ class TestProjectCreate(TestProject):
'description': None,
'enabled': True,
'parent': None,
- 'tags': []
+ 'tags': [],
+ 'options': {},
}
# ProjectManager.create(name=, domain=, description=,
# enabled=, **kwargs)
@@ -156,7 +157,8 @@ class TestProjectCreate(TestProject):
'description': 'new desc',
'enabled': True,
'parent': None,
- 'tags': []
+ 'tags': [],
+ 'options': {},
}
# ProjectManager.create(name=, domain=, description=,
# enabled=, **kwargs)
@@ -194,7 +196,8 @@ class TestProjectCreate(TestProject):
'description': None,
'enabled': True,
'parent': None,
- 'tags': []
+ 'tags': [],
+ 'options': {},
}
# ProjectManager.create(name=, domain=, description=,
# enabled=, **kwargs)
@@ -232,7 +235,8 @@ class TestProjectCreate(TestProject):
'description': None,
'enabled': True,
'parent': None,
- 'tags': []
+ 'tags': [],
+ 'options': {},
}
self.projects_mock.create.assert_called_with(
**kwargs
@@ -266,7 +270,8 @@ class TestProjectCreate(TestProject):
'description': None,
'enabled': True,
'parent': None,
- 'tags': []
+ 'tags': [],
+ 'options': {},
}
# ProjectManager.create(name=, domain=, description=,
# enabled=, **kwargs)
@@ -302,7 +307,8 @@ class TestProjectCreate(TestProject):
'description': None,
'enabled': False,
'parent': None,
- 'tags': []
+ 'tags': [],
+ 'options': {},
}
# ProjectManager.create(name=, domain=,
# description=, enabled=, **kwargs)
@@ -339,7 +345,8 @@ class TestProjectCreate(TestProject):
'parent': None,
'fee': 'fi',
'fo': 'fum',
- 'tags': []
+ 'tags': [],
+ 'options': {},
}
# ProjectManager.create(name=, domain=, description=,
# enabled=, **kwargs)
@@ -380,7 +387,8 @@ class TestProjectCreate(TestProject):
'parent': self.parent.id,
'description': None,
'enabled': True,
- 'tags': []
+ 'tags': [],
+ 'options': {},
}
self.projects_mock.create.assert_called_with(
@@ -465,8 +473,89 @@ class TestProjectCreate(TestProject):
'description': None,
'enabled': True,
'parent': None,
- 'tags': ['foo']
+ 'tags': ['foo'],
+ 'options': {},
+ }
+ self.projects_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_project_create_with_immutable_option(self):
+ arglist = [
+ '--immutable',
+ self.project.name,
+ ]
+ verifylist = [
+ ('immutable', True),
+ ('description', None),
+ ('enable', False),
+ ('disable', False),
+ ('name', self.project.name),
+ ('parent', None),
+ ('tags', [])
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.project.name,
+ 'domain': None,
+ 'description': None,
+ 'enabled': True,
+ 'parent': None,
+ 'tags': [],
+ 'options': {'immutable': True},
}
+ # ProjectManager.create(name=, domain=, description=,
+ # enabled=, **kwargs)
+ self.projects_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.datalist, data)
+
+ def test_project_create_with_no_immutable_option(self):
+ arglist = [
+ '--no-immutable',
+ self.project.name,
+ ]
+ verifylist = [
+ ('no_immutable', True),
+ ('description', None),
+ ('enable', False),
+ ('disable', False),
+ ('name', self.project.name),
+ ('parent', None),
+ ('tags', [])
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': self.project.name,
+ 'domain': None,
+ 'description': None,
+ 'enabled': True,
+ 'parent': None,
+ 'tags': [],
+ 'options': {'immutable': False},
+ }
+ # ProjectManager.create(name=, domain=, description=,
+ # enabled=, **kwargs)
self.projects_mock.create.assert_called_with(
**kwargs
)
@@ -927,6 +1016,60 @@ class TestProjectSet(TestProject):
)
self.assertIsNone(result)
+ def test_project_set_with_immutable_option(self):
+ arglist = [
+ '--domain', self.project.domain_id,
+ '--immutable',
+ self.project.name,
+ ]
+ verifylist = [
+ ('domain', self.project.domain_id),
+ ('immutable', True),
+ ('enable', False),
+ ('disable', False),
+ ('project', self.project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'options': {'immutable': True},
+ }
+ self.projects_mock.update.assert_called_with(
+ self.project.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_project_set_with_no_immutable_option(self):
+ arglist = [
+ '--domain', self.project.domain_id,
+ '--no-immutable',
+ self.project.name,
+ ]
+ verifylist = [
+ ('domain', self.project.domain_id),
+ ('no_immutable', True),
+ ('enable', False),
+ ('disable', False),
+ ('project', self.project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'options': {'immutable': False},
+ }
+ self.projects_mock.update.assert_called_with(
+ self.project.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
class TestProjectShow(TestProject):
diff --git a/openstackclient/tests/unit/identity/v3/test_role.py b/openstackclient/tests/unit/identity/v3/test_role.py
index 4278ab1c..544da7c1 100644
--- a/openstackclient/tests/unit/identity/v3/test_role.py
+++ b/openstackclient/tests/unit/identity/v3/test_role.py
@@ -333,6 +333,7 @@ class TestRoleCreate(TestRole):
'domain': None,
'name': identity_fakes.role_name,
'description': None,
+ 'options': {},
}
# RoleManager.create(name=, domain=)
@@ -377,6 +378,7 @@ class TestRoleCreate(TestRole):
'domain': identity_fakes.domain_id,
'name': identity_fakes.ROLE_2['name'],
'description': None,
+ 'options': {},
}
# RoleManager.create(name=, domain=)
@@ -420,6 +422,97 @@ class TestRoleCreate(TestRole):
'description': identity_fakes.role_description,
'name': identity_fakes.ROLE_2['name'],
'domain': None,
+ 'options': {},
+ }
+
+ # RoleManager.create(name=, domain=)
+ self.roles_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ collist = ('domain', 'id', 'name')
+ self.assertEqual(collist, columns)
+ datalist = (
+ 'd1',
+ identity_fakes.ROLE_2['id'],
+ identity_fakes.ROLE_2['name'],
+ )
+ self.assertEqual(datalist, data)
+
+ def test_role_create_with_immutable_option(self):
+
+ self.roles_mock.create.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.ROLE_2),
+ loaded=True,
+ )
+ arglist = [
+ '--immutable',
+ identity_fakes.ROLE_2['name'],
+ ]
+ verifylist = [
+ ('immutable', True),
+ ('name', identity_fakes.ROLE_2['name']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+
+ 'options': {'immutable': True},
+ 'description': None,
+ 'name': identity_fakes.ROLE_2['name'],
+ 'domain': None,
+ }
+
+ # RoleManager.create(name=, domain=)
+ self.roles_mock.create.assert_called_with(
+ **kwargs
+ )
+
+ collist = ('domain', 'id', 'name')
+ self.assertEqual(collist, columns)
+ datalist = (
+ 'd1',
+ identity_fakes.ROLE_2['id'],
+ identity_fakes.ROLE_2['name'],
+ )
+ self.assertEqual(datalist, data)
+
+ def test_role_create_with_no_immutable_option(self):
+
+ self.roles_mock.create.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.ROLE_2),
+ loaded=True,
+ )
+ arglist = [
+ '--no-immutable',
+ identity_fakes.ROLE_2['name'],
+ ]
+ verifylist = [
+ ('no_immutable', True),
+ ('name', identity_fakes.ROLE_2['name']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+
+ 'options': {'immutable': False},
+ 'description': None,
+ 'name': identity_fakes.ROLE_2['name'],
+ 'domain': None,
}
# RoleManager.create(name=, domain=)
@@ -871,6 +964,7 @@ class TestRoleSet(TestRole):
kwargs = {
'name': 'over',
'description': None,
+ 'options': {},
}
# RoleManager.update(role, name=)
self.roles_mock.update.assert_called_with(
@@ -903,6 +997,7 @@ class TestRoleSet(TestRole):
kwargs = {
'name': 'over',
'description': None,
+ 'options': {},
}
# RoleManager.update(role, name=)
self.roles_mock.update.assert_called_with(
@@ -935,6 +1030,73 @@ class TestRoleSet(TestRole):
kwargs = {
'name': 'over',
'description': identity_fakes.role_description,
+ 'options': {},
+ }
+ # RoleManager.update(role, name=)
+ self.roles_mock.update.assert_called_with(
+ identity_fakes.ROLE_2['id'],
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_role_set_with_immutable(self):
+ self.roles_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.ROLE_2),
+ loaded=True,
+ )
+ arglist = [
+ '--name', 'over',
+ '--immutable',
+ identity_fakes.ROLE_2['name'],
+ ]
+ verifylist = [
+ ('name', 'over'),
+ ('immutable', True),
+ ('role', identity_fakes.ROLE_2['name']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': 'over',
+ 'description': None,
+ 'options': {'immutable': True},
+ }
+ # RoleManager.update(role, name=)
+ self.roles_mock.update.assert_called_with(
+ identity_fakes.ROLE_2['id'],
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_role_set_with_no_immutable(self):
+ self.roles_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.ROLE_2),
+ loaded=True,
+ )
+ arglist = [
+ '--name', 'over',
+ '--no-immutable',
+ identity_fakes.ROLE_2['name'],
+ ]
+ verifylist = [
+ ('name', 'over'),
+ ('no_immutable', True),
+ ('role', identity_fakes.ROLE_2['name']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'name': 'over',
+ 'description': None,
+ 'options': {'immutable': False},
}
# RoleManager.update(role, name=)
self.roles_mock.update.assert_called_with(