• No results found

Writing a playbook

Playbook files may begin with the YAML document marker (---). This marker is optional and has no impact on the execution of the playbook.

Conversely, the YAML document terminator (...) may be used to terminate a playbook file. This entry is also optional, and if it is not present the end of the file will automatically be the end of the playbook.

Within a playbook file, plays are expressed in a list context where each play is defined using a YAML dictionary data structure. Therefore, the beginning of each play begins with a single dash followed by a space.

-Within a play, administrators can define various attributes. An attribute definition consists of the attribute name followed by a colon and a space (: ) and then the attribute value.

attribute: value

Following YAML syntax, each attribute in a play needs to be indented with spaces to be at the same indentation level to indicate their place in the data structure hierarchy.

The following example shows how two attributes are indented to indicate their relationship to the parent play. The dash in the first entry marks the beginning of a play using the list item syntax.

The second entry is space-indented to the same indentation level as the first entry to convey that the two attributes refer to the same parent play.

---- attribute1: value1 attribute2: value2

Name attribute

The name attribute can be used to give a descriptive label to a play. This is an optional attribute, but it is a recommended practice to name all tasks with a label. This is especially useful when a playbook contains multiple plays.

name: my first play

Hosts attribute

The set of managed hosts to perform tasks on is defined using the hosts attribute. Because this component is integral to the concept of a play, the host attribute must be defined in every

Writing a playbook

play. The host attribute is defined using host patterns to reference hosts from the inventory as previously discussed.

hosts: managedhost.example.com

User attributes

Tasks in playbooks are normally executed through a network connection to the managed hosts.

As with ad hoc commands, the user account used for these task execution is dependent on various parameters in Ansible's configuration file, /etc/ansible/ansible.cfg. The user that runs the tasks can be defined by the remote_user parameter. However, if privilege escalation is enabled, other parameters such become_user can also have an impact.

If the remote user defined in the Ansible configuration for task execution is not suitable, it can be overwritten using the remote_user attribute within a play.

remote_user: remoteuser

Privilege escalation attributes

Additional attributes are also available to define privilege escalation parameters from within a playbook. The become Boolean parameter can be used to enable or disable privilege escalation regardless of how it is defined in the Ansible configuration file.

become: True/False

If privilege escalation is enabled, the become_method attribute can be used to define the privilege escalation method to use during a specific play. The example below dictates that sudo be used for privilege escalation.

become_method: sudo

Additionally, with privilege escalation enabled, the become_user attribute can define the user account to be used for privilege escalation within the context of a specific play.

become_user: privileged_user

Tasks attribute

The main component of a play, the operations to be executed on the managed hosts, are defined using the tasks attribute. This attribute is defined as a list of dictionaries. Each task in the tasks list is composed of a set of key/value pairs.

In the following example, the tasks list consists of a single task item. The first entry of the task item defines a name for the task. The second entry invokes the service module and supplies its arguments as the values.

tasks:

- name: first task

service: name=httpd enabled=true

In the preceding example, the dash in the first entry marks the beginning of the list of attributes which pertain to the task. The second entry is space-indented to the same indentation level as the first entry to convey that the two attributes refer to the same parent task.

If multiple tasks are desired, the same syntax is repeated for each task.

tasks:

- name: first task

service: name=httpd enabled=true - name: second task

service: name=sshd enabled=true ...output omitted...

- name: last task

service: name=sshd enabled=true

Important

Use ansible-doc to find and learn how to use modules for your tasks.

When possible, try to avoid the command, shell, and raw modules in playbooks, as simple as they may seem to use. Because these take arbitrary commands, it is very easy to write non-idempotent playbooks with these modules.

For example, this task using the shell module is not idempotent. Every time the play is run, it will rewrite /etc/resolv.conf even if it already consists of the line

"nameserver 192.0.2.1".

- name: Non-idempotent approach with shell module shell: echo "nameserver 192.0.2.1" > /etc/resolv.conf

A number of things could be done to use the shell module in an idempotent way, and sometimes making those changes and using shell is the best approach. But a quicker solution may be to use ansible-doc to discover the copy module and use that to get the desired effect.

The following example will not rewrite the file /etc/resolv.conf if it already consists of the right content:

- name: Idempotent approach with copy module copy:

dest: /etc/resolv.conf

content: "nameserver 192.0.2.1\n"

The copy module is special-purpose and can easily test to see if the state has already been met, and if it has will make no changes. The shell module allows a lot of flexibility, but also requires more attention to ensure that it runs in an idempotent way.

Idempotent playbooks can be run repeatedly to ensure systems are in a particular state without disrupting those systems if they already are.

Comments

As is good practice with all programming languages and configuration files, comments can be added to Ansible playbooks. Comments in playbooks are preceded by the pound sign, #.

Comments should be used throughout a playbook to enhance readability and documentation.

# This is a comment