Setting vars dynamically in command from stdout. (like bcfg2 probes)

Hello

I have a use case where I want to create a user in a postgres database
only if it does not exist. A separate module could be written for
this but I think a general solution for this kind of situation makes
sense.

My suggestion is to have a way to assign stdout to a variable to be
used later on in the playbook. I think this could be added to command.
As a very simple example (even though this is covered by facts/ohai).

command uname -i stdout_var=architecture

So architecture can be used as var later on in the templates/
conditionals.

This seems pretty trivial to implement, but does require a change to
the runner code. I have made a quick hack attempt but it seems that
currently the way to do this is to add these variables to setup_cache,
which is badly named, and the comments say it is going away anyway.

I would suggest that having a way for any module to add vars would be
useful. So adding an optional

"extra_vars" : {"var1" : "value", ...}

to any module result json/dict could make sense. This would mean that
ohai/factor could use this and would not be a special case anymore.

I am happy to work on this and give you a patch, but want to make sure
that you also think this kind of feature is valuable.

Thanks

David

My suggestion is to have a way to assign stdout to a variable to be
used later on in the playbook. I think this could be added to command.

This has been suggested before. It's a good idea, just being able to access a $last_result
variable per host.

In this case, stdout would actually be

${last_result.stdout}

I'll file a ticket so we do this for 0.5

Already you can have a custom module return a dictionary called ansible_facts, and create variables in this way, though it's a bit heavy handed for something like last_result, which you may just as easily want to use from the command module.

This seems pretty trivial to implement, but does require a change to
the runner code. I have made a quick hack attempt but it seems that
currently the way to do this is to add these variables to setup_cache,
which is badly named, and the comments say it is going away anyway.

It has nothing to do with the runner code, and everything to do with playbooks.

It may or may not go away, that is to be determined. In any event, much refactoring is due in 0.5 that will change the way it all works quite a bit, as we expose Host objects directly into the core of Runner, Tasks become real objects, etc.

Each Host, if we do things right, will know the last command it executed and the result, without having to access the various hashes as it does now.

I would suggest that having a way for any module to add vars would be
useful. So adding an optional

"extra_vars" : {"var1" : "value", ...}

to any module result json/dict could make sense. This would mean that
ohai/factor could use this and would not be a special case anymore.

I don't understand how --extra-vars, which is a way of injecting variables into a playbook, would be relevant in a module.

In this case, stdout would actually be

${last_result.stdout}

I'll file a ticket so we do this for 0.5

That would be great. It could be useful though to hold onto a
variable for the length of that host. Nonetheless, the 'creates'
param in command is also a bit a hack due to namespacing issues i.e if
a command has is own 'creates' param. So adding another one (such as
stdout_var) is probably bad practice.

The other solution is to pass on the whole stack of results. i.e $
{results[-1].stdout} but I do not know how your parser or the jinja
handles lists. The simple solution, as you suggested, would be good
enough for most cases including mine.

Already you can have a custom module return a dictionary called ansible_facts, and create variables in this way, though it's a bit heavy handed for something like last_result, which you may just as easily want to use from the command module.

Great, missed that. That is all I was after in with the extra_vars
that I mentioned.

In this case, stdout would actually be

${last_result.stdout}

I’ll file a ticket so we do this for 0.5

That would be great. It could be useful though to hold onto a
variable for the length of that host. Nonetheless, the ‘creates’
param in command is also a bit a hack due to namespacing issues i.e if
a command has is own ‘creates’ param. So adding another one (such as
stdout_var) is probably bad practice.

Creates doesn’t alter the variable space or have any sort of namespacing issues.
It’s no different than any other type of parameter.

I don’t find it being a hack at all. I think it fulfills a decent use case.

The other solution is to pass on the whole stack of results. i.e $
{results[-1].stdout} but I do not know how your parser or the jinja
handles lists. The simple solution, as you suggested, would be good
enough for most cases including mine.

Jinja is not relevant here, as it’s not guaranteed you only want it in a template… and Jinaj2 isn’t used except in templates in 0.4 (there are other ways
to get variables).

We may offer up $last_result in 0.5

TBD. Likely.

I don't find it being a hack at all. I think it fulfills a decent use case.

My point was that if I had a odd command line tool say

fake_command.sh creates='2005-01-01'

was a valid way of using fake_command.sh

So in this case.
command /usr/bin/fake_command.sh creates='2005-01-01'

the creates='2005-01-01' would not get passed to fake_command.

Its such a minor edge case, and it definitely should be kept, just
saying that a proliferation of these is probably bad.

The module still sees it, so as long as it goes to the module, I don’t see it being so much as an edge case.

Anyway, the idea of returning a last_result is generalizable to all modules, and would not be an argument you would pass to a module.

–Michael

Yes the core code has no problems and your solution is definitely the
cleanest.

Thanks for the excellent work on this, it is really a breath of fresh
air compared to other config management software out there.