Sadly, I don't think there is a good way to do that with salt at the moment. The only way I know of to make a perfectly reusable state is to write your own custom state. That isn't so hard by itself, but (unless I missed the memo) you can't actually call
other states from your states. You have to call other
modules. Which means that if your custom state needs to set up some files, you have to replicate a lot of code that's already in the file state.
I think this is actually a problem worth seriously considering. As engineers, we're constantly taught to think modular. Design individual components that can be swapped, plugged, moved around, etc. So that's how we're used to thinking. But with the salt state system, that's actually not possible. You can't build a completely isolated state and use it as you wish; it's always going to be influenced by the global state configuration. This comes out most clearly when trying to get one state to run twice with different parameters. It just doesn't work. So we end up designing around the constraints of salt, which is totally backwards. Python is about readability and ease for the programmer, not the machine.
I don't want to sound like I'm coming down too hard on salt, because I LOVE salt, but this problem in particular is a pain point. I haven't contributed yet, but I'd be willing to put some time into it if we could come up with a better idea of what it should look like. Ideas so far:
Making states available to custom states. For example, here is one that would allow installing a s3cmd config file on a per-user basis
s3cmd.py
def installed(name, user='root', home='/root', access_key=None, secret_key=None):
salt['state.pkg.installed']('s3cmd')
salt['state.file.managed'](home + '/.s3cfg',
user=user,
group=user,
mode='0600',
template='jinja',
source='salt://s3cmd/s3cfg.tmpl',
context={'access_key':access_key,
'secret_key':secret_key}
)
Parameterized include. Same example:
s3cmd.sls
#!(user='root', home='/root', access_key=None, secret_key=None) | jinja | yaml
.pkgs:
pkg.installed:
- name: s3cmd
.config:
file.managed:
- name: {{ home }}/.s3cfg
- user: {{ user }}
- group: {{ group }}
- mode: 0600
- template: jinja
- source: salt://s3cmd/s3cfg.tmpl
- context:
access_key: {{ access_key }}
secret_key: {{ secret_key }}
This one would also require a change in the 'include' semantics to allow multiple includes in a single file. In reality, we'd probably have to create another directive, like 'render'. Does anyone else have better ideas? Because I don't completely like either of the two things I suggested.