4.3 Ansible Playbooks - Output

In this lab we learn how to handle output of tasks.

Task 1

  • Write a playbook output.yml that uses the command module to find all config files of postfix. These files are located under /etc/postfix/ and end with .cf. Targeted server is node1.
  • Register the result to a variable called output by using the register keyword.
  • Include a task using the debug module to print out all content of the variable output. If unsure, consult the documentation about the debug module.
Solution Task 1

Documentation about debug module Example output.yml:

1
2
3
4
5
6
7
8
9
---
- hosts: node1
  become: true
  tasks:
    - name:
      command: "find /etc/postfix -type f -name *.cf"
      register: output
    - debug:
        var: output

Task 2

  • Add another task to the playbook output.yml using the debug module and print out the resulting filenames of the search above.
  • Now, loop over the results and create a backup file called <filename.cf>.bak for each file <filename.cf> that was found. Use the command module. Remember, that the result is probably a list with multiple elements.
Solution Task 2

Example output.yml:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
---
- hosts: node1
  become: true
  tasks:
    - name:
      command: "find /etc/postfix -type f -name *.cf"
      register: output
    - debug:
        var: output.stdout_lines
    - name: create backup
      command: "cp {{ item }} {{ item }}.bak"
      loop: "{{ output.stdout_lines  }}"

Task 3 (Advanced)

  • Now we enhance our playbook output.yml to only create the backup if no backup file is present.
  • Solve this task by searching for files ending with .bak and registering the result to a variable. Then do tasks only if certain conditions are met.
Solution Task 3

Possible solution 1: Example output.yml:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
---
- hosts: node1
  become: true
  tasks:
    - name:
      command: "find /etc/postfix -type f -name *.cf"
      register: output
    - name: create backup only when no backupfile is present
      command: "cp {{ item }} {{ item }}.bak"
      # only do this if there is no .bak for file: item
      args:
        creates: "{{ item }}.bak"
      loop: "{{ output.stdout_lines }}"

Possible solution 2: Example output.yml:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
---
- hosts: node1
  become: true
  tasks:
    - name:
      command: "find /etc/postfix -type f -name *.cf.bak"
      register: search
    - name:
      command: "find /etc/postfix -type f -name *.cf"
      register: output
    - name: create backup only when no backupfile is present
      command: "cp {{ item }} {{ item }}.bak"
      loop: "{{ output.stdout_lines  }}"
      # only do this if there is no .bak for file: item
      when: search.stdout.find(item) == -1

Task 4 (Advanced)

  • Ensure httpd is stopped on the group web by using an Ansible ad hoc command.
  • Write a play servicehandler.yml that does the following:
  • Install httpd by using the dnf module
  • Start the service httpd with the command module. Don’t use service or systemd module.
  • Start the service only if it is not started and running already. (The output of systemctl status httpd doesn’t contains the string Active: active (running))
Solution Task 4

Stop the httpd service with Ansible:

1
ansible web -b -a "systemctl stop httpd"

Content of servicehandler.yml:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
---
- hosts: web
  become: true
  tasks:
    - name: install httpd
      dnf:
        name: httpd
        state: present
    - name: check state of service httpd
      command: 'systemctl status httpd'
      register: status
      ignore_errors: true
    - debug:
        var: status.stdout
    - name: start httpd
      command: 'systemctl start httpd'
      when: "'Active: active (running)' not in status.stdout"

Task 5 (Advanced)

  • Rewrite the playbook servicehandler.yml and ensure that the ignore_errors: true line is removed. Instead set the state of the task to failed when and only when the output of systemctl status httpd contains the string “failed”.
  • Rerun your playbook and ensure it still runs fine.
  • By using an ansible ad hoc command, place an invalid configuration file /etc/httpd/conf/httpd.conf and backup the file before. Use the copy module to do this in ad hoc command.
  • Restart httpd by using an Ansible ad hoc command. This should fail since the config file is not valid.
  • Rerun your playbook and ensure it fails.
  • Fix the errors in the config file, restart httpd on node1 and rerun your playbook. Everything should be fine again.
Solution Task 5

Example servicehandler.yml:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
---
- hosts: web
  become: true
  tasks:
    - name: install httpd
      dnf:
        name: httpd
        state: present
    - name: check state of service httpd
      command: 'systemctl status httpd'
      register: status
      failed_when: "'failed' in status.stdout"
    - debug:
        var: status.stdout
    - name: start httpd
      command: 'systemctl start httpd'
      when: "'Active: active (running)' not in status.stdout"
1
ansible web -b -m copy -a "content='bli bla blup' dest=/etc/httpd/conf/httpd.conf backup=yes"

Now fix your apache config. You could use the backup of the file created in the previous ad-hoc command.

1
ansible web -b -m service -a "name=httpd state=restarted"

All done?

Last modified November 14, 2022: add http headers (7f665a8)