with_flattened: list vs lookup('flattened',list-of-lists)

We have a playbook like this:

  - hosts: localhost
    gather_facts: false
    vars:
      produsers: [chris, dana]
      stgusers: [pat, sandy]
      allusers: [alex, andy, chris, dan, dana, jamie, pat, sandy, terry]

    tasks:

      - name: show authorized
        debug: msg={{ item }}
        when: item in lookup('flattened', [produsers, stgusers])
        with_items: allusers

A list of users who should have access to prod, a list of users who should
have access to stg, and a list of all the users, including some who
shouldn't have access to either of those things. The task is then intended
to show the users who are in one list or the other. Thing is, it does this:

  TASK: [show authorized] *******************************************************
  skipping: [localhost] => (item=alex)
  ok: [localhost] => (item=andy) => {
      "item": "andy",
      "msg": "andy"
  }
  ok: [localhost] => (item=chris) => {
      "item": "chris",
      "msg": "chris"
  }
  ok: [localhost] => (item=dan) => {
      "item": "dan",
      "msg": "dan"
  }
  ok: [localhost] => (item=dana) => {
      "item": "dana",
      "msg": "dana"
  }
  skipping: [localhost] => (item=jamie)
  ok: [localhost] => (item=pat) => {
      "item": "pat",
      "msg": "pat"
  }
  ok: [localhost] => (item=sandy) => {
      "item": "sandy",
      "msg": "sandy"
  }
  skipping: [localhost] => (item=terry)

What are andy and dan doing there? They're not on the right lists! But,
their names *are* substrings of the names of some of the users who *are*
on the right lists. Hmm.

We tried this to debug:

    - name: show flattened
      debug: msg={{ item }}
      with_items: lookup('flattened', [produsers, stgusers])

That says:

  TASK: [show flattened] ********************************************************
  ok: [localhost] => (item=chris,dana,pat,sandy) => {
      "item": "chris,dana,pat,sandy",
      "msg": "chris,dana,pat,sandy"
  }

So, a list of users, right? Not so, because here's a similar one, but with
a literal list of users, not run lookup('flattened', list-of-lists):

    - name: show literal
      debug: msg={{ item }}
      with_items: ['chris', 'dana', 'pat', 'sandy']

And that says

  TASK: [show literal] **********************************************************
  ok: [localhost] => (item=chris) => {
      "item": "chris",
      "msg": "chris"
  }
  ok: [localhost] => (item=dana) => {
      "item": "dana",
      "msg": "dana"
  }
  ok: [localhost] => (item=pat) => {
      "item": "pat",
      "msg": "pat"
  }
  ok: [localhost] => (item=sandy) => {
      "item": "sandy",
      "msg": "sandy"
  }

So it looks like lookup('flattened', list-of-lists) is returning a
*string* of comma-separated values, rather than a list of values.

with_flattened seems to return a list of values, but we're not sure how to
use that in this context, because we already need to with_items over
allusers.

What's the best way to do this? Is there a lookup plugin that works like
with_flattened, i.e. returns a list of values rather than a string?

                                      -Josh (jbs@care.com)

This email is intended for the person(s) to whom it is addressed and may contain information that is PRIVILEGED or CONFIDENTIAL. Any unauthorized use, distribution, copying, or disclosure by any person other than the addressee(s) is strictly prohibited. If you have received this email in error, please notify the sender immediately by return email and delete the message and any attachments from your system.

" when: item in lookup(‘flattened’, [produsers, stgusers])"

I’ve never seen that syntax used and am slightly surprised it works. However, what’s happening is “item” is the only thing that decides what you are looping over.

The “when” decides, at that loop iteration, what gets executed.

I would not expect to see a lookup inside a “when” conditional. It’s not disallowed, but it’s weird enough to be the first time I’ve seen someone try it.

Ultimately, it may be possible to string ansible together to do some weird/clever things because there’s a template engine in there, though we generally stick to idiomatic things in the docs.

I would have suspected:

  • debug: msg={{ item }}
    with_flatted:
  • listone
  • listtwo

As the best way to list or iterate over the users in multiple lists at the same time.

It may be that I’m misinterpreting the question, and you are looking for another form of iteration, but that seems to be what you want, to me.

However, what's happening is "item" is the only thing that decides
what you are looping over.

Right; the thing that we wanted to do here, if I were expressing it in
Python-like pseudocode, would be something like:

  for user in allusers:
    if user in itertools.chain(produsers, stgusers):
      do stuff

That is, our logic is to iterate over the list of all users, and then see
if each of them is in the flattened list of authorized users, do stuff if
they are, and skip them if they aren't. But to do that, we need to get our
hands on the flattened list of authorized users, and we can't do that with
with_flattened, because we're already in the middle of a with_items across
the list of all users.

After thinking about it some more, though, we think that our approach here
is wrong: Rather than iterating over the list of all users, and seeing if
they're in one of the lists of authorized users, we should instead iterate
over the flattened list of authorized users (which we can get just fine
via with_flattened), and look up the information about each user that way.
We didn't think of this at first because our list of all users is
currently a list of dicts, but if it were a dict, that would work fine.
(This is a slightly simplified example -- in our real use case, allusers
isn't just a list of usernames, it's a list of dicts about each user. It
should really be a dict of dicts instead, and then everything else would
work perfectly.)

https://groups.google.com/d/msg/ansible-project/W-o_hXj-6IA/hzJFs3GRcd4J
has an example of this -- that's actually the post that inspired us to do
it the way we're doing it now, but because our users were a list rather
than a dict, that example didn't work out of the box, and we came up with
this other weird thing that seemed to work.

                                      -Josh (jbs@care.com)

This email is intended for the person(s) to whom it is addressed and may contain information that is PRIVILEGED or CONFIDENTIAL. Any unauthorized use, distribution, copying, or disclosure by any person other than the addressee(s) is strictly prohibited. If you have received this email in error, please notify the sender immediately by return email and delete the message and any attachments from your system.