Added opportunity to set extra user options.
Change-Id: I191eca8806f92c84896e776ddc8b9263f00947ae
Related-PROD: PROD-28027
(cherry picked from commit a0b79e20af97a54a24e64724d3a3feb81ef28791)
diff --git a/README.rst b/README.rst
index a63393e..e0cd3c1 100644
--- a/README.rst
+++ b/README.rst
@@ -894,6 +894,60 @@
password_regex_description: 'Your password must contains at least 1 letter, 1 digit, and have a minimum length of 7 characters'
change_password_upon_first_use: true
+
+Define extra user options.
+-------------------------
+
+ To ignore `change_password_upon_first_use` requirement for specific users,
+such as service users, set the `options` attribute `ignore_change_password_upon_first_use`
+to `True` for the desired user via the update user API.
+
+ To ignore `password_expires_days` requirement for specific users,
+such as service users, set the `options` attribute `ignore_password_expiry`
+to `True` for the desired user via the update user API.
+
+ To ignore `lockout_failure_attempts` requirement for specific users,
+such as service users, set the `options` attribute `ignore_lockout_failure_attempts`
+to `True` for the desired user via the update user API.
+
+ Also If there exists a user who should not be able to change her own password via
+the keystone password change API, keystone supports setting that user’s option `lock_password`
+to True via the user update API.
+
+#For release since Q
+.. code-block:: yaml
+
+keystone:
+ client:
+ resources:
+ v3:
+ users:
+ cinder:
+ options:
+ ignore_change_password_upon_first_use: True
+ ignore_password_expiry: False
+ ignore_lockout_failure_attempts: False
+ lock_password: True
+.. code-block::
+
+#For all early releases
+.. code-block:: yaml
+
+keystone:
+ client:
+ server:
+ identity:
+ project:
+ service:
+ user:
+ cinder:
+ options:
+ ignore_change_password_upon_first_use: True
+ ignore_password_expiry: False
+ ignore_lockout_failure_attempts: False
+ lock_password: True
+.. code-block::
+
Upgrades
========
diff --git a/_modules/keystoneng.py b/_modules/keystoneng.py
index 76b6870..ddf0da5 100644
--- a/_modules/keystoneng.py
+++ b/_modules/keystoneng.py
@@ -1082,11 +1082,11 @@
return ret
-def user_update(user_id=None, name=None, email=None, enabled=None,
+def user_update(user_id=None, name=None, email=None, enabled=None, options=None,
tenant=None, profile=None, project=None, description=None, **connection_args):
'''
Update a user's information (keystone user-update)
- The following fields may be updated: name, email, enabled, tenant.
+ The following fields may be updated: name, email, enabled, tenant, options.
Because the name is one of the fields, a valid user id is required.
CLI Examples:
@@ -1112,6 +1112,8 @@
email = user.email
if enabled is None:
enabled = user.enabled
+ if not options:
+ options = {}
if _client_version(kstone) > 2:
if description is None:
@@ -1129,9 +1131,9 @@
project_id = getattr(user, 'project_id', None)
kstone.users.update(user=user_id, name=name, email=email, enabled=enabled, description=description,
- project_id=project_id)
+ options=options, project_id=project_id)
else:
- kstone.users.update(user=user_id, name=name, email=email, enabled=enabled)
+ kstone.users.update(user=user_id, name=name, email=email, options=options, enabled=enabled)
tenant_id = None
if tenant:
diff --git a/_states/keystoneng.py b/_states/keystoneng.py
index 82ce494..36a0d52 100644
--- a/_states/keystoneng.py
+++ b/_states/keystoneng.py
@@ -105,6 +105,7 @@
profile=None,
password_reset=True,
project=None,
+ options=None,
**connection_args):
'''
Ensure that the keystone user is present with the specified properties.
@@ -138,6 +139,9 @@
enabled
Availability state for this user
+ options
+ Dictionary of extra user options.
+
roles
The roles the user should have under given tenants.
Passed as a dictionary mapping tenant names to a list
@@ -182,6 +186,7 @@
change_enabled = False
change_tenant = False
change_password = False
+ change_options = False
if user[name].get('email', None) != email:
change_email = True
@@ -200,7 +205,15 @@
**connection_args)):
change_password = True
- if __opts__.get('test') and (change_email or change_enabled or change_tenant or change_password):
+ if options:
+ options_to_update = {option: options[option] for option in options
+ if (option not in user[name]['options'])
+ or (options[option] != user[name]['options'][option])}
+
+ if len(options_to_update):
+ change_options = True
+
+ if __opts__.get('test') and (change_email or change_enabled or change_tenant or change_password or change_options):
ret['result'] = None
ret['comment'] = 'User "{0}" will be updated'.format(name)
if change_email is True:
@@ -211,6 +224,8 @@
ret['changes']['Tenant'] = 'Will be added to "{0}" tenant'.format(tenant)
if change_password is True:
ret['changes']['Password'] = 'Will be updated'
+ if change_options is True:
+ ret['changes']['Options'] = 'Will be updated'
return ret
ret['comment'] = 'User "{0}" is already present'.format(name)
@@ -236,6 +251,11 @@
ret['comment'] = 'User "{0}" has been updated'.format(name)
ret['changes']['Password'] = 'Updated'
+ if change_options:
+ __salt__['keystoneng.user_update'](name=name, options=options_to_update, profile=profile, **connection_args)
+ ret['comment'] = 'Options has been updated'
+ ret['changes']['Options'] = options_to_update
+
if roles:
for tenant in roles:
args = dict({'user_name': name, 'tenant_name':
@@ -283,6 +303,7 @@
email=email,
tenant_id=tenant_id,
enabled=enabled,
+ options=options,
profile=profile,
**connection_args)
if roles:
diff --git a/_states/keystonev3.py b/_states/keystonev3.py
index 2dd651d..9f287d5 100644
--- a/_states/keystonev3.py
+++ b/_states/keystonev3.py
@@ -251,15 +251,23 @@
exact_user = users[0]
user_id = exact_user['id']
changable = (
- 'default_project_id', 'domain_id', 'enabled', 'email'
+ 'default_project_id', 'domain_id', 'enabled', 'email', 'options'
)
if password_reset:
changable += ('password',)
to_update = {}
for key in kwargs:
- if (key in changable and (key not in exact_user or
- kwargs[key] != exact_user[key])):
+ if key in changable:
+ if key == 'options':
+ to_update['options'] = {option: value for option, value in kwargs['options'].items()
+ if (option not in exact_user['options'])
+ or (value != exact_user['options'][option])}
+
+ if not len(to_update['options']):
+ del to_update['options']
+
+ elif key not in exact_user or kwargs[key] != exact_user[key]:
to_update[key] = kwargs[key]
if to_update:
diff --git a/keystone/client/project.sls b/keystone/client/project.sls
index 240c99f..c8179d9 100644
--- a/keystone/client/project.sls
+++ b/keystone/client/project.sls
@@ -33,6 +33,21 @@
- password: {{ user.password }}
- email: {{ user.get('email', 'root@localhost') }}
- tenant: {{ tenant_name }}
+ {%- if user.options is defined %}
+ - options:
+ {%- if user.options.lock_password is defined %}
+ lock_password: {{ user.options.lock_password }}
+ {%- endif %}
+ {%- if user.options.ignore_change_password_upon_first_use is defined %}
+ ignore_change_password_upon_first_use: {{ user.options.ignore_change_password_upon_first_use }}
+ {%- endif %}
+ {%- if user.options.ignore_password_expiry is defined %}
+ ignore_password_expiry: {{ user.options.ignore_password_expiry }}
+ {%- endif %}
+ {%- if user.options.ignore_lockout_failure_attempts is defined %}
+ ignore_lockout_failure_attempts: {{ user.options.ignore_lockout_failure_attempts }}
+ {%- endif %}
+ {%- endif %}
- roles:
"{{ tenant_name }}":
{%- if user.get('is_admin', False) %}
diff --git a/keystone/client/resources/v3.sls b/keystone/client/resources/v3.sls
index 7803233..8f58f0c 100644
--- a/keystone/client/resources/v3.sls
+++ b/keystone/client/resources/v3.sls
@@ -172,6 +172,21 @@
{%- if user.password_reset is defined %}
- password_reset: {{ user.password_reset }}
{%- endif %}
+ {%- if user.options is defined %}
+ - options:
+ {%- if user.options.lock_password is defined %}
+ lock_password: {{ user.options.lock_password }}
+ {%- endif %}
+ {%- if user.options.ignore_change_password_upon_first_use is defined %}
+ ignore_change_password_upon_first_use: {{ user.options.ignore_change_password_upon_first_use }}
+ {%- endif %}
+ {%- if user.options.ignore_password_expiry is defined %}
+ ignore_password_expiry: {{ user.options.ignore_password_expiry }}
+ {%- endif %}
+ {%- if user.options.ignore_lockout_failure_attempts is defined %}
+ ignore_lockout_failure_attempts: {{ user.options.ignore_lockout_failure_attempts }}
+ {%- endif %}
+ {%- endif %}
{%- elif user.get('status', 'present') == 'absent' %}
diff --git a/keystone/client/server.sls b/keystone/client/server.sls
index 9f97b74..bf83eeb 100644
--- a/keystone/client/server.sls
+++ b/keystone/client/server.sls
@@ -149,6 +149,21 @@
- email: {{ user.email }}
{%- endif %}
- tenant: {{ tenant_name }}
+ {%- if user.options is defined %}
+ - options:
+ {%- if user.options.lock_password is defined %}
+ lock_password: {{ user.options.lock_password }}
+ {%- endif %}
+ {%- if user.options.ignore_change_password_upon_first_use is defined %}
+ ignore_change_password_upon_first_use: {{ user.options.ignore_change_password_upon_first_use }}
+ {%- endif %}
+ {%- if user.options.ignore_password_expiry is defined %}
+ ignore_password_expiry: {{ user.options.ignore_password_expiry }}
+ {%- endif %}
+ {%- if user.options.ignore_lockout_failure_attempts is defined %}
+ ignore_lockout_failure_attempts: {{ user.options.ignore_lockout_failure_attempts }}
+ {%- endif %}
+ {%- endif %}
- roles:
"{{ tenant_name }}":
{%- if user.get('is_admin', False) %}