Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
218 views
in Technique[技术] by (71.8m points)

amazon web services - A playbook with two roles: running role B complains with role A's code which successfully ran

I am experiencing a strange behavior: when I run role B, it complains role A's code which I can successfully run! I have reproduced this to this minimal example:

$ cat playbooka.yml 

- hosts:
    - host_a

  roles:
    - role: rolea
      tags:
        - taga
    - role: roleb
      tags:
        - tagb

I have tagged two roles because I want to selectively run role A or role B, they consist simple tasks as shown below in this minimal example:

$ cat roles/rolea/tasks/main.yml

- name: Get service_facts
  service_facts:

- debug:
    msg: '{{ ansible_facts.services["amazon-ssm-agent"]["state"] }}'

- when: ansible_facts.services["amazon-ssm-agent"]["state"] != "running"
  meta: end_play

$ cat roles/roleb/tasks/main.yml

- debug:
    msg: "I am roleb"

The preview confirms that I can run individual roles as specified by tags:

$ ansible-playbook playbooka.yml -t taga -D -C --list-hosts --list-tasks

playbook: playbooka.yml

  play #1 (host_a): host_a  TAGS: []
    pattern: ['host_a']
    hosts (1):
      3.11.111.4
    tasks:
      rolea : Get service_facts TAGS: [taga]
      debug TAGS: [taga]

$ ansible-playbook playbooka.yml -t tagb -D -C --list-hosts --list-tasks

playbook: playbooka.yml

  play #1 (host_a): host_a  TAGS: []
    pattern: ['host_a']
    hosts (1):
      3.11.111.4
    tasks:
      debug TAGS: [tagb]

I can run role A OK:

$ ansible-playbook playbooka.yml -t taga -D -C

PLAY [host_a] *************************************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************************************************************************************************************************************
ok: [3.11.111.4]

TASK [rolea : Get service_facts] ******************************************************************************************************************************************************************************************************************
ok: [3.11.111.4]

TASK [rolea : debug] ******************************************************************************************************************************************************************************************************************************
ok: [3.11.111.4] => {
    "msg": "running"
}

PLAY RECAP ****************************************************************************************************************************************************************************************************************************************
3.11.111.4               : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

But when I run role B, it complains the code in role A which I just successfully ran!

$ ansible-playbook playbooka.yml -t tagb -D -C

PLAY [host_a] *************************************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ****************************************************************************************************************************************************************************************************************************
ok: [3.11.111.4]
ERROR! The conditional check 'ansible_facts.services["amazon-ssm-agent"]["state"] != "running"' failed. The error was: error while evaluating conditional (ansible_facts.services["amazon-ssm-agent"]["state"] != "running"): 'dict object' has no attribute 'services'

The error appears to be in '<path>/roles/rolea/tasks/main.yml': line 9, column 3, but may
be elsewhere in the file depending on the exact syntax problem.

The offending line appears to be:

- when: ansible_facts.services["amazon-ssm-agent"]["state"] != "running"
  ^ here
We could be wrong, but this one looks like it might be an issue with
unbalanced quotes. If starting a value with a quote, make sure the
line ends with the same set of quotes. For instance this arbitrary
example:

    foo: "bad" "wolf"

Could be written as:

    foo: '"bad" "wolf"'

I have two questions:

  • Why role A's code should be involved at all?
  • Even it gets involved, ansible_facts has services, and the service is "running" as shown above by running role A.

PS: I am using the latest Ansible 2.10.2 and latest python 3.9.1 locally on a MacOS. The remote python can be either 2.7.12 or 3.5.2 (Ubuntu 16_04). I worked around the problem by testing if the dictionary has the services key:

ansible_facts.services is not defined or ansible_facts.services["amazon-ssm-agent"]["state"] != "running"

but it still surprises me that role B will interpret role A's code and interpreted it incorrectly. Is this a bug that I should report?

question from:https://stackoverflow.com/questions/65861456/a-playbook-with-two-roles-running-role-b-complains-with-role-as-code-which-suc

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

From the notes in meta module documentation:

Skipping meta tasks with tags is not supported before Ansible 2.11.

Since you run ansible 2.10, the when condition for your meta task in rolea is always evaluated, whatever tag you use. When you use -t tagb, ansible_facts.services["amazon-ssm-agent"] does not exist as you skipped service_facts, and you then get the error you reported.

You can either:

  • upgrade to ansible 2.11 (might be a little soon as I write this answer since it is not yet available over pip...)
  • rewrite your condition so that the meta task skips when the var does not exists e.g.
    when:
      - ansible_facts.services["amazon-ssm-agent"]["state"] is defined
      - ansible_facts.services["amazon-ssm-agent"]["state"] != "running"
    

The second solution is still a good practice IMO in whatever condition (e.g. share your work with someone running an older version, running accidentally against a host without the agent installed....).

One other possibility in your specific case is to move the service_facts tasks to an other role higher in play order, or in the pre_tasks section of your playbook, and tag it always. In this case the task will always play and the fact will always exists, whatever tag you use.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...