Chapter 5. Getting Started with Playbooks

This chapter covers the following subjects:

Exploring Your First Playbook

Working with YAML

Managing Multiplay Playbooks

The following RHCE exam objectives are covered in this chapter:

• Understand core components of Ansible

• Plays

• Playbooks

• Create Ansible plays and playbooks

• Create playbooks to configure systems to a specified state

“Do I Know This Already?” Quiz

The “Do I Know This Already?” quiz allows you to assess whether you should read this entire chapter thoroughly or jump to the “Exam Preparation Tasks” section. If you are in doubt about your answers to these questions or your own assessment of your knowledge of the topics, read the entire chapter. Table 5-1 lists the major headings in this chapter and their corresponding “Do I Know This Already?” quiz questions. You can find the answers in Appendix A, “Answers to the ’Do I Know This Already?’ Quizzes and Review Questions.

Table 5-1 “Do I Know This Already?” Section-to-Question Mapping

Image

1. Which of the following do you normally find on the first line of a playbook?

a. The name of the first play

b. The name of the hosts that are addressed

c. ---

d. ...

2. Each play must have at least three parameters in its header. Which of the following is not one of them?

a. hosts

b. tasks

c. name

d. become

3. Which statements about indentation are true?

a. Indentation is used to identify the relationship between parent and child objects.

b. Spaces may not be used.

c. Tabs may not be used.

d. Plays without indentation are hard to read but do work.

4. How do you undo modifications that are applied from a playbook?

a. Use ansible-playbook -u.

b. Use ansible-playbook -u --force.

c. You cannot undo changes made by a playbook.

d. You can create a playbook that accomplishes the opposite of the original playbook.

5. What status would you expect to see while running a task that has modified the managed system?

a. ok

b. changed

c. modified

d. applied

6. Which statement about using YAML lists in playbooks is true?

a. Any module can use a YAML list to specify the names of items that need to be processed.

b. YAML lists can be used at a play level, not at a tasks level.

c. The service module does not support YAML lists to manage multiple servers.

d. A YAML list can be used to run multiple modules.

7. Which option can you use to feed multiple lines of text to a text file, while keeping the newline characters to guarantee proper formatting?

a. |

b. >

c. :

d.

8. Which of the following can you use to verify which tasks in a playbook would trigger a change?

a. --syntax-check

b. --dry-run

c. -vvv

d. -C

9. Which of the following indicates the best use case for a multiplay playbook?

a. A web server must be installed on server1; a database server must be installed on server2.

b. An FTP server must be installed on server1, after which localhost is used to test connectivity to that server.

c. A task must run using a different user account.

d. A play must run with different privilege escalation parameters.

10. Which of the following is not a benefit of using a multiplay playbook?

a. Different hosts may be addressed.

b. Plays may run with different user accounts.

c. Plays can be scheduled separately.

d. Some plays may be configured to run without privilege escalation.

Foundation Topics

Exploring Your First Playbook

Ansible is all about running playbooks. In this section you learn how to move forward from entering tasks as ad hoc commands on the command line to writing Ansible playbooks.

From Ad Hoc Commands to Playbook

Before we get into the details about playbooks and explore the possibilities of using them, let’s run a playbook. In Chapter 4, “Using Ad Hoc Commands,” you learned how to work with ad hoc commands, and in Listing 4-5, you created a Bash script to run some of these commands against managed nodes. Listing 5-1 shows you the commands.

Listing 5-1 Running Ad Hoc Commands from a Script

#!/bin/bash

ansible all -m yum -a "name=httpd state=installed"
ansible all -m service -a "name=httpd state=started enabled=yes"

All that you do in this script can be done in a playbook as well. Just take a look at the playbook example in Listing 5-2 to see what such a playbook would look like. If you look close enough, you can see that all elements that were specified in the ad hoc commands also occur in the playbook.

Listing 5-2 Configuring Hosts from a Playbook

---
- name: install start and enable httpd
  hosts: all
  tasks:
  - name: install package
    yum:
      name: httpd
      state: installed
  - name: start and enable service
    service:
      name: httpd
      state: started
      enabled: yes

Playbook Elements

A playbook is a collection of plays. Each play targets specific hosts, and in each play a list of tasks is specified. In the sample playbook in Listing 5-2, one play with the name “install start and enable httpd” is defined.

Playbooks are written in the YAML format and are normally saved with either the .yml or the .yaml extension. YAML format essentially specifies objects as key-value pairs. Dashes can be used to specify lists of embedded objects. For more details about YAML, see the section “Working with YAML” later in this chapter.

At the start of each playbook, you find three dashes. Optionally, you may also find three dots at the end of the playbook. Using these characters makes it easy to embed the playbook code into something else and easily isolate the playbook code when it is included.

While you’re working with playbooks, the target hosts are specified in the play, not in the command that runs the playbook (which happens in ad hoc commands). After you indicate the target hosts, you specify a list of tasks. Each item in the list is identified with a hyphen.

For each task, you specify the Ansible module that the task is running and a name. Notice that using names for tasks is not mandatory but is highly recommended, because using names makes it a little easier to identify which tasks have been able to run successfully. Next, you should identify the arguments that the task should be running.

To identify hierarchical relations in playbooks, you use indentation. The basic rules for indentation are easy:

• Data elements at the same level in the hierarchy must have the same indentation.

• Items that are children (properties) and another element are indented more than the parents.

You create indentation using spaces. There is no requirement for how many spaces to use, but using two spaces is common. Using tabs for indentation is not permitted.

Within the playbook, one or more plays are defined. Plays are the highest level in the playbook, and each play starts with a hyphen. The reason is that the playbook defines a list of plays, and it is valid if the list contains just one play. All properties of the play (name, hosts, and the word tasks) are indented at the same level, and next there is a list of tasks. The list of tasks is a property of the play, and these tasks are indented one level deeper than the parent items to show the hierarchical relation between play and tasks. The next level of indentation happens at the task argument level, where each argument that is passed to a task is indented one more level deeper.


Tip

To make working with indentation easier, you may configure the vi editor. If the following line is included in the file ~/.vimrc, indentation automatically happens correctly if vi detects that a YAML file is created. Notice this requires you to either use the .yml or the .yaml extension to the files.

autocmd FileType yaml setlocal ai ts=2 sw=2 et

In playbooks, you may find one or more plays. Each play has some required elements, which are listed in Table 5-2.

Image

Table 5-2 Playbook Play Required Keys

Image

Running the Playbook

To run the playbook, you use the command ansible-playbook listing52.yaml. The result is shown in Listing 5-3. Notice that depending on the state of the managed machine, you might see a slightly different result, showing “changed” instead of “ok.”

Listing 5-3 Running a Playbook Output

[ansible@control ~]$ ansible-playbook listing52.yaml

PLAY [install start and enable httpd] ***********************************************************************

TASK [Gathering Facts] ***********************************************************************
ok: [ansible2]
ok: [ansible1]

TASK [install package] ***********************************************************************
ok: [ansible1]
ok: [ansible2]

TASK [start and enable service] *********************************************************************
ok: [ansible2]
ok: [ansible1]

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

In the output of the ansible-playbook command, you always see the same elements. The output starts with the name of the play. This is the name that you defined yourself in the name part of each play. Next, you get an overview of the tasks that you defined in the playbook. Each task is identified by the name that you used for the task in the playbook code, and for each task, the ansible-playbook command indicates on which managed host it was executed and whether that was successful.

Before the list of tasks that you defined, the ansible-playbook command gathers facts. Fact gathering is an important part of Ansible, where Ansible learns about current configuration and settings on managed nodes; you’ll learn more about this topic in Chapter 6, “Working with Variables and Facts.”

The last element is the Play Recap. In this element you get an overview of the status of each task. If you see “ok” in the task result status, the task has executed successfully and no changes were required. If a task gives the result status “changed,” a task has successfully applied modifications to apply the desired state as defined in the playbook. We discuss the other output status options later.

Undoing Playbook Modifications

Undoing playbook modifications is easy to understand. Ansible does not offer any undo functionality, so if you created a playbook and later regret the modifications the playbook has made, you must write a new playbook to define a new desired state that reverts the changes you applied earlier. In Exercise 5-1 you practice all the skills discussed so far and run your first playbook.

Exercise 5-1 Running Your First Playbook

1. Type vim exercise51.yaml to open a new file that will contain the desired playbook code. Make sure the file is created in your home directory, where an ansible.cfg and inventory file already exist.

2. Type three dashes to start the playbook code:

---

3. Start the play definition on a new line. This play definition starts with a dash, which is followed by a space and name:, which is followed by the name of the play:

---
- name: install and start the vsftpd service

4. You need to add a line that defines the hosts that the play should manage. Notice that this line is indented at the same level as the word “name” because this line is a part of the same play definition:

---
- name: install and start the vsftpd service
  hosts: all

5. In the next part of the play, you define the tasks that will be executed by this play. Under the word hosts, indented at the same level, type tasks:. There is nothing after the colon because the value of the key tasks is a list of tasks, which is provided on the next couple of lines:

---
- name: install and start the vsftpd service
  hosts: all
  tasks:

6. At this point, you can start defining the tasks. The first task ensures that the yum module is used to define the vsftpd package. Notice the indentation, which identifies that the task is a child element of the play:

---
- name: install and start the vsftpd service
  hosts: all
  tasks:
  - name: install vsftpd
    yum:

7. At this point, you may specify the arguments to the yum module. Because these arguments are child elements in relation to the yum module, you need another level of indentation:

---
- name: install and start the vsftpd service
  hosts: all
  tasks:
  - name: install vsftpd
    yum:
      name: vsftpd
      state: latest

8. The first task is now defined, and you can specify the next task that calls the service module to start and enable the vsftpd service. Notice that this task is indented at the same level as the yum task:

---
- name: install and start the vsftpd service
  hosts: all
  tasks:
  - name: install vsftpd
    yum:
      name: vsftpd
      state: latest
  - name: start and enable vsftpd service
    service:
      name: vsftpd
      state: started
      enabled: yes

9. The playbook is now completed, so write your changes to the file and quit the editor. Next, use ansible-playbook exercise51.yaml to run the playbook.

10. Observe the output of the playbook and verify that everything has executed all right.

Working with YAML

YAML (an acronym for YAML Ain’t Markup Language according to some, and Yet Another Markup Language according to others) is an easy-to-read data-serialization language. YAML is a common language used for configuration files, not only in Ansible but also in other environments, like Kubernetes and in configuration of some Linux services. YAML isn’t difficult to use, but you should know a few things when working with YAML.

Indentation

To start with, YAML uses indentation. As discussed earlier, indentation identifies relations between parts of the configuration so that you can easily see what is a parent object and what is a child object. The most important rule in indentation is that you must use spaces and not tabs.

Using Key-Value Pairs

YAML is all about defining key-value pairs, also known as dictionaries. An example of such a key-value pair is name: vsftpd. Key-value pairs can be defined in two ways: key: value or key=value. Of these two, the first method is preferred, but the second way works also.

If an object in YAML needs multiple key-value pairs to define its properties, it is common to define one key-value pair on a line. If the key=value format is used, it’s possible to define all the multiple key-value pairs on one line. The sample playbook in Listing 5-4 shows such an example.

Listing 5-4 Multiple Ways to Define Key-Value Pairs

---
- name: deploy vsftpd
  hosts: ansible2
  tasks:
  - name: install vsftpd
    yum: name=vsftpd
  - name: enable vsftpd
    service: name=vsftpd enabled=true
  - name: create readme file
    copy:
      content: "welcome to the FTP server
"
      dest: /var/ftp/pub/README
      force: no
      mode: 0444
...

In the sample playbook in Listing 5-4, three tasks are defined. In the first two tasks, all key-value pairs are defined in the key=value format on the same line as the name of the module that is used. The third task defines all key-value pairs in the key: value format on separate lines. To keep your playbooks readable, you should use only the latter approach.


Note

In Ansible, on multiple occasions it’s possible to use a different syntax. This section is provided as an introduction to working with YAML, not as a complete overview to working with the language. If you need a more complete overview of YAML syntax variations, look for “YAML Syntax” in the Ansible documentation.


Notice that in the third task the copy module is used to copy a line of text into a destination file. This is an easy way to create a configuration file that contains some standard text. There are other modules to manage text that needs to be copied into a file; you’ll learn more about them in Chapter 8, “Deploying Files.”

Understanding YAML Lists

While you’re working with YAML in Ansible playbooks, keys can have one value, and some keys can have multiple values. No standard rule defines what is the case in which situation. Whether a key can contain multiple values depends on the Ansible module. When you use the yum module, for instance, you can specify a list of packages to the name key. When you use the service module, for instance, it’s not possible to specify a list as the argument to the name key. The module documentation normally indicates whether it’s possible to specify a list as a value to a specific key. Listing 5-5 shows an example of a playbook that uses a list to define the values of a key.

Listing 5-5 Installing Multiple Packages Using Lists

---
- name: using lists
  hosts: all
  tasks:
  - name: install packages
    yum:
      name:
      - nmap
      - httpd
      - vsftpd
      state: latest

Tip

The yum module can work with different package states. For example, you can use state: installed to make sure that a package is installed and use state: latest to ensure that the latest version of a package is installed, which triggers a package update if needed.


Using YAML Strings

In YAML files, you include strings on multiple occasions. Using strings is not difficult because the string doesn’t have to be escaped by using quotation marks. However, you are allowed to use quotation marks anyway. This means that all the following notations are valid:

Line of text

“Line of text”

‘Line of text’

There are two ways to deal with multiline strings. You can use the | sign in a multiline string to take over all newline characters. If all text in a multiline string just needs to be treated as a line of text, without any further formatting, you can use the > sign. Use the | sign if you want to maintain formatting. Use the > sign if you want to split text over multiple lines in the playbook for better readability, but the lines don’t have to be written as multiple lines in the target file.

Verifying Syntax

Because you can easily make a typo or indent items at the wrong level, it might be wise to verify syntax. The ansible-playbook command provides the --syntax-check option for this task. Listing 5-6 shows what the result of this command might look like.

Listing 5-6 Checking Syntax with ansible-playbook --syntax-check

[ansible@control ~]$ ansible-playbook --syntax-check listing56.yaml
ERROR! Syntax Error while loading YAML.
  mapping values are not allowed in this context

The error appears to be in ’/home/ansible/listing54.yaml’: line 8, column 12, but may
be elsewhere in the file depending on the exact syntax problem.

The offending line appears to be:

    name: httpd
      state: latest
           ^ here

As you can see, the ansible-playbook command tries to make a reasonable guess about where the syntax problem occurs. Based on the exact error, this guess may be accurate or totally inaccurate. In this case it is quite accurate, as you can see in Listing 5-7, which shows the code that is used to produce the error in Listing 5-6 (as the error occurs just one line earlier).


Tip

Where relevant, the playbook code that is used in the listings in this book is available in the book github repository. If you haven’t done so yet, you can get the files by using the command git clone https://github.com/sandervanvugt/rhce8-book.


Listing 5-7 Sample YAML File with Errors

---
- name: install start and enable httpd
  hosts: all
  tasks:
  - name: install package
    yum:
    name: httpd
      state: latest
  - service:
    name: httpd
      state: started
      enabled: yes

As seen in the output of the ansible-playbook --syntax-check command in Listing 5-6, the output is quite accurate while indicating the exact location of the problem. In Listing 5-7, you might also notice a second problem that was not found in the code; the line name: httpd should be indented as a child element to the service: module. The reason is that the ansible-playbook --syntax-check stops after finding the first error. You have to fix this error and run the command again to see the second error as well.

One last word about --syntax-check. It may be a useful option, but you should realize that the ansible-playbook command checks syntax by default. So if you had just run ansible-playbook listing56.yaml, you would have seen the exact same message.

Performing a Playbook Dry Run

Before you actually run a playbook and make all modifications to the managed hosts, it may make sense to perform a dry run. You can do this by using the ansible-playbook -C myplaybook.yaml command. While you perform a dry run, the ansible-playbook command shows you which hosts would be changed by running the playbook without actually applying the changes. See Listing 5-8 for an example. After that, you can work on Exercise 5-2 to practice your YAML skills.

Listing 5-8 Performing a Playbook Dry Run

[ansible@control ~]$ ansible-playbook -C listing56.yaml

PLAY [using lists] ******************************************************************************************

TASK [Gathering Facts] **************************************************************************************
ok: [ansible2]
ok: [ansible1]

TASK [install packages] *************************************************************************************
changed: [ansible2]
changed: [ansible1]

PLAY RECAP **************************************************************************************************
ansible1                   : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
ansible2                   : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Exercise 5-2 Practicing YAML Skills

1. Open an editor to create the file exercise52.yaml. Define the playbook header by including the following lines:

---
- name: copy multiline text
  hosts: ansible1
  tasks:

2. Add the first task. In this task you use the copy module, using content and the | sign to copy two lines of text to a file that does not yet exist:

---
- name: copy multiline text
  hosts: ansible1
  tasks:
  - name: copy text
    copy:
      content: |
        line 1
        line 2
      dest: /tmp/multiline1.txt

3. Add a second task that also uses the copy module but this time uses the > sign:

---
- name: copy multiline text
  hosts: ansible1
  tasks:
  - name: copy text
    copy:
      content: |
        line 1
        line 2
      dest: /tmp/multiline1.txt
  - name: copy more text
    copy:
      content: >
        line 1
        line 2
      dest: /tmp/multiline2.txt

4. Use ansible-playbook exercise52.yaml to run the playbook and verify that in the output you see two tasks reporting a changed status.

5. Verify the files that have been created. First, use ansible ansible1 -a “cat /tmp/multiline1.txt” to verify the contents of the first file. Notice that it contains multiple lines.

6. Next, use ansible ansible1 -a “cat /tmp/multiline2.txt” to verify that the file contains all the separate lines on one single line.

Managing Multiplay Playbooks

Up to now, you’ve worked with a playbook that has just one play. Many playbooks that you find out in the wild work with multiple plays though. Using multiple plays in a playbook makes it easy to perform the complete setup of a managed environment, where you can set up one group of servers with one specific configuration and another group of servers with another configuration. When you work with multiplay playbooks, each play has its own list of hosts to address.

Multiplay Playbook Considerations

The main benefit of running a multiplay playbook is that you can configure multiple plays that should all be run in the same procedure. In each play, different connectivity options can be used. To start with, you can define different hosts or host groups, but it’s also possible to use different connection parameters that may even overwrite default parameters that have been set in the ansible.cfg file. Think of parameters like become: no, which indicates that no privilege escalation is needed, or remote_user: bob, which instructs the playbook to run the remote tasks as user bob instead of using the default user account.

When you are writing playbooks, there are many options. It might seem tempting to write huge playbooks, including many tasks and multiple plays. Doing so is not recommended as a best practice though. To summarize the most important guideline from the best practices: keep it simple. If there is no need to put everything in one playbook, then simply don’t. The bigger the playbook, the more difficult it will be to troubleshoot.

In many cases it’s a much better solution to write multiple smaller playbooks and use includes to include functionality from other playbooks. One advantage is that this approach makes troubleshooting a lot easier. Another advantage is that this approach makes it easy to develop a toolkit with many small playbooks that can be used in a flexible way to perform a wide range of management tasks. You’ll read more about this approach in Chapter 10, “Using Ansible in Large Environments.”

Multiplay Playbook Example

Listing 5-9 shows an example of a multiplay playbook. The first play sets up the httpd service on a managed host. In the second play, the uri module is used to test web server accessibility. If no further configuration is used, this module tries to connect to a target web server and expects the HTTP return code 200, indicating that the target web page was accessed successfully.

In this multiplay playbook, the first play is executed on the host group all. This host group includes all hosts that are defined in inventory, but it does not include localhost. The host localhost is not defined in inventory; it’s an implicit host that is always usable and that refers to the Ansible control machine. Using localhost can be an efficient way to verify the accessibility of services on managed hosts.

Listing 5-9 Multiplay Playbook Example

---
- name: install start and enable httpd
  hosts: all
  tasks:
  - name: install package
    yum:
      name: httpd
      state: latest
  - name: start and enable service
    service:
      name: httpd
      state: started
      enabled: yes

- name: test httpd accessibility
  hosts: localhost
  tasks:
  - name: test httpd access
    uri:
      url: http://ansible1

In Listing 5-10 you can see what happens when you run the playbook. The uri module indicates that the status code is −1, which indicates the httpd service could not be accessed on the managed host. The exit code 200 was expected, and because this is not the case, the uri module returns an error. Do you have any idea why? You don’t need to fix this problem yet; you’ll do this in the end-of-chapter lab with this chapter.

Listing 5-10 Playbook Result

[ansible@control ~]$ ansible-playbook listing59.yaml

PLAY [install start and enable httpd] ***********************************************************************

TASK [Gathering Facts] **************************************************************************************
ok: [ansible2]
ok: [ansible1]

TASK [install package] **************************************************************************************
ok: [ansible2]
ok: [ansible1]

TASK [start and enable service] *****************************************************************************
ok: [ansible2]
ok: [ansible1]

PLAY [test httpd accessibility] *****************************************************************************

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

TASK [test httpd access] ************************************************************************************
fatal: [localhost]: FAILED! => {"changed": false, "content": "", "elapsed": 0, "msg": "Status code was -1 and not [200]: Request failed: <urlopen error [Errno 113] No route to host>", "redirected": false, "status": -1, "url": "http://ansible1"}

PLAY RECAP **************************************************************************************************
ansible1                   : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
ansible2                   : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
localhost                  : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

Increasing Output Verbosity

While you are analyzing playbook errors, it might be helpful to increase playbook output verbosity. To do so, you can use the -v command-line option one time or multiple times. Table 5-3 gives an overview.

Table 5-3 Output Verbosity Options Overview

Image

Increasing output verbosity can be useful and provide you with additional information. Output verbosity must be used with moderation, though. While -vv can be useful in many cases, the -vvvv option just overloads you with irrelevant information in most cases. Listing 5-11 shows partial output of the command ansible-playbook -vv listing59.yaml, and Listing 5-12 shows partial output of the command ansible-playbook -vvvv listing59.yaml.

Listing 5-11 ansible-playbook -vv Partial Output

[ansible@control ~]$ ansible-playbook -vv listing59.yaml
ansible-playbook 2.9.5
  config file = /home/ansible/ansible.cfg
  configured module search path = [’/home/ansible/.ansible/plugins/modules’, ’/usr/share/ansible/plugins/modules’]
  ansible python module location = /usr/lib/python3.6/site-packages/ansible
  executable location = /usr/bin/ansible-playbook
  python version = 3.6.8 (default, Nov 21 2019, 19:31:34) [GCC 8.3.1 20190507 (Red Hat 8.3.1-4)]
Using /home/ansible/ansible.cfg as config file

PLAYBOOK: listing59.yaml ************************************************************************************
2 plays in listing59.yaml

PLAY [install start and enable httpd] ***********************************************************************

TASK [Gathering Facts] **************************************************************************************
task path: /home/ansible/listing59.yaml:2
ok: [ansible2]
ok: [ansible1]
META: ran handlers

TASK [install package] **************************************************************************************
task path: /home/ansible/listing59.yaml:5
ok: [ansible2] => {"changed": false, "msg": "Nothing to do", "rc": 0, "results": []}
ok: [ansible1] => {"changed": false, "msg": "Nothing to do", "rc": 0, "results": []}

Listing 5-12 ansible-playbook -vvvv Partial Output

[ansible@control ~]$ ansible-playbook -vvvv listing59.yaml
ansible-playbook 2.9.5
  config file = /home/ansible/ansible.cfg
  configured module search path = [’/home/ansible/.ansible/plugins/modules’, ’/usr/share/ansible/plugins/modules’]
  ansible python module location = /usr/lib/python3.6/site-packages/ansible
  executable location = /usr/bin/ansible-playbook
  python version = 3.6.8 (default, Nov 21 2019, 19:31:34) [GCC 8.3.1 20190507 (Red Hat 8.3.1-4)]
Using /home/ansible/ansible.cfg as config file
setting up inventory plugins
host_list declined parsing /home/ansible/inventory as it did not pass its verify_file() method
script declined parsing /home/ansible/inventory as it did not pass its verify_file() method
auto declined parsing /home/ansible/inventory as it did not pass its verify_file() method
Parsed /home/ansible/inventory inventory source with ini plugin
Loading callback plugin default of type stdout, v2.0 from /usr/lib/python3.6/site-packages/ansible/plugins/callback/default.py

PLAYBOOK: listing59.yaml ************************************************************************************
Positional arguments: listing59.yaml
verbosity: 4
remote_user: ansible
connection: smart
timeout: 10
become: True
become_method: sudo
tags: (’all’,)
inventory: (’/home/ansible/inventory’,)
forks: 5
2 plays in listing57.yaml

PLAY [install start and enable httpd] ***********************************************************************

TASK [Gathering Facts] **************************************************************************************
task path: /home/ansible/listing59.yaml:2
<ansible2> ESTABLISH SSH CONNECTION FOR USER: ansible
<ansible2> SSH: EXEC ssh -vvv -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ’User="ansible"’ -o ConnectTimeout=10 -o ControlPath=/home/ansible/.ansible/cp/b95d9eb347 ansible2 ’/bin/sh -c ’"’"’echo ~ansible && sleep 0’"’"’’
<ansible1> ESTABLISH SSH CONNECTION FOR USER: ansible
<ansible1> SSH: EXEC ssh -vvv -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ’User="ansible"’ -o ConnectTimeout=10 -o ControlPath=/home/ansible/.ansible/cp/88f8e128b5 ansible1 ’/bin/sh -c ’"’"’echo ~ansible && sleep 0’"’"’’
<ansible2> (0, b’/home/ansible
’, b"OpenSSH_8.0p1, OpenSSL 1.1.1c FIPS  28 May 2019
debug1: Reading configuration data /etc/ssh/ssh_config
debug3: /etc/ssh/ssh_config line 51: Including file /etc/ssh/ssh_config.d/05-redhat.conf depth 0
debug1: Reading configuration data /etc/ssh/ssh_config.d/05-redhat.conf
debug2: checking match for ’final all’ host ansible2 originally ansible2
debug3: /etc/ssh/ssh_config.d/05-redhat.conf line 3: not matched ’final’
debug2: match not found
debug3: /etc/ssh/ssh_config.d/05-redhat.conf line 5: Including file /etc/crypto-policies/back-ends/openssh.config depth 1 (parse only)
debug1: Reading configuration data /etc/crypto-policies/back-ends/openssh.config
debug3: gss kex names ok: [gss-gex-sha1-,gss-group14-sha1-]
debug3: kex names ok: [curve25519-sha256,[email protected],ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1]
debug1: configuration requests final Match pass
debug1: re-parsing configuration
debug1: Reading configuration data /etc/ssh/ssh_config
debug3: /etc/ssh/ssh_config line 51: Including file /etc/ssh/ssh_config.d/05-redhat.conf depth 0
debug1: Reading configuration data /etc/ssh/ssh_config.d/05-redhat.conf
debug2: checking match for ’final all’ host ansible2 originally ansible2
debug3: /etc/ssh/ssh_config.d/05-redhat.conf line 3: matched ’final’
debug2: match found
debug3: /etc/ssh/ssh_config.d/05-redhat.conf line 5: Including file /etc/crypto-policies/back-ends/openssh.config depth 1
debug1: Reading configuration data /etc/crypto-policies/back-ends/openssh.config
debug3: gss kex names ok: [gss-gex-sha1-,gss-group14-sha1-]
debug3: kex names ok: [curve25519-sha256,[email protected],ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1]
debug1: auto-mux: Trying existing master
debug2: fd 4 setting O_NONBLOCK
debug2: mux_client_hello_exchange: master version 4
debug3: mux_client_forwards: request forwardings: 0 local, 0 remote
debug3: mux_client_request_session: entering
debug3: mux_client_request_alive: entering
debug3: mux_client_request_alive: done pid = 2384
debug3: mux_client_request_session: session request sent
debug3: mux_client_read_packet: read header failed: Broken pipe
debug2: Received exit status from master 0
")
<ansible2> ESTABLISH SSH CONNECTION FOR USER: ansible
<ansible2> SSH: EXEC ssh -vvv -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ’User="ansible"’ -o ConnectTimeout=10 -o ControlPath=/home/ansible/.ansible/cp/b95d9eb347 ansible2 ’/bin/sh -c ’"’"’( umask 77 && mkdir -p "` echo /home/ansible/.ansible/tmp/ansible-tmp-1585565643.3326187-58978915363330 `" && echo ansible-tmp-1585565643.3326187-58978915363330="` echo /home/ansible/.ansible/tmp/ansible-tmp-1585565643.3326187-58978915363330 `" ) && sleep 0’"’"’’
<ansible1> (0, b’/home/ansible
’, b"OpenSSH_8.0p1, OpenSSL 1.1.1c FIPS  28 May 2019
debug1: Reading configuration data /etc/ssh/ssh_config
debug3: /etc/ssh/ssh_config line 51: Including file /etc/ssh/ssh_config.d/05-redhat.conf depth 0
debug1: Reading configuration data /etc/ssh/ssh_config.d/05-redhat.conf
debug2: checking match for ’final all’ host ansible1 originally ansible1
debug3: /etc/ssh/ssh_config.d/05-redhat.conf line 3: not matched ’final’
debug2: match not found
debug3: /etc/ssh/ssh_config.d/05-redhat.conf

If you think Listing 5-12 is too much, that’s exactly the idea I want to transmit. The -vvvv output shows all there is to show, and it’s not uncommon to see it producing thousands of lines of output code. There are very few situations in which that information may be useful, however.


Exam tip

Of the troubleshooting options you’ve seen so far, the output verbosity options are not the most useful. Using common sense is. Most errors in playbooks are the result of logic errors, where the flow of tasks in a playbook has not been well thought through. It is relatively easy to avoid those types of errors: don’t include too many tasks in a play, and don’t include too many plays in a playbook. That way, you make it easy to avoid losing oversight.


In Exercise 5-3 you work on a multiplay playbook.

Exercise 5-3 Creating a Multiplay Playbook

1. Use an editor to create the file exercise53.yaml and create the first play:

---
- name: enable web server
  hosts: ansible1
  tasks:
  - name: install stuff
    yum:
    - httpd
    - firewalld
  - name: create a welcome page
    copy:
      content: "welcome to the webserver
"
      dest: /var/www/html/index.html
  - name: enable webserver
    service:
      name: httpd
      state: started
      enabled: true
  - name: enable firewall
    service:
      name: firewalld
      state: started
      enabled: true
  - name: open service in firewall
    firewalld:
      service: http
      permanent: true
      state: enabled
      immediate: yes

2. Continue by adding the second play to complete the playbook. Notice the use of the return_content in the uri module, which ensures that the result of the command is shown while running the playbook:

---
- name: enable web server
  hosts: ansible1
  tasks:
  - name: install stuff
    yum:
      name:
      - httpd
      - firewalld
  - name: create a welcome page
    copy:
      content: "welcome to the webserver
"
      dest: /var/www/html/index.html
  - name: enable webserver
    service:
      name: httpd
      state: started
      enabled: true
  - name: enable firewall
    service:
      name: firewalld
      state: started
      enabled: true
  - name: open service in firewall
    firewalld:
      service: http
      permanent: true
      state: enabled
      immediate: yes

- name: test webserver access
  hosts: localhost
  become: no
  tasks:
  - name: test webserver access
    uri:
      url: http://ansible1
      return_content: yes
      status_code: 200

3. Verify playbook syntax by using ansible-playbook --syntax-check exercise53.yaml.

4. Run the playbook by using ansible-playbook -vv exercise53.yaml.

Summary

In this chapter you read how to work with playbooks. To start with, you ran a sample playbook and verified its results. Next, you learned about the YAML file format used in playbooks and some of its most important features. In the last section you read how to work with multiplay playbooks and learned when using them makes sense.

Exam Preparation Tasks

As mentioned in the section “How to Use This Book” in the Introduction, you have a couple of choices for exam preparation: the exercises here, Chapter 16, “Final Preparation,” and the exam simulation questions on the companion website.

Review All Key Topics

Review the most important topics in this chapter, noted with the Key Topics icon in the outer margin of the page. Table 5-4 lists a reference of these key topics and the page numbers on which each is found.

Image

Table 5-4 Key Topics for Chapter 5

Image

Memory Tables

Print a copy of Appendix D, “Memory Tables” (found on the companion website), or at least the section for this chapter, and complete the tables and lists from memory. Appendix E, “Memory Tables Answer Key,” also on the companion website, includes completed tables and lists to check your work.

Define Key Terms

Define the following key terms from this chapter, and check your answers in the glossary:

dictionary

key-value

list

play

playbook

task

YAML

Review Questions

1. Which option do you use to show the most verbose output to the ansible-playbook command?

2. What characters must be used for indentation in YAML files?

3. How can you verify syntax of an Ansible playbook?

4. Which module can you use to verify connectivity to a web server?

5. Which module can you use to add a few lines of text to a file?

6. What is the use case for using a > sign before specifying a string of text in a playbook?

7. When should multiple playbooks be used instead of multiplay playbooks?

8. What does a task show that has successfully been executed but does not trigger any changes?

9. If a playbook has run three tasks, and none of these tasks trigger any changes on the managed hosts, how many times would you see “ok” in the playbook output?

10. Which exit code does the uri module look for to check whether web content is accessible?

End-of-Chapter Lab

In the end-of-chapter lab with this chapter, you analyze what is wrong with a playbook and fix it.

Lab 5-1

Run the playbook listing57.yaml. As you’ve seen before, it generates an error. Fix the error by using the following directions:

• What specific information do you obtain when increasing verbosity?

• Does it help to perform a syntax check?

• Does it help to perform a dry run?

• Which module is required to fix this playbook?

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.221.13.173