Reputation: 1192
I want to execute a Salt state not always when changes happened in another state, but only for specific changes. This appears like I would have to make onchanges
/onchanges_in
dependent on the specific changes.
The respective bug report has been closed saying "this is totally resolved now that states have access to the running dict and the lowstate for a state run". However, I can find no documentation on that and hardly any explanation of what the "running dict" actually is.
So I guess the question could also be rephrased as "How do I access the 'running dict' in an onchanges
requisite?", but I'm open to any solutions for the original problem. Thanks for your help!
Update: A comment asked for a specific example, so here is my use case: As most state modules, user.present
may either update fields of an existing (user) object or create a new one. Then, I want to run a second state module if and only if a specific field has been changed and/or the object has just been created. In Ansible, for comparison, I would register
a variable and access the module's result through it.
So, why would I want to do that?
Essentially, I want to create user accounts on Linux and have them be able to set their own password (when logged in via an SSH key). user.present
supports empty_password
for that purpose, but it doesn't play nicely with enforce_password
. This means that after a password has been manually set, a repeated state run will clear that password again. One might even consider this a bug in Salt, but the interactions between the different user.present
fields are convoluted and debatable.
My solution is to create the accounts first and run a module.run
state executing shadow.del_password
afterwards. This is realised through an onchanges_in
requisite. However, password deletion should not be triggered for any change, but only when the user account is created, which is also the only case my user.present
state touches the password at all. Otherwise, things like adding users to a group would clear their password. For that effect, I think I would have to look into the details of the user.present
change.
Create user account for dummy:
user.present:
- name: dummy
- gid_from_name: True
- remove_groups: False
# TODO: This should be made more specific
- onchanges_in:
- module: Allow dummy to set a password
Allow dummy to set a password:
module.run:
- name: shadow.del_password
- m_name: dummy
# Make sure that this is not executed accidentally if no `onchanges_in` is present
- onchanges: []
- require:
- user: Create user account for dummy
Upvotes: 1
Views: 4106
Reputation: 953
I think what you want to use in this case is module.wait
, not module.run
. module.wait
by default will not do anything, unless asked by something else. Also, onchanges_in
for some reason (I think this issue) doesn't play well with module.wait
for me. I've tried watch_in
and it did the job.
I've tried the following code and it seem to work just fine. It creates a user with an empty password and doesn't change anything if user is already there:
Create user account for dummy:
user.present:
- name: dummy
- gid_from_name: True
- remove_groups: False
# TODO: This should be made more specific
- watch_in:
- module: Allow dummy to set a password
Allow dummy to set a password:
module.wait:
- name: shadow.del_password
- m_name: dummy
- require:
- user: Create user account for dummy
Upvotes: 0
Reputation: 945
I don't know about specific onchanges or the 'running dict', but, for your particular use case, you can use a condition to enable your password clearing state only when needed, such as:
Create user account for dummy:
user.present:
- name: dummy
- gid_from_name: True
- remove_groups: False
{% if salt['user.info']('dummy') == {} %}
# Only clear the password if the account didn't exist before
Allow dummy to set a password:
module.run:
- name: shadow.del_password
- m_name: dummy
- require:
- user: Create user account for dummy
{% endif %}
Upvotes: 2