Search code examples
linuxansibleansible-awx

Error running playbook that only affects one of the hosts


I've recently started using more and more Ansible, and especially AWX, for simple repetitive tasks. Below is a playbook for downloading, installing and configuring logging via a Bash script. The script is for two hosts: Ubuntu 20.04 and CentOS 7.6, and for the latter, making some changes to SELinux is required.

The question is, why am I getting an error for the Ubuntu only and not the CentOS also?

Here is the playbook:

# Download an run Nagios Log Server configuration script
---
- name: nagios-log configure
  hosts: all
  remote_user: root
  tasks:
  
  - name: Distribution
    debug: msg="{{ ansible_distribution }}"

  - name: Download setup-linux.sh
    get_url: 
      url: http://10.10.10.10/nagioslogserver/scripts/setup-linux.sh
      validate_certs: no
      dest: /tmp/setup-linux.sh
      
  - name: Change script permission
    file: dest=/tmp/setup-linux.sh mode=a+x
      
  - name: Run setup-linux.sh
    shell: /tmp/setup-linux.sh -s 10.10.10.10 -p 5544
    register: ps
    failed_when: "ps.rc not in [ 0, 1 ]"
    
  - name: Install policycoreutils if needed
    yum: 
      name: 
        - policycoreutils
        - policycoreutils-python
      state: latest
    when: ansible_distribution == 'CentOS'
        
  - name: Check if policy file exists
    stat:
      path: /etc/selinux/targeted/active/ports.local
    register: result
    when: ansible_distribution == 'CentOS'

  - name: Check whether line exists
    find:
      paths: /etc/selinux/targeted/active/ports.local 
      contains: '5544'
    register: found
    when: result.stat.exists == True
    
  - name: Add SELinux policy exception if missing
    command: semanage port -a -t syslogd_port_t -p udp 5544
    when: found.matched > 0
    
  - name: Restart rsyslog
    systemd:
      name: rsyslog
      state: restarted
      enabled: yes

And here is the error output when running the playbook on AWX:

TASK [Check whether line exists] ***********************************************
fatal: [Ubuntu.domain.corp]: FAILED! => {"msg": "The conditional check 'result.stat.exists == True' failed. The error was: error while evaluating conditional (result.stat.exists == True): 'dict object' has no attribute 'stat'\n\nThe error appears to be in '/tmp/awx_154_1811rny6/project/nagios-log.yml': line 39, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n  - name: Check whether line exists\n    ^ here\n"}
ok: [Centos.domain.corp]

For reasons I can't comprehend, the CentOS server is fine, but the Ubuntu is getting a strange error that I don't understand. I've tried other methods to achieve the same logic as the when command.


Solution

  • You get this error, because you register the variable result in

      - name: Check if policy file exists
        stat:
          path: /etc/selinux/targeted/active/ports.local
        register: result
        when: ansible_distribution == 'CentOS'
    

    But because of when: ansible_distribution == 'CentOS' this does not run on Ubuntu and therefor the variable result does not exist when running the playbook on Ubuntu.

    To fix this (and run the task using result on CentOS only as well) you can change it to this:

      - name: Check whether line exists
        find:
          paths: /etc/selinux/targeted/active/ports.local 
          contains: '5544'
        register: found
        when:
        - ansible_distribution == 'CentOS'
        - result.stat.exists == True
    
      - name: Add SELinux policy exception if missing
        command: semanage port -a -t syslogd_port_t -p udp 5544
        when:
        - ansible_distribution == 'CentOS'
        - found.matched > 0
    

    Or you can put all CentOS specific tasks in a block like this:

      - name: CentOS specific tasks
        block:
        - name: Install policycoreutils if needed
          yum: 
            name: 
              - policycoreutils
              - policycoreutils-python
            state: latest
        - name: Check if policy file exists
          stat:
            path: /etc/selinux/targeted/active/ports.local
          register: result
        - name: Check whether line exists
          find:
            paths: /etc/selinux/targeted/active/ports.local 
            contains: '5544'
          register: found
          when: result.stat.exists == True      
        - name: Add SELinux policy exception if missing
          command: semanage port -a -t syslogd_port_t -p udp 5544
          when: found.matched > 0
        when: ansible_distribution == 'CentOS'
    

    Or you can put them in their own file and include that file. There are actually a lot of ways to do this.