Looping over multiple sets of values

As far as I can tell, it’s currently impossible to loop over two sets of values in any fashion.

For each user I’m creating in a play, I’d like to install customizations to the user’s remote environment or fallback to a default. The way I’ve done this is by allowing a user to provide a file named as his or her username is a particular directory in source control. Essentialy:

  • name: install customizations
    action: copy src=$available_file dest=/home/$item/custom
    with_items: $users
    first_available_file:
  • res/users/$item
  • res/users/default

Obviously, with this use case and probably most any other one one could work around the issue outside of ansible – and perhaps this goes too far in compromising the simplicity of the play syntax.

As far as I can tell, it's currently impossible to loop over two sets of values in any fashion.

AHA! YOU HAVE FALLEN INTO MY TRAP!!!!111

If you mean that with_items and first_available_file don't work together, this is true, because they both use the variable $item.

This should probably have raised an error message or something, I didn't expect anyone to want to do it, though perfectly fine that you have tried.

(Sidenote, first_available_file is not a loop per se -- it selects the first file that exists on the local system, and passes that in for $item)

For each user I'm creating in a play, I'd like to install customizations to the user's remote environment or fallback to a default. The way I've done this is by allowing a user to provide a file named as his or her username is a particular directory in source control. Essentialy:

- name: install customizations
action: copy src=$available_file dest=/home/$item/custom
with_items: $users
first_available_file:
- res/users/$item
- res/users/default

Obviously, with this use case and probably most any other one one could work around the issue outside of ansible -- and perhaps this goes too far in compromising the simplicity of the play syntax.

The variable used by $first_available_file could be changed to be "$file", perhaps.

Though this change would be incompatible with past play books, it wouldn't be catastrophic.

I would like to keep things simple enough where I don't have to say:

with_items_as_foo: $splat
first_available_file_as_bar: $glorp

It's hideous to explain and hard to read, so I think multiple "with_items" loops are probably not going to happen.

Patches to change the "first_available_file" variable to "file", with updated tests, would definitely be accepted. We'd just have to make clear note of it in the release notes.

Could you perhaps do this with conditional imports instead? http://ansible.github.com/playbooks2.html#conditional-imports

Another wrinkle is that, if you wanted to support multiple loops, they’d presumably have to be executed in the order given. Not impossible, but you’d have to load the YAML as an ordered dictionary.

As an aside, the unordered-ness of dictionaries is my biggest pet peeve and incites rage very frequently.

I’ll look into a patch (it could probably be made backwards-compatible by providing $file as $item if with_items is not specified, yes?). Also, can anyone suggest the right way to maintain multiple pull requests on github? I’m kind of a dumb git.

Another wrinkle is that, if you wanted to support multiple loops, they'd presumably have to be executed in the order given. Not impossible, but you'd have to load the YAML as an ordered dictionary.

That too. Though I hope there's not a huge case for needing that either. Would mean the configuration has taken on a life of it's own, I'd think :slight_smile:

In the present case, with_items is basically a macro that creates more than one task, and first_available_file is something that happens in the context of the task, so at least the order for those is pretty well defined.

As an aside, the unordered-ness of dictionaries is my biggest pet peeve and incites rage very frequently.

I'll look into a patch (it could probably be made backwards-compatible by providing $file as $item if with_items is not specified, yes?). Also, can anyone suggest the right way to maintain multiple pull requests on github? I'm kind of a dumb git. --

I'd find that confusing for the case where they were, so it's probably better if we just change it -- also makes future conversations easier.

As for github, I highly recommend starting a new branch for each feature request or idea -- and then you can delete those branches when they are no longer needed.

I’m having a bit of trouble cracking the code - at what point is result of first_available_file bound to $item?

OK, I get how it works now.

apply templating to source argument

inject = self.setup_cache.get(conn.host,{})

… find first available file

if self.module_vars is not None:
inject.update(self.module_vars)

It looks like the solution could be as easy as moving the update statement above the first-available-file lookup – presuming that this isn’t bad in some way I haven’t grasped.

Let's continue the discussion here:

https://github.com/ansible/ansible/issues/552