How to NOT to loop in ansible if one of the variable is undefined

Viewed 577

Here is my script , i am trying to send a message to multiple slack channels, using loops. I have defined variable inside variable.

    - name: send msg to slack
      community.general.slack:
         token: XXXXXXXXXXXX
         blocks:
           - type: section
             text:
              type: mrkdwn
              text: |-
               ****text message********
         channel: '{{ item.slack_channel }}'
         username: 'slackbot'
         parse: 'full'
      loop: "{{ slack | default([]) | selectattr('slack_channel') | list }}"
      when: inventory_hostname ==  'abc.xyz'

vars

slack:
      - slack_channel: '#mychannel'
      - slack_channel: '{{ slackchannel1|default(None) }}'
      - slack_channel: '{{ slackchannel2|default(None) }}'

slackchanne1 and slackchannel2 variable are optional, sometimes i will define value but sometimes i won't define value

What i want is -

When a script is triggered, message has to send to all slack channels, but if the variable is not defined then i don't want loop to run and get fail, incase if it run and no variable found then it should't say play failed, it has to skip that loop cause no value is defined for variable slackchannel1 and slackchannel2 , at the end play should be successful with single defined variable vlaue - slack_channel: #mychannel

error i am getting

fatal: [abc.xyz]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'msg'\n\nThe error appears to be in 'tasks/slack.yml': line 303, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n    - name: send msg to slack\n      ^ here\n"}
1 Answers

Use default(None) to avoid error "'slackchannel1' is undefined"

    slack:
      - slack_channel: '#mychannel'
      - slack_channel: '{{ slackchannel1|default(None) }}'
      - slack_channel: '{{ slackchannel2|default(None) }}'

Then, select defined items

loop: "{{ slack | default([]) | selectattr('slack_channel') | list }}"

Quoting from selectattr

If no test is specified, the attribute’s value will be evaluated as a boolean.


For example, the playbook

shell> cat playbook.yml
- hosts: localhost
  vars:
    slack:
      - slack_channel: '#mychannel'
      - slack_channel: '{{ slackchannel1|default(None) }}'
      - slack_channel: '{{ slackchannel2|default(None) }}'

  tasks:
    - debug:
        msg: "{{ item.slack_channel }}"
      loop: "{{ slack | default([]) | selectattr('slack_channel') | list }}"
shell> ansible-playbook playbook.yml

gives

ok: [localhost] => (item={'slack_channel': '#mychannel'}) => 
  msg: '#mychannel'

When the variable is defined

shell> ansible-playbook playbook.yml -e slackchannel2=test

the playbook gives

ok: [localhost] => (item={'slack_channel': '#mychannel'}) => 
  msg: '#mychannel'
ok: [localhost] => (item={'slack_channel': 'test'}) => 
  msg: test
Related