Ansible Training Notes

 

Configuration file

When installed, the ansible package provides a base configuration file located at /etc/ansible/ansible.cfg.

Priority in which the configuration files are processed:

  1. $ANSIBLE_CONFIG (an environment variable)
  2. ./ansible.cfg (in the current directory)
  3. ~/.ansible.cfg (the user’s home directory)
  4. /etc/ansible/ansible.cfg

To find out what config file is in use, run the following:

To get started, copy configuration files to the home directory:

Note the maximum number of simultaneous connections that Ansible makes is controlled by the forks parameter in ansible.cfg:

Inventory

Example inventory configuration:

Listing hosts from inventory:

There is a special group named “all” that matches all managed hosts in the inventory.

There is also a special group named “ungrouped” which matches all managed hosts in the inventory that are not members of any group.

Quote host patterns used on the CLI to protect them from unwanted shell expansion:

Multiple entries in the inventory can be referenced using lists:

If you have static and dynamic inventory files in the same directory, then they are merged and treated as one inventory!

Show inventory for all:

Target two inventories from the command line like this:

Aggregating inventory sources with a directory::

Privilege escalation configuration in ansible.cfg:

How to set the default user to use for playbooks in ansible.cfg:

How to set the log file in ansible.cfg:

Ad Hoc Commands

  • ping – Validate if server is up and recheable. No required parameters.

  • command – If no module is defined, Ansible uses the internally predefined “command” module.
  • yum – Use yum package manager. Parameters name and state.

  • service – Control Daemons. Parameters name and state.

  • user – Manipulate system users. Parameters name.

Creating a user sam in the labservers group:

Adding user sam to the wheel group. Append parameter is needed due to we dont wan’t to wipe out group file:

  • copy – Copy files. Parameters src.

Use the copy module to change content of a file:

  • file – Work with files. Parameters path.
Creating a file on managed host in user directory:

Informations about the file:

Changing properties of the file:

  • setup – Gather ansible facts. No required parameters.
  • debug – prints statements during execution and can be useful for debugging variables or expressions without necessarily halting the playbook

  • git – Interact with git repositories. Parameters repo and dest.

Note: if possible, try to avoid the command, shell and raw modules in playbooks! It’s easy to write non-idempotent playbooks this way.

Documentation

Ansible module documentation and playbook snippets:

Ansible-playbook command

Ansible executes plays and tasks in the order they are presented! How to check for YAML syntax errors:

Limit playbook to specyfied host:

Which host(s) the playbook applies to?

Whats tasks will be performed?

Run one task at a time:

Playbook dry-run:

Playbook step-by-step execution:

The beginning of each play begins with a single dash followed by a space.

To only run the first task, the –tags argument can be used:

To skip tagged task:

 

 Playbook

Playbook attributes:

  • hosts – hosts which are managed by ansible. Must be defined in every play.
  • user – user which will run ansible playbook
  • remote_user – can be used to define the user that runs the tasks.
  • become – can be used to enable privilege escalation.
  • become_method – can be used to define the privilege escalation method.
  • become_user – can define the user account to be used for privilege escalation.
  • gether_facts – to gether or not to gether the facts
  • tasks – is defined as a list of dictionaries.
  • block – can be used to group related tasks together.
  • name – can be used to give a descriptive label to a play.

Skeleton of simple playbook:

Common modules:

  • yum – Installs, upgrade, downgrades, removes, and lists packages
  • yum_repository – Add or remove YUM repositories
  • service – Controls services on remote hosts.
  • file – Set attributes of files, symlinks or directories.
  • copy – copies a file from the local or remote machine to a location on the remote machine.
  • firewalld – manages firewalld rules.
  • template – tTemplates processed by the Jinja2 templating
    language.
  • lineinfile – ensures a particular line is in a file, or replace
    an existing line using a back-referenced regular expression.
  • blockinfile – This module will insert/update/remove a block of multi-line text
  • replace – replace all instances of a pattern within a file
  • command – The given command will be executed on all selected nodes. The command(s) will not be processed through the shell, so variables like $HOME' and operations like “<“‘, ">"', “|”‘, ";"' and “&”‘ will not work. Use the [shell] module if you need these features.
  • shell – takes the command name followed by a list of space-delimited arguments.
  • debug – prints statements during execution and can be useful for
    debugging variables or expressions
  • fetch – Download a file from managed host.
  • get_url – Downloads files from HTTP, HTTPS, or FTP to the remote server.
  • uri – Interacts with HTTP and HTTPS web services
  • mysql_user – Adds or removes a user from a MySQL database.
  • mysql_db – Add or remove MySQL databases from a remote host
  • cron – manage crontab and environment variables entries.
  • at – schedule a command or script file to run once in the future
  • selinux – Configures the SELinux mode and policy
  • package_facts – Return information about installed packages as facts
  • parted – Allows configuring block device partition using the parted' command line tool.
  • lvg - create voulme group
  • lvol - create logical volume
  • filesystem - creates a filesystem.
  • mount - controls active and configured mount points in /etc/fstab’.
  • archive -Packs an archive. It is the opposite of [unarchive].
  • unarchive Unpacks an archive. It will not unpack a compressed file that does not contain an archive.
  • authorized_key – Adds or removes SSH authorized keys for particular user accounts.
  • add_host – create new hosts and groups in inventory

For each play in a playbook, you get to choose which machines in your infrastructure to target and what remote user to complete the steps as. You can use keyword become on a particular task instead of the play:

Use the serial keyword to run the hosts through the play in batches. Host variables take precedence over group variables, but variables defined by a playbook take precedence over both.

Including and Importing Files

When you include content, then Ansible processes included content during the run of the playbook, as content is required.

When you import content, Ansible processes imported content when the playbook is initially read, before the run starts.

Note that include was replaced in Ansible 2.4 with new directives such as:

  • vars_files
  • include_vars
  • include_tasks
  • import_tasks
  • import_playbook

You can find documentation in ansible-doc command.

These can be used to enhance the ability to reuse tasks and playbooks:

Examples:

Ansible Variables

Places to define variables:

  • vars, include_vars
  • Command line (-e ) as key=value:

or YAML/JSON

if filename prepend with @

  • Variables for hosts and host groups can be defined by creating two directories, group_vars and host_vars, in the same working directory as the inventory file or directory.

If the value to define varies for each datacenter, a group variable can be set for each datacenter:

If the value to be defined varies for each host in every datacenter, using host variables is recommended:
Shell

The directory structure for project, if it contained all of the example files above, might look like this:

  • Roles, blocks, and inventories

Whether or not you define any variables, you can access information about your hosts with the Special Variables Ansible provides, including “magic” variables, facts, and connection variables.

The most commonly used magic variables are:

  • hostvars
  • groups
  • group_names
  • inventory_hostname

Prints all magic variables:

The group_names variable contains a list of all the groups the current host is in. We can use it to install specific packages:

The hostvars variable lets you access variables for another host, including facts that have been gathered about that host.

The inventory_hostname variable is the name of the hostname as configured in Ansible’s inventory host file. The groups variable is a list of all the groups in the inventory.

Ansible Facts

How to print facts for all hosts?

Before Ansible 2.5, facts were injected as individual variables prefixed with the string ansible_ instead of being part of the ansible_facts variable.

At the time of writing this, Ansible recognises both the new fact naming system (using ansible_facts) and the old pre 2.5 naming system where facts are injected as separate variables.

You can use an ad-hoc command to run the setup module to print the value of all facts:

or

Filter results:

Some commonly used facts. In no particular order:

To disable fact gathering for a play, you can set the gather_facts keyword to “no”:

 

Custom facts can be defined in a static file, formatted as an INI file or using JSON and placed in /etc/ansible/facts.d and the file name must end in .fact.

They can also be executable scripts which generate JSON output, just like a dynamic inventory script. Note that custom fact files cannot be in YAML format!

Creating custom facts on managedhost1:

On the controlnode we can print local facts from the managedhost1:

Ansible Loops, Conditionals

Ansible supports iterating a task over a set of items using the loop keyword. A simple loop iterates a task over a list of items.

Since Ansible 2.5, the recommended way to write loops is to use the loop keyword. The old syntax used loops prefixed with with_.

Ansible conditionals operators

Operator Example
Equal  "{{ max_memory }} == 512"
Less than  "{{ min_memory }} < 128"
Greater than "{{ min_memory }} > 256"
Less than or equal to  "{{ min_memory }} <= 256"
Greater than or equal to  "{{ min_memory }} >= 512"
Not equal to  "{{ min_memory }} != 512"
Variable exists "{{ min_memory }} is defined"
Variable does not exist  "{{ min_memory }} is not defined"
Variable is set to 1, True, or yes  "{{ available_memory }}"
Variable is set to 0, False, or no  "not {{ available_memory }}"
Value is present in a variable or an array "{{ users }} in
users["db_admins"]"

Logical AND and OR operations are supported:

Loops and conditionals can be combined:

Lookups

Lookup plugins allow access to outside data sources. Lookups occur on the local computer, not on the remote computer. One way of using lookups is to populate variables:

Ansible Handlers

Handlers always run in the order specified by the handlers section of the play. A handler called by a task in the tasks part of the playbook will not run until all of the tasks under tasks have been processed.

If a task fails and the play aborts on that host, any handlers that had been notified by earlier tasks in the play will not run. Use the following to force execution of the handler:

Handlers are notified when a task reports a “changed” result. Handlers are not notified when it reports an “ok” or “failed” result.

Ignore errors:

Commonly Used Files Modules with Examples

The file module acts like chcon when setting file contexts:

Jinja2 Templates

Similar to Puppet. Puppet templates are based upon Ruby’s ERB, Ansible templates are based upon Jinja2.

A file containing a Jinja2 template does not need to have any specific file extension.

Use the template module to deploy it:

Roles

Similar to Puppet modules, reusable code in a modular fashion. Create a role skeleton:

The original way to use roles is via the roles: option for a play:

Changing a role’s behavior with variables:

As of Ansible 2.4, you can use roles inline with any other tasks using import_role or include_role:

The order of execution for your playbook is as follows:

  1. Any pre_tasks defined in the play.
  2. Any handlers triggered so far will be run.
  3. Each role listed in roles will execute in turn (with dependencies).
  4. Any tasks defined in the play.
  5. Any handlers triggered so far will be run.
  6. Any post_tasks defined in the play.
  7. Any handlers triggered so far will be run.

Role dependencies are always executed before the role that includes them, and may be recursive.

Search for roles from the CLI:

Ansible Galaxy is a public library of Ansible roles written by users. Similar to Puppet Forge. Install a role from Galaxy:

List installed roles:

To define role source, use requirements.yml:

 

RHEL System Roles

Password Hashing

How to generate SHA512 crypted passwords for the user module? The answer is taken from Ansible FAQ.

meta – Execute Ansible Actions

Meta tasks are a special kind of task which can influence Ansible internal execution or state. Choices:

Example meta task for how to run handlers after an error occurred:

Note that meta is not really a module as such it cannot be overwritten.

Ansible Check Mode (Dry Run)

When ansible-playbook is executed with --check or -C it will not make any changes on remote systems. To modify the check mode behavior of individual tasks, you can use the check_mode option:

The above will force a task to run in check mode, even when the playbook is called without --check.

Ansible Playbook Debugger

Ansible includes a debugger as part of the strategy plugins. This debugger enables you to debug as task.

The debugger keyword can be used on any block where you provide a name attribute, such as a play, role, block or task.

Ansible Ignoring Failed Commands

Playbooks will stop executing any more steps on a host that has a task fail. To ignore this behaviour, set ignore_errors to true:

This is useful when you expect a task to fail. For example, you are checking if Apache website is reachable. It may be unreachable, but you don’t want the play to fail because of that.

Ansible Run Once

There may be a need to only run a task one time for a batch of hosts. This can be achieved by configuring run_once on a task:

Ansible Aborting the Play

There will be cases when you will need to abort the entire play on failure, not just skip remaining tasks for a host, to avoid breaking the system. The any_errors_fatal play option will mark all hosts as failed if any fails, causing an immediate abort:

Ansible Keywords

These are some of the keywords available on common playbook objects.

Notable play keywords:

Notable block keywords:

Notable task keywords:

Ansible Setting Defaults for Modules

It can be useful to define default arguments for a particular module using the module_defaults attribute:

It is a time saver when you need to use the same module repeatedly.

Ansible Vault

By default, Ansible uses functions from the python-crypto package to encrypt and decrypt vault files. To speed up decryption at startup, you install the python-cryptography package.

Check syntax of a playbook that uses the vault file:

Create a password file to use for the playbook execution:

 

Ansible Best Practices

Tips for making the most of Ansible and Ansible playbooks.

  1. Always mention the state. The state parameter is optional to a lot of modules. Whether state=present or state=absent, it is always best to leave that parameter in your playbooks to make it clear.
  2. Generous use of whitespace to break things up, and use of comments, which start with #, is encouraged.
  3. Always name tasks. It is recommended to provide a description about why something is being done!
  4. Keep it simple. Do not attemtp to use every feature of Ansible together, all at once. Use what works for you!
  5. Ansible best practice has no limit on the amount of variable and vault files or their names.

Ansible and Vim

When writing playbooks in vim editor, modify its action in response to Tab key entries. Add the following line to $HOME/.vimrc. It will perform a two space indentation when the Tab key is pressed.

Settings explained:

Two other helpful but optional vim settings: