Merge "Add resource option immutable"
This commit is contained in:
		@@ -16,6 +16,7 @@ Create new project
 | 
			
		||||
        [--domain <domain>]
 | 
			
		||||
        [--parent <project>]
 | 
			
		||||
        [--description <description>]
 | 
			
		||||
        [--immutable | --no-immutable]
 | 
			
		||||
        [--enable | --disable]
 | 
			
		||||
        [--property <key=value>]
 | 
			
		||||
        [--or-show]
 | 
			
		||||
@@ -46,6 +47,15 @@ Create new project
 | 
			
		||||
 | 
			
		||||
    Disable project
 | 
			
		||||
 | 
			
		||||
.. option:: --immutable
 | 
			
		||||
 | 
			
		||||
    Make project immutable. An immutable project may not be deleted or
 | 
			
		||||
    modified except to remove the immutable flag
 | 
			
		||||
 | 
			
		||||
.. option:: --no-immutable
 | 
			
		||||
 | 
			
		||||
    Make project mutable (default)
 | 
			
		||||
 | 
			
		||||
.. option:: --property <key=value>
 | 
			
		||||
 | 
			
		||||
    Add a property to :ref:`\<name\> <project_create-name>`
 | 
			
		||||
@@ -180,6 +190,7 @@ Set project properties
 | 
			
		||||
        [--name <name>]
 | 
			
		||||
        [--domain <domain>]
 | 
			
		||||
        [--description <description>]
 | 
			
		||||
        [--immutable | --no-immutable]
 | 
			
		||||
        [--enable | --disable]
 | 
			
		||||
        [--property <key=value>]
 | 
			
		||||
        [--tag <tag> | --clear-tags | --remove-tags <tag>]
 | 
			
		||||
@@ -199,6 +210,15 @@ Set project properties
 | 
			
		||||
 | 
			
		||||
    Set project description
 | 
			
		||||
 | 
			
		||||
.. option:: --immutable
 | 
			
		||||
 | 
			
		||||
    Make project immutable. An immutable project may not be deleted or
 | 
			
		||||
    modified except to remove the immutable flag
 | 
			
		||||
 | 
			
		||||
.. option:: --no-immutable
 | 
			
		||||
 | 
			
		||||
    Make project mutable (default)
 | 
			
		||||
 | 
			
		||||
.. option:: --enable
 | 
			
		||||
 | 
			
		||||
    Enable project (default)
 | 
			
		||||
 
 | 
			
		||||
@@ -97,6 +97,7 @@ Create new role
 | 
			
		||||
    openstack role create
 | 
			
		||||
        [--or-show]
 | 
			
		||||
        [--domain <domain>]
 | 
			
		||||
        [--immutable | --no-immutable]
 | 
			
		||||
        <name>
 | 
			
		||||
 | 
			
		||||
.. option:: --domain <domain>
 | 
			
		||||
@@ -119,6 +120,15 @@ Create new role
 | 
			
		||||
 | 
			
		||||
    Add description about the role
 | 
			
		||||
 | 
			
		||||
.. option:: --immutable
 | 
			
		||||
 | 
			
		||||
    Make role immutable. An immutable role may not be deleted or modified
 | 
			
		||||
    except to remove the immutable flag
 | 
			
		||||
 | 
			
		||||
.. option:: --no-immutable
 | 
			
		||||
 | 
			
		||||
    Make role mutable (default)
 | 
			
		||||
 | 
			
		||||
role delete
 | 
			
		||||
-----------
 | 
			
		||||
 | 
			
		||||
@@ -253,6 +263,7 @@ Set role properties
 | 
			
		||||
    openstack role set
 | 
			
		||||
        [--name <name>]
 | 
			
		||||
        [--domain <domain>]
 | 
			
		||||
        [--immutable | --no-immutable]
 | 
			
		||||
        <role>
 | 
			
		||||
 | 
			
		||||
.. option:: --name <name>
 | 
			
		||||
@@ -269,6 +280,15 @@ Set role properties
 | 
			
		||||
 | 
			
		||||
    Role to modify (name or ID)
 | 
			
		||||
 | 
			
		||||
.. option:: --immutable
 | 
			
		||||
 | 
			
		||||
    Make role immutable. An immutable role may not be deleted or modified
 | 
			
		||||
    except to remove the immutable flag
 | 
			
		||||
 | 
			
		||||
.. option:: --no-immutable
 | 
			
		||||
 | 
			
		||||
    Make role mutable (default)
 | 
			
		||||
 | 
			
		||||
role show
 | 
			
		||||
---------
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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)'),
 | 
			
		||||
    )
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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):
 | 
			
		||||
 
 | 
			
		||||
@@ -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):
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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,7 +473,8 @@ class TestProjectCreate(TestProject):
 | 
			
		||||
            'description': None,
 | 
			
		||||
            'enabled': True,
 | 
			
		||||
            'parent': None,
 | 
			
		||||
            'tags': ['foo']
 | 
			
		||||
            'tags': ['foo'],
 | 
			
		||||
            'options': {},
 | 
			
		||||
        }
 | 
			
		||||
        self.projects_mock.create.assert_called_with(
 | 
			
		||||
            **kwargs
 | 
			
		||||
@@ -474,6 +483,86 @@ class TestProjectCreate(TestProject):
 | 
			
		||||
        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
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(self.columns, columns)
 | 
			
		||||
        self.assertEqual(self.datalist, data)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestProjectDelete(TestProject):
 | 
			
		||||
 | 
			
		||||
@@ -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):
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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(
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
---
 | 
			
		||||
features:
 | 
			
		||||
  - |
 | 
			
		||||
    Added the below mentioned parameters to the role, project and domain commands.
 | 
			
		||||
 | 
			
		||||
    * --immutable
 | 
			
		||||
    * --no-immutable
 | 
			
		||||
 | 
			
		||||
    This will allow user to set "immutable" resource option.
 | 
			
		||||
		Reference in New Issue
	
	Block a user