How to make an item in with_items conditional?

Take this playbook:

  • hosts: mt1-dummys101
    tasks:
  • name: Install apt packages
    sudo: true
    apt: pkg={{ item }}
    with_items:
  • build-essential
  • libyaml-dev
  • python2.7-dev
  • “{{ ‘silversearcher-ag’ if ansible_distribution_major_version == ‘14’ else ‘’ }}”

How would I make it so that silversearcher-ag is installed only on Ubuntu 14 and is omitted for other operating systems?

The above gives:

TASK: [Install apt packages] **************************************************
failed: [mt1-dummys101] => (item=build-essential,libyaml-dev,python2.7-dev,) => {“failed”: true, “item”: “build-essential,libyaml-dev,python2.7-dev,”}
msg: No package matching ‘’ is available

I also tried changing the empty string '' to omit but that also fails:

TASK: [Install apt packages] **************************************************
failed: [mt1-dummys101] => (item=build-essential,libyaml-dev,python2.7-dev,__omit_place_holder__07ef1633a8f8d1dc718ffb780b3f0e54d7f7b02a) => {“failed”: true, “item”: “build-essential,libyaml-dev,python2.7-dev,__omit_place_holder__07ef1633a8f8d1dc718ffb780b3f0e54d7f7b02a”}
msg: No package matching ‘__omit_place_holder__07ef1633a8f8d1dc718ffb780b3f0e54d7f7b02a’ is available

Any way to do this?

I’ve done it by having two lists in group vars files and doing a group_by

My first thought is to create a new task and use a when clause:

`

  • hosts: mt1-dummys101
    tasks:

  • name: Install apt packages
    sudo: true
    apt: pkg={{ item }}
    with_items:

  • build-essential

  • libyaml-dev

  • python2.7-dev

  • name: Install apt packages for version 14

sudo: true
apt: pkg={{ item }}
with_items: - silversearcher-ag
when: ansible_distribution_major_version == ‘14’

`

Yeah, this was what I went with for the time being. I’m curious if there are other ways, but this does seem to be a reasonable solution. Thanks!

with_items:
   - "{{ (ansible_distribution_major_version == '14')|ternary(
'silversearcher-ag','' }}"

Thanks, but that doesn’t work.

E.g.: I used this slightly tweaked line:

  • “{{ (ansible_distribution_major_version == ‘12’)|ternary(‘silversearcher-ag’, ‘’) }}”

and if the condition is not true, then I get:

TASK: [Install apt packages] **************************************************
failed: [mt1-dummys101] => (item=build-essential,libyaml-dev,python2.7-dev,) => {“failed”: true, “item”: “build-essential,libyaml-dev,python2.7-dev,”}
msg: No package matching ‘’ is available

It seems that for this kind of thing to work, there would either need to be:

  • a way to tell with_items to not add the item at all (by using “omit” perhaps, which doesn’t currently work in this context)
  • “apt” module would ignore a blank string or other sentinel value like “omit”.

And I would think the former would be more preferable as it is more generally applicable (would work with all modules).

I think of “with_items” as being analogous to a for loop in most programming languages. So I guess that means the feature that I am wishing I had here is analogous to a “continue” statement in those same programming languages.

ah, thought you wanted an empty string, misread from your example.

you'll have to use a when condition or dynamically construct the list,
there is no way to have a list item return a 'delete this item', even
None would return an empty element, but still and element.

list:
- 1
- 2
  - <whatever>

is already a list of 3 items, no value of <whatever> can remove the -
in front of it as it is processed by YAML and <whatever> is by jinja2,
when its already a 3 element list.

example of dynamic list
with_items: {{"[1,2]|union( condition|ternary(['stuff'], ))"}}

it uses union to add elements from either list with 'stuff' or empty
list, which leaves the original 'unchanged'

Ah, that’s clever. Probably too clever for me to want to use on my colleagues, but clever nonetheless.

That could be an example if anyone ever writes a book called the “The Little Ansibler” in the style of “The Little Schemer”. :slight_smile: