Bookmark this page

Guided Exercise: Controlling Task Execution

  • Use pre_tasks and post_tasks sections to control whether tasks run before or after roles, and listen directives to notify multiple handlers at the same time.

Outcomes

  • Control the execution order of tasks.

  • Trigger handlers using the listen directive.

As the student user on the workstation machine, use the lab command to prepare your system for this exercise.

This command creates an Ansible project in the /home/student/task-execution/ directory.

[student@workstation ~]$ lab start task-execution

Procedure 6.2. Instructions

  1. From a terminal, change to the /home/student/task-execution/ directory and review the deploy.yml playbook.

    [student@workstation ~]$ cd ~/task-execution
    [student@workstation task-execution]$ cat deploy.yml
    ---
    - name: Implementing Handlers
      hosts: web_servers
    
      pre_tasks:
        - name: Configuring Apache
          ansible.builtin.include_tasks: apache.yml
    
      roles:
        - role: firewall

    The deploy.yml playbook consists of one play. This play uses a pre_tasks section to include tasks that configure an Apache HTTPD web server, and then a roles section to run a role that allows access through the firewall.

  2. Edit the deploy.yml playbook to add tasks that notify handlers.

    1. Use the ansible.builtin.set_fact module to assign the static values 80/tcp for the web_port variable and public for the web_zone variable. Use changed_when: true to guarantee that the task always notifies the display variables handler.

      The content for the pre_tasks section should read as follows:

        pre_tasks:
          - name: Configuring Apache
            ansible.builtin.include_tasks: apache.yml
      
          - name: Setting web port and zone for firewall
            ansible.builtin.set_fact:
              web_port: 80/tcp
              web_zone: public
            changed_when: true
            notify: display variables
    2. After the roles section, add the post_tasks section with a task to copy the index.html file to the /var/www/html directory. Use the ansible.builtin.copy module to copy the file. Notify the verify connectivity handler if the task changes the managed host.

      The content for the post_tasks section should read as follows:

        roles:
          - role: firewall
      
        post_tasks:
          - name: Ensure the web content is copied
            ansible.builtin.copy:
              src: index.html
              dest: /var/www/html/
            notify: verify connectivity

      Note

      You could define the Ensure the web content is copied task under a tasks section because Ansible also runs the tasks section after the roles. However, to mirror the pre_tasks section, define the task under the post_tasks section.

  3. Add the handlers for the play. Two handlers must listen for the display variables notification in order to show the values for the web_port and the web_zone variables when they are defined. The same notification must trigger both handlers.

    In addition, add a handler named verify connectivity that verifies that the web content at http://{​{ ansible_facts['fqdn'] }​} can be retrieved at the end of the first play if the play changed the content. This confirms that the play worked.

    Important

    Make sure that you create this handlers section in the deploy.yml playbook at the end of the play.

    1. Create the handlers section at the end of the play, and include two similar handlers using the ansible.builtin.debug module to print the value of the web_port and the web_zone variables. Give them an arbitrary string as a name, and use the listen directive for the display variables notification.

      The handlers section is highlighted and should consist of the following content:

        post_tasks:
          - name: Ensure the web content is copied
            ansible.builtin.copy:
              src: index.html
              dest: /var/www/html/
            notify: verify connectivity
      
        handlers:
          - name: Showing the web port configured as pre_task
            ansible.builtin.debug:
              var: web_port
            listen: display variables
      
          - name: Showing the web zone configured as pre_task
            ansible.builtin.debug:
              var: web_zone
            listen: display variables
    2. Add the handler for the verify connectivity notification. Use the ansible.builtin.uri module to verify that the web content is available.

        handlers:
          - name: Showing the web port configured as pre_task
            ansible.builtin.debug:
              var: web_port
            listen: display variables
      
          - name: Showing the web zone configured as pre_task
            ansible.builtin.debug:
              var: web_zone
            listen: display variables
      
          - name: verify connectivity
            ansible.builtin.uri:
              url: http://{​{ ansible_facts['fqdn'] }​}
              status_code: 200
            become: false

      The complete deploy.yml file should consist of the following content:

      ---
      - name: Implementing Handlers
        hosts: web_servers
      
        pre_tasks:
          - name: Configuring Apache
            ansible.builtin.include_tasks: apache.yml
      
          - name: Setting web port and zone for firewall
            ansible.builtin.set_fact:
              web_port: 80/tcp
              web_zone: public
            changed_when: true
            notify: display variables
      
        roles:
          - role: firewall
      
        post_tasks:
          - name: Ensure the web content is copied
            ansible.builtin.copy:
              src: index.html
              dest: /var/www/html/
            notify: verify connectivity
      
        handlers:
          - name: Showing the web port configured as pre_task
            ansible.builtin.debug:
              var: web_port
            listen: display variables
      
          - name: Showing the web zone configured as pre_task
            ansible.builtin.debug:
              var: web_zone
            listen: display variables
      
          - name: verify connectivity
            ansible.builtin.uri:
              url: http://{​{ ansible_facts['fqdn'] }​}
              status_code: 200
            become: false
  4. Run the deploy.yml Ansible Playbook to verify your work and confirm that Ansible triggers your handlers. Pay attention to the order of execution of the handlers.

    In particular, you should see that the handlers subscribed to display variables called in the pre_tasks section run before the verify connectivity handler called in the post_tasks section.

    1. Run the deploy.yml playbook.

      [student@workstation task-execution]$ ansible-navigator run \
      > -m stdout deploy.yml
      
      PLAY [Implementing Handlers] ***************************************************
      
      TASK [Gathering Facts] *********************************************************
      ok: [serverf.lab.example.com]
      
      TASK [Configuring Apache] ******************************************************
      included: /home/student/task-execution/apache.yml for serverf.lab.example.com
      
      TASK [Installing apache] *******************************************************
      changed: [serverf.lab.example.com]
      
      TASK [Starting apache] *********************************************************
      changed: [serverf.lab.example.com]
      
      TASK [Setting web port and zone for firewall] **********************************
      changed: [serverf.lab.example.com]
      
      RUNNING HANDLER [Showing the web port configured as pre_task] ******************
      ok: [serverf.lab.example.com] => {
          "web_port": "80/tcp"
      }
      
      RUNNING HANDLER [Showing the web zone configured as pre_task] ******************
      ok: [serverf.lab.example.com] => {
          "web_zone": "public"
      }
      
      TASK [firewall : Ensure Firewall Port Configuration] ***************************
      changed: [serverf.lab.example.com] => (item={'port': '80/tcp', 'zone': 'public'})
      
      RUNNING HANDLER [firewall : reload firewalld] **********************************
      changed: [serverf.lab.example.com]
      
      TASK [Ensure the web content is copied] ****************************************
      changed: [serverf.lab.example.com]
      
      RUNNING HANDLER [verify connectivity] *************************************************
      ok: [serverf.lab.example.com]
      
      PLAY RECAP *********************************************************************
      serverf.lab.example.com    : ok=11   changed=6    unreachable=0    failed=0  ...
    2. Use the curl command to verify that the playbook successfully updated the host:

      [student@workstation task-execution]$ curl serverf.lab.example.com
      This is the index file
  5. Update two tasks in the revert.yml playbook to notify handlers and add a new handler to the playbook.

    1. Add a notify: package check statement to the Uninstall apache task. Add a notify: post handler statement to the Removing index.html file task. After you modify the revert.yml file, the content for the playbook should read as follows:

      ...output omitted...
        tasks:
          - name: Uninstall apache
            ansible.builtin.yum:
              name: httpd
              state: absent
              autoremove: true
            notify: package check
      
        post_tasks:
          - name: Removing index.html file
            ansible.builtin.file:
              path: /var/www/html/index.html
              state: absent
            notify: post handler
      ...output omitted...
    2. In the revert.yml playbook, create a handler called post handler that uses the ansible.builtin.debug module to print The index.html file was deleted to stdout.

      The complete revert.yml file should consist of the following content:

      ---
      - name: Cleaning Firewall rules
        hosts: web_servers
      
        roles:
          - role: firewall
            vars:
              firewall_rules:
                - port: 80/tcp
                  zone: public
                  state: disabled
      
        tasks:
          - name: Uninstall apache
            ansible.builtin.yum:
              name: httpd
              state: absent
              autoremove: true
            notify: package check
      
        post_tasks:
          - name: Removing index.html file
            ansible.builtin.file:
              path: /var/www/html/index.html
              state: absent
            notify: post handler
      
        handlers:
          - name: Gather package facts
            ansible.builtin.package_facts:
              manager: auto
            listen: package check
      
          - name: Check for the httpd package
            ansible.builtin.debug:
              msg: "httpd is not installed!"
            when: "'httpd' not in ansible_facts['packages']"
            listen: package check
      
          - name: post handler
            ansible.builtin.debug:
              msg: The index.html file was deleted
  6. Run the revert.yml Ansible Playbook to verify your work and confirm that Ansible triggers your handlers. Pay attention to the order of execution of the handlers.

    1. Run the revert.yml playbook.

      [student@workstation task-execution]$ ansible-navigator run \
      > -m stdout revert.yml
      
      PLAY [Cleaning Firewall rules] *************************************************
      
      TASK [Gathering Facts] *********************************************************
      ok: [serverf.lab.example.com]
      
      TASK [firewall : Ensure Firewall Port Configuration] ***************************
      changed: [serverf.lab.example.com] => (item={'port': '80/tcp', 'zone': 'public', 'state': 'disabled'})
      
      TASK [Uninstall apache] ********************************************************
      changed: [serverf.lab.example.com]
      
      RUNNING HANDLER [firewall : reload firewalld] **********************************
      changed: [serverf.lab.example.com]
      
      RUNNING HANDLER [Gather package facts] *****************************************
      ok: [serverf.lab.example.com]
      
      RUNNING HANDLER [Check for the httpd package] **********************************
      ok: [serverf.lab.example.com] => {
          "msg": "httpd is not installed!"
      }
      
      TASK [Removing index.html file] ************************************************
      changed: [serverf.lab.example.com]
      
      RUNNING HANDLER [post handler] *************************************************
      ok: [serverf.lab.example.com] => {
          "msg": "The index.html file was deleted"
      }
      
      PLAY RECAP *********************************************************************
      serverf.lab.example.com    : ok=9    changed=4    unreachable=0    failed=0  ...
    2. Use the curl command to verify that the playbook successfully updated the host:

      [student@workstation task-execution]$ curl serverf.lab.example.com
      curl: (7) Failed to connect to serverf.lab.example.com port 80: No route to host

Finish

On the workstation machine, change to the student user home directory and use the lab command to complete this exercise. This step is important to ensure that resources from previous exercises do not impact upcoming exercises.

[student@workstation ~]$ lab finish task-execution

This concludes the section.

Revision: do374-2.2-82dc0d7