Question: Foundations of Docker

Answer:
Install Docker and jump into discovering what Docker is.
Learn the foundational concepts and workflows of Docker.


Question: Environment replacement

Answer:
Environment variables (declared withtheENVstatement) can also be
used in certain instructions as variables to be interpreted by the
Dockerfile. Escapes are also handled for including variable-like syntax
into a statement literally.
Environment variables are notated in the Dockerfile either with$variable_nameor${variable_name}. They are treated equivalently and the
brace syntax is typically used to address issues with variable names with no
whitespace, like${foo}_bar.
The${variable_name}syntax also supports a few of the standardbashmodifiers as specified below:
${variable:-word}indicates that ifvariableis set then the result
will be that value. Ifvariableis not set thenwordwill be the result.${variable:+word}indicates that ifvariableis set thenwordwill be
the result, otherwise the result is the empty string.
The following variable replacements are supported in a pre-release version of
Dockerfile syntax, when using the# syntax=docker/dockerfile-upstream:mastersyntax
directive in your Dockerfile:
${variable#pattern}removes the shortest match ofpatternfromvariable,
seeking from the start of the string.str=foobarbazecho${str#f*b}# arbaz${variable##pattern}removes the longest match ofpatternfromvariable,
seeking from the start of the string.str=foobarbazecho${str##f*b}# az${variable%pattern}removes the shortest match ofpatternfromvariable,
seeking backwards from the end of the string.string=foobarbazecho${string%b*}# foobar${variable%%pattern}removes the longest match ofpatternfromvariable,
seeking backwards from the end of the string.string=foobarbazecho${string%%b*}# foo${variable/pattern/replacement}replace the first occurrence ofpatterninvariablewithreplacementstring=foobarbazecho${string/ba/fo}# fooforbaz${variable//pattern/replacement}replaces all occurrences ofpatterninvariablewithreplacementstring=foobarbazecho${string//ba/fo}# fooforfoz


Question: Use a different shell

Answer:
You can change the default shell using theSHELLcommand. For example:
For more information, seeSHELL.


Question: Understand how ARG and FROM interact

Answer:
FROMinstructions support variables that are declared by anyARGinstructions that occur before the firstFROM.
AnARGdeclared before aFROMis outside of a build stage, so it
can't be used in any instruction after aFROM. To use the default value of
anARGdeclared before the firstFROMuse anARGinstruction without
a value inside of a build stage:


Question: Cache invalidation for RUN instructions

Answer:
The cache forRUNinstructions isn't invalidated automatically during
the next build. The cache for an instruction likeRUN apt-get dist-upgrade -ywill be reused during the next build. The
cache forRUNinstructions can be invalidated by using the--no-cacheflag, for exampledocker build --no-cache.
See theDockerfile Best Practices
guidefor more information.
The cache forRUNinstructions can be invalidated byADDandCOPYinstructions.


Question: RUN --mount=type=bind

Answer:
This mount type allows binding files or directories to the build container. A
bind mount is read-only by default.


Question: RUN --mount=type=cache

Answer:
This mount type allows the build container to cache directories for compilers
and package managers.
Contents of the cache directories persists between builder invocations without
invalidating the instruction cache. Cache mounts should only be used for better
performance. Your build should work with any contents of the cache directory as
another build may overwrite the files or GC may clean it if more storage space
is needed.
Apt needs exclusive access to its data, so the caches use the optionsharing=locked, which will make sure multiple parallel builds using
the same cache mount will wait for each other and not access the same
cache files at the same time. You could also usesharing=privateif
you prefer to have each build create another cache directory in this
case.


Question: RUN --mount=type=tmpfs

Answer: This mount type allows mountingtmpfsin the build container.


Question: RUN --mount=type=secret

Answer:
This mount type allows the build container to access secret values, such as
tokens or private keys, without baking them into the image.
By default, the secret is mounted as a file. You can also mount the secret as
an environment variable by setting theenvoption.
The following example takes the secretAPI_KEYand mounts it as an
environment variable with the same name.
Assuming that theAPI_KEYenvironment variable is set in the build
environment, you can build this with the following command:


Question: RUN --mount=type=ssh

Answer:
This mount type allows the build container to access SSH keys via SSH agents,
with support for passphrases.
You can also specify a path to*.pemfile on the host directly instead of$SSH_AUTH_SOCK.
However, pem files with passphrases are not supported.


Question: RUN --network=default

Answer:
Equivalent to not supplying a flag at all, the command is run in the default
network for the build.


Question: MAINTAINER (deprecated)

Answer:
TheMAINTAINERinstruction sets theAuthorfield of the generated images.
TheLABELinstruction is a much more flexible version of this and you should use
it instead, as it enables setting any metadata you require, and can be viewed
easily, for example withdocker inspect. To set a label corresponding to theMAINTAINERfield you could use:
This will then be visible fromdocker inspectwith the other labels.


Question: COPY --chown --chmod

Answer:
The--chownand--chmodfeatures are only supported on Dockerfiles used to build Linux containers,
and doesn't work on Windows containers. Since user and group ownership concepts do
not translate between Linux and Windows, the use of/etc/passwdand/etc/groupfor
translating user and group names to IDs restricts this feature to only be viable for
Linux OS-based containers.
All files and directories copied from the build context are created with a UID and GID of0unless the
optional--chownflag specifies a given username, groupname, or UID/GID
combination to request specific ownership of the copied content. The
format of the--chownflag allows for either username and groupname strings
or direct integer UID and GID in any combination. Providing a username without
groupname or a UID without GID will use the same numeric UID as the GID. If a
username or groupname is provided, the container's root filesystem/etc/passwdand/etc/groupfiles will be used to perform the translation
from name to integer UID or GID respectively. The following examples show
valid definitions for the--chownflag:
If the container root filesystem doesn't contain either/etc/passwdor/etc/groupfiles and either user or group names are used in the--chownflag, the build will fail on theCOPYoperation. Using numeric IDs requires
no lookup and does not depend on container root filesystem content.
With the Dockerfile syntax version 1.10.0 and later,
the--chmodflag supports variable interpolation,
which lets you define the permission bits using build arguments:


Question: Exec form ENTRYPOINT example

Answer:
You can use the exec form ofENTRYPOINTto set fairly stable default commands
and arguments and then use either form ofCMDto set additional defaults that
are more likely to be changed.
When you run the container, you can see thattopis the only process:
To examine the result further, you can usedocker exec:
And you can gracefully requesttopto shut down usingdocker stop test.
The following Dockerfile shows using theENTRYPOINTto run Apache in the
foreground (i.e., asPID 1):
If you need to write a starter script for a single executable, you can ensure that
the final executable receives the Unix signals by usingexecandgosucommands:


Question: Shell form ENTRYPOINT example

Answer:
You can specify a plain string for theENTRYPOINTand it will execute in/bin/sh -c.
This form will use shell processing to substitute shell environment variables,
and will ignore anyCMDordocker runcommand line arguments.
To ensure thatdocker stopwill signal any long runningENTRYPOINTexecutable
correctly, you need to remember to start it withexec:
When you run this image, you'll see the singlePID 1process:
Which exits cleanly ondocker stop:
If you forget to addexecto the beginning of yourENTRYPOINT:
You can then run it (giving it a name for the next step):
You can see from the output oftopthat the specifiedENTRYPOINTis notPID 1.


Question: Understand how CMD and ENTRYPOINT interact

Answer:
BothCMDandENTRYPOINTinstructions define what command gets executed when running a container.
There are few rules that describe their co-operation.
Dockerfile should specify at least one ofCMDorENTRYPOINTcommands.ENTRYPOINTshould be defined when using the container as an executable.CMDshould be used as a way of defining default arguments for anENTRYPOINTcommand
or for executing an ad-hoc command in a container.CMDwill be overridden when running the container with alternative arguments.
The table below shows what command is executed for differentENTRYPOINT/CMDcombinations:


Question: Notes about specifying volumes

Answer:
Keep the following things in mind about volumes in the Dockerfile.
Volumes on Windows-based containers: When using Windows-based containers,
the destination of a volume inside the container must be one of:a non-existing or empty directorya drive other thanC:Changing the volume from within the Dockerfile: If any build steps change the
data within the volume after it has been declared, those changes will be discarded
when using the legacy builder. When using Buildkit, the changes will instead be kept.JSON formatting: The list is parsed as a JSON array.
You must enclose words with double quotes (") rather than single quotes (').The host directory is declared at container run-time: The host directory
(the mountpoint) is, by its nature, host-dependent. This is to preserve image
portability, since a given host directory can't be guaranteed to be available
on all hosts. For this reason, you can't mount a host directory from
within the Dockerfile. TheVOLUMEinstruction does not support specifying ahost-dirparameter. You must specify the mountpoint when you create or run the container.


Question: Automatic platform ARGs in the global scope

Answer:
This feature is only available when using theBuildKitbackend.
BuildKit supports a predefined set ofARGvariables with information on the platform of
the node performing the build (build platform) and on the platform of the
resulting image (target platform). The target platform can be specified with
the--platformflag ondocker build.
The followingARGvariables are set automatically:
TARGETPLATFORM- platform of the build result. Eglinux/amd64,linux/arm/v7,windows/amd64.TARGETOS- OS component of TARGETPLATFORMTARGETARCH- architecture component of TARGETPLATFORMTARGETVARIANT- variant component of TARGETPLATFORMBUILDPLATFORM- platform of the node performing the build.BUILDOS- OS component of BUILDPLATFORMBUILDARCH- architecture component of BUILDPLATFORMBUILDVARIANT- variant component of BUILDPLATFORM
These arguments are defined in the global scope so are not automatically
available inside build stages or for yourRUNcommands. To expose one of
these arguments inside the build stage redefine it without value.
For example:


Question: BuildKit built-in build args

Answer:
When using a Git context,.gitdir is not kept on checkouts. It can be
useful to keep it around if you want to retrieve git information during
your build:


Question: Impact on build caching

Answer:
ARGvariables are not persisted into the built image asENVvariables are.
However,ARGvariables do impact the build cache in similar ways. If a
Dockerfile defines anARGvariable whose value is different from a previous
build, then a "cache miss" occurs upon its first usage, not its definition. In
particular, allRUNinstructions following anARGinstruction use theARGvariable implicitly (as an environment variable), thus can cause a cache miss.
All predefinedARGvariables are exempt from caching unless there is a
matchingARGstatement in the Dockerfile.
For example, consider these two Dockerfile:
If you specify--build-arg CONT_IMG_VER=
on the command line, in both
cases, the specification on line 2 doesn't cause a cache miss; line 3 does
cause a cache miss.ARG CONT_IMG_VERcauses theRUNline to be identified
as the same as runningCONT_IMG_VER=
echo hello, so if the
changes, you get a cache miss.
Consider another example under the same command line:
In this example, the cache miss occurs on line 3. The miss happens because
the variable's value in theENVreferences theARGvariable and that
variable is changed through the command line. In this example, theENVcommand causes the image to include the value.
If anENVinstruction overrides anARGinstruction of the same name, like
this Dockerfile:


Question: Copy or mount from stage, image, or context

Answer:
As of Dockerfile syntax 1.11, you can useONBUILDwith instructions that copy
or mount files from other stages, images, or build contexts. For example:
If the source offromis a build stage, the stage must be defined in the
Dockerfile whereONBUILDgets triggered. If it's a named context, that
context must be passed to the downstream build.


Question: Example: Running a multi-line script

Answer:
If the command only contains a here-document, its contents is evaluated with
the default shell.
Alternatively, shebang header can be used to define an interpreter.
More complex examples may use multiple here-documents.


Question: Example: Creating inline files

Answer:
WithCOPYinstructions, you can replace the source parameter with a here-doc
indicator to write the contents of the here-document directly to a file. The
following example creates agreeting.txtfile containinghello worldusing
aCOPYinstruction.
Regular here-docvariable expansion and tab stripping rulesapply.
The following example shows a small Dockerfile that creates ahello.shscript
file using aCOPYinstruction with a here-document.
In this case, file script prints "hello bar", because the variable is expanded
when theCOPYinstruction gets executed.
If instead you were to quote any part of the here-document wordEOT, the
variable would not be expanded at build-time.
Note thatARG FOO=baris excessive here, and can be removed. The variable
gets interpreted at runtime, when the script is invoked:


Question: Stateless Applications

Answer: Exposing an External IP Address to Access an Application in a ClusterExample: Deploying PHP Guestbook application with Redis


Question: Stateful Applications

Answer: StatefulSet BasicsExample: WordPress and MySQL with Persistent VolumesExample: Deploying Cassandra with Stateful SetsRunning ZooKeeper, A CP Distributed System


Question: Manage Infrastructure

Answer: Configuration LanguageDescribe infrastructure on various providers with Terraform's configuration language.Terraform CLIUse the Terraform CLI to manage configuration, plugins, infrastructure, and state.


Question: Inventories in INI or YAML format

Answer:
You can create inventories in eitherINIfiles or inYAML.
In most cases, such as the example in the preceding steps,INIfiles are straightforward and easy to read for a small number of managed nodes.
Creating an inventory inYAMLformat becomes a sensible option as the number of managed nodes increases.
For example, the following is an equivalent of theinventory.inithat declares unique names for managed nodes and uses theansible_hostfield:


Question: Tips for building inventories

Answer: Ensure that group names are meaningful and unique. Group names are also case sensitive.Avoid spaces, hyphens, and preceding numbers (usefloor_19, not19th_floor) in group names.Group hosts in your inventory logically according to theirWhat,Where, andWhen.WhatGroup hosts according to the topology, for example: db, web, leaf, spine.WhereGroup hosts by geographic location, for example: datacenter, region, floor, building.WhenGroup hosts by stage, for example: development, test, staging, production.


Question: Solutions by industry

Answer: AutomotiveFinancial servicesHealthcareIndustrial sectorMedia and entertainmentPublic sector (Global)Public sector (U.S.)Telecommunications


Question: Discover cloud technologies

Answer: Learn how to use our cloud products and solutions at your own pace in the Red Hat® Hybrid Cloud Console.


Question: Training & certification

Answer:
Courses and examsCertificationsRed Hat AcademyLearning communityLearning subscription
Explore training


Question: Build solutions powered by trusted partners

Answer: Find solutions from our collaborative community of experts and technologies in the Red Hat® Ecosystem Catalog.


Question: I want to learn more about:

Answer: AIApplication modernizationAutomationCloud-native applicationsLinuxVirtualization


Question: Artificial intelligence

Answer: Updates on the platforms that free customers to run AI workloads anywhere


Question: Red Hat legal and privacy links

Answer: About Red HatJobsEventsLocationsContact Red HatRed Hat BlogInclusion at Red HatCool Stuff StoreRed Hat Summit


Question: Desired state and idempotency

Answer: Most Ansible modules check whether the desired final state has already been achieved and exit without performing any actions if that state has been achieved. Repeating the task does not change the final state. Modules that behave this way are ‘idempotent’. Whether you run a playbook once or multiple times, the outcome should be the same. However, not all playbooks and not all modules behave this way. If you are unsure, test your playbooks in a sandbox environment before running them multiple times in production.


Question: Running playbooks in check mode

Answer:
The Ansible check mode allows you to execute a playbook without applying any alterations to your systems. You can use check mode to test playbooks before you implement them in a production environment.
To run a playbook in check mode, pass the-Cor--checkflag to theansible-playbookcommand:
Executing this command runs the playbook normally. Instead of implementing any modifications, Ansible provides a report on the changes it would have made. This report includes details such as file modifications, command execution, and module calls.
Check mode offers a safe and practical approach to examine the functionality of your playbooks without risking unintended changes to your systems. Check mode is also a valuable tool for troubleshooting playbooks that are not functioning as expected.


Question: Verifying playbooks

Answer: You may want to verify your playbooks to catch syntax errors and other problems before you run them. Theansible-playbookcommand offers several options for verification, including--check,--diff,--list-hosts,--list-tasks, and--syntax-check. TheTools for validating playbookstopic describes other tools for validating and testing playbooks.


Question: Handling undefined variables

Answer: Filters can help you manage missing or undefined variables by providing defaults or making some variables optional. If you configure Ansible to ignore most undefined variables, you can mark some variables as requiring values with themandatoryfilter.


Question: Providing default values

Answer:
You can provide default values for variables directly in your templates using the Jinja2 ‘default’ filter. This is often a better approach than failing if a variable is not defined:
In the above example, if the variable ‘some_variable’ is not defined, Ansible uses the default value 5, rather than raising an “undefined variable” error and failing. If you are working within a role, you can also add role defaults to define the default values for variables in your role. To learn more about role defaults seeRole directory structure.
Beginning in version 2.8, attempting to access an attribute of an Undefined value in Jinja will return another Undefined value, rather than throwing an error immediately. This means that you can now simply use
a default with a value in a nested data structure (in other words,{{foo.bar.baz|default('DEFAULT')}}) when you do not know if the intermediate values are defined.
If you want to use the default value when variables evaluate to false or an empty string you have to set the second parameter totrue:


Question: Making variables optional

Answer:
By default, Ansible requires values for all variables in a templated expression. However, you can make specific module variables optional. For example, you might want to use a system default for some items and control the value for others. To make a module variable optional, set the default value to the special variableomit:
In this example, the default mode for the files/tmp/fooand/tmp/baris determined by the umask of the system. Ansible does not send a value formode. Only the third file,/tmp/baz, receives themode=0444option.


Question: Defining mandatory values

Answer:
If you configure Ansible to ignore undefined variables, you may want to define some values as mandatory. By default, Ansible fails if a variable in your playbook or command is undefined. You can configure Ansible to allow undefined variables by settingDEFAULT_UNDEFINED_VAR_BEHAVIORtofalse. In that case, you may want to require some variables to be defined. You can do this with:
The variable value will be used as is, but the template evaluation will raise an error if it is undefined.
A convenient way of requiring a variable to be overridden is to give it an undefined value using theundef()function.


Question: Defining different values for true/false/null (ternary)

Answer:
You can create a test, then define one value to use when the test returns true and another when the test returns false (new in version 1.9):
In addition, you can define one value to use on true, one value on false and a third value on null (new in version 2.8):


Question: Managing data types

Answer: You might need to know, change, or set the data type on a variable. For example, a registered variable might contain a dictionary when your next task needs a list, or a userpromptmight return a string when your playbook needs a boolean value. Use theansible.builtin.type_debug,ansible.builtin.dict2items, andansible.builtin.items2dictfilters to manage data types. You can also use the data type itself to cast a value as a specific data type.


Question: Discovering the data type

Answer:
If you are unsure of the underlying Python type of a variable, you can use theansible.builtin.type_debugfilter to display it. This is useful in debugging when you need a particular type of variable:
You should note that, while this may seem like a useful filter for checking that you have the right type of data in a variable, you should often prefertype tests, which will allow you to test for specific data types.


Question: Transforming strings into lists

Answer:
Use theansible.builtin.splitfilter to transform a character/string delimited string into a list of items suitable forlooping. For example, if you want to split a string variablefruitsby commas, you can use:
String data (before applying theansible.builtin.splitfilter):
List data (after applying theansible.builtin.splitfilter):


Question: Transforming dictionaries into lists

Answer:
Use theansible.builtin.dict2itemsfilter to transform a dictionary into a list of items suitable forlooping:
Dictionary data (before applying theansible.builtin.dict2itemsfilter):
List data (after applying theansible.builtin.dict2itemsfilter):
Theansible.builtin.dict2itemsfilter is the reverse of theansible.builtin.items2dictfilter.
If you want to configure the names of the keys, theansible.builtin.dict2itemsfilter accepts 2 keyword arguments. Pass thekey_nameandvalue_namearguments to configure the names of the keys in the list output:
Dictionary data (before applying theansible.builtin.dict2itemsfilter):


Question: Transforming lists into dictionaries

Answer:
Use theansible.builtin.items2dictfilter to transform a list into a dictionary, mapping the content intokey:valuepairs:
List data (before applying theansible.builtin.items2dictfilter):
Dictionary data (after applying theansible.builtin.items2dictfilter):
Theansible.builtin.items2dictfilter is the reverse of theansible.builtin.dict2itemsfilter.
Not all lists usekeyto designate keys andvalueto designate values. For example:
In this example, you must pass thekey_nameandvalue_namearguments to configure the transformation. For example:


Question: Forcing the data type

Answer:
You can cast values as certain types. For example, if you expect the input “True” from avars_promptand you want Ansible to recognize it as a boolean value instead of a string:
If you want to perform a mathematical comparison on a fact and you want Ansible to recognize it as an integer instead of a string:


Question: Formatting data: YAML and JSON

Answer:
You can switch a data structure in a template from or to JSON or YAML format, with options for formatting, indenting, and loading data. The basic filters are occasionally useful for debugging:
Seeansible.builtin.to_jsonandansible.builtin.to_yamlfor documentation on these filters.
For human readable output, you can use:
Seeansible.builtin.to_nice_jsonandansible.builtin.to_nice_yamlfor documentation on these filters.
You can change the indentation of either format:
Theansible.builtin.to_yamlandansible.builtin.to_nice_yamlfilters use thePyYAML librarywhich has a default 80 symbol string length limit. That causes an unexpected line break after 80th symbol (if there is a space after 80th symbol)
To avoid such behavior and generate long lines, use thewidthoption. You must use a hardcoded number to define the width, instead of a construction likefloat("inf"), because the filter does not support proxying Python functions. For example:


Question: Filterto_jsonand Unicode support

Answer:
By defaultansible.builtin.to_jsonandansible.builtin.to_nice_jsonwill convert data received to ASCII, so:
will return:
To keep Unicode characters, pass the parameterensure_ascii=Falseto the filter:
To parse multi-document YAML strings, theansible.builtin.from_yaml_allfilter is provided.
Theansible.builtin.from_yaml_allfilter will return a generator of parsed YAML documents.
for example:


Question: Combining and selecting data

Answer: You can combine data from multiple sources and types, and select values from large data structures, giving you precise control over complex data.


Question: Combining items from multiple lists: zip and zip_longest

Answer:
To get a list combining the elements of other lists useansible.builtin.zip:
To always exhaust all lists useansible.builtin.zip_longest:
Similarly to the output of theansible.builtin.items2dictfilter mentioned above, these filters can be used to construct adict:
List data (before applying theansible.builtin.zipfilter):
Dictionary data (after applying theansible.builtin.zipfilter):


Question: Combining objects and subelements

Answer:
Theansible.builtin.subelementsfilter produces a product of an object and the subelement values of that object, similar to theansible.builtin.subelementslookup. This lets you specify individual subelements to use in a template. For example, this expression:
Data before applying theansible.builtin.subelementsfilter:
Data after applying theansible.builtin.subelementsfilter:
You can use the transformed data withloopto iterate over the same subelement for multiple objects:


Question: Combining hashes/dictionaries

Answer:
Theansible.builtin.combinefilter allows hashes to be merged. For example, the following would override keys in one hash:
The resulting hash would be:
The filter can also take multiple arguments to merge:
In this case, keys indwould override those inc, which would override those inb, and so on.
The filter also accepts two optional parameters:recursiveandlist_merge.
Ifrecursive=False(the default), nested hash aren’t merged:


Question: Selecting values from arrays or hashtables

Answer:
Theextractfilter is used to map from a list of indices to a list of values from a container (hash or array):
The results of the above expressions would be:
The filter can take another argument:
This takes the list of hosts in group ‘x’, looks them up inhostvars, and then looks up theec2_ip_addressof the result. The final result is a list of IP addresses for the hosts in group ‘x’.
The third argument to the filter can also be a list, for a recursive lookup inside the container:
This would return a list containing the value ofb[‘a’][‘x’][‘y’].


Question: Selecting JSON data: JSON queries

Answer:
To select a single element or a data subset from a complex data structure in JSON format (for example, Ansible facts), use thecommunity.general.json_queryfilter.  Thecommunity.general.json_queryfilter lets you query a complex JSON structure and iterate over it using a loop structure.
Consider this data structure:
To extract all clusters from this structure, you can use the following query:
To extract all server names:
To extract ports from cluster1:
To print out the ports from cluster1 in a comma-separated string:


Question: Random MAC addresses

Answer:
This filter can be used to generate a random MAC address from a string prefix.
To get a random MAC address from a string prefix starting with ‘52:54:00’:
Note that if anything is wrong with the prefix string, the filter will issue an error.
As of Ansible version 2.9, you can also initialize the random number generator from a seed to create random-but-idempotent MAC addresses:


Question: Random items or numbers

Answer:
Theansible.builtin.randomfilter in Ansible is an extension of the default Jinja2 random filter, and can be used to return a random item from a sequence of items or to generate a random number based on a range.
To get a random item from a list:
To get a random number between 0 (inclusive) and a specified integer (exclusive):
To get a random number from 0 to 100 but in steps of 10:
To get a random number from 1 to 100 but in steps of 10:
You can initialize the random number generator from a seed to create random-but-idempotent numbers:


Question: Managing list variables

Answer:
You can search for the minimum or maximum value in a list, or flatten a multi-level list.
To get the minimum value from the list of numbers:
To get the minimum value in a list of objects:
To get the maximum value from a list of numbers:
To get the maximum value in a list of objects:
Flatten a list (same thing theflattenlookup does):


Question: Selecting from sets or lists (set theory)

Answer:
You can select or combine items from sets or lists. Note, multisets are currently not supported and all of the following filters imply uniqueness. That means that duplicate elements are removed from the result.
To get a unique set from a list:
To get a union (with duplicate elements removed) of two lists:
To get the intersection of two lists (unique list of all items that exist in both lists):
To get the difference of two lists (items in first list that don’t exist in second list):
To get the symmetric difference of two lists (items exclusive to each list):


Question: Calculating numbers (math)

Answer:
You can calculate logs, powers, and roots of numbers with Ansible filters. Jinja2 provides other mathematical functions like abs() and round().
Get the logarithm (default is e):
Get the base 10 logarithm:
Give me the power of 2! (or 5):
Square root, or the 5th:


Question: Network CLI filters

Answer:
To convert the output of a network device CLI command into structured JSON
output, use theansible.netcommon.parse_clifilter:
Theansible.netcommon.parse_clifilter will load the spec file and pass the command output
through it, returning JSON output. The YAML spec file defines how to parse the CLI output.
The spec file should be valid formatted YAML.  It defines how to parse the CLI
output and return JSON data.  Below is an example of a valid spec file that
will parse the output from theshowvlancommand.
The spec file above will return a JSON data structure that is a list of hashes
with the parsed VLAN information.
The same command could be parsed into a hash by using the key and values
directives.  Here is an example of how to parse the output into a hash
value using the sameshowvlancommand.
Another common use case for parsing CLI commands is to break a large command
into blocks that can be parsed.  This can be done using thestart_blockandend_blockdirectives to break the command into blocks that can be parsed.


Question: Network XML filters

Answer:
To convert the XML output of a network device command into structured JSON
output, use theansible.netcommon.parse_xmlfilter:
Theansible.netcommon.parse_xmlfilter will load the spec file and pass the command output
through formatted as JSON.
The spec file should be valid formatted YAML. It defines how to parse the XML
output and return JSON data.
Below is an example of a valid spec file that
will parse the output from theshowvlan|displayxmlcommand.
The spec file above will return a JSON data structure that is a list of hashes
with the parsed VLAN information.
The same command could be parsed into a hash by using the key and values
directives.  Here is an example of how to parse the output into a hash
value using the sameshowvlan|displayxmlcommand.


Question: Network VLAN filters

Answer:
Use theansible.netcommon.vlan_parserfilter to transform an unsorted list of VLAN integers into a
sorted string list of integers according to IOS-like VLAN list rules. This list has the following properties:
Vlans are listed in ascending order.Three or more consecutive VLANs are listed with a dash.The first line of the list can be first_line_len characters long.Subsequent list lines can be other_line_len characters.
To sort a VLAN list:
This example renders the following sorted list:
Another example Jinja template:
This allows for the dynamic generation of VLAN lists on a Cisco IOS tagged interface. You can store an exhaustive raw list of the exact VLANs required for an interface and then compare that to the parsed IOS output that would actually be generated for the configuration.


Question: Hashing and encrypting strings and passwords

Answer:
To get the sha1 hash of a string:
To get the md5 hash of a string:
Get a string checksum:
Other hashes (platform dependent):
To get a sha512 password hash (random salt):
To get a sha256 password hash with a specific salt:


Question: Adding comments to files

Answer:
Theansible.builtin.commentfilter lets you create comments in a file from text in a template, with a variety of comment styles. By default, Ansible uses#to start a comment line and adds a blank comment line above and below your comment text. For example the following:
produces this output:
Ansible offers styles for comments in C (//...), C block
(/*...*/), Erlang (%...) and XML (
):
You can define a custom comment character. This filter:
produces:
You can fully customize the comment style:


Question: URLEncode Variables

Answer: Theurlencodefilter quotes data for use in a URL path or query using UTF-8:


Question: Searching strings with regular expressions

Answer:
To search in a string or extract parts of a string with a regular expression, use theansible.builtin.regex_searchfilter:
To extract all occurrences of regex matches in a string, use theansible.builtin.regex_findallfilter:
To replace text in a string with regex, use theansible.builtin.regex_replacefilter:
To escape special characters within a standard Python regex, use theansible.builtin.regex_escapefilter (using the defaultre_type='python'option):
To escape special characters within a POSIX basic regex, use theansible.builtin.regex_escapefilter with there_type='posix_basic'option:


Question: Managing file names and path names

Answer:
To get the last name of a file path, like ‘foo.txt’ out of ‘/etc/asdf/foo.txt’:
To get the last name of a Windows style file path (new in version 2.0):
To separate the Windows drive letter from the rest of a file path (new in version 2.0):
To get only the Windows drive letter:
To get the rest of the path without the drive letter:
To get the directory from a path:


Question: Manipulating strings

Answer:
To add quotes for shell usage:
(Documentation:ansible.builtin.quote)
To concatenate a list into a string:
To split a string into a list:
To work with Base64 encoded strings:
(Documentation:ansible.builtin.b64encode)


Question: Handling dates and times

Answer:
To get a date object from a string use theto_datetimefilter:
To format a date using a string (like with the shell date command), use the “strftime” filter:
strftime takes an optional utc argument, defaulting to False, meaning times are in the local timezone:


Question: Getting Kubernetes resource names

Answer:
Use the “k8s_config_resource_name” filter to obtain the name of a Kubernetes ConfigMap or Secret,
including its hash:
This can then be used to reference hashes in Pod specifications:


Question: Testing if a list contains a value

Answer:
Ansible includes acontainstest which operates similarly, but in reverse of the Jinja2 providedintest.
Thecontainstest is designed to work with theselect,reject,selectattr, andrejectattrfilters


Question: Testing if a list value is True

Answer: You can useanyandallto check if any or all elements in a list are true or not


Question: Testing size formats

Answer:
Thehuman_readableandhuman_to_bytesfunctions let you test your
playbooks to make sure you are using the right size format in your tasks, and that
you provide Byte format to computers and human-readable format to people.


Question: Testing task results

Answer: The following tasks are illustrative of the tests meant to check the status of tasks


Question: The lookup function

Answer:
You can use thelookupfunction to populate variables dynamically. Ansible evaluates the value each time it is executed in a task (or template).
The first argument to thelookupfunction is required and specifies the name of the lookup plugin. If the lookup plugin is in a collection, the fully qualified name must be provided, since thecollections keyworddoes not apply to lookup plugins.
Thelookupfunction also accepts an optional boolean keywordwantlist, which defaults toFalse. WhenTrue, the result of the lookup is ensured to be a list.
Refer to the lookup plugin’s documentation to see plugin-specific arguments and keywords.


Question: The query/q function

Answer:
This function is shorthand forlookup(...,wantlist=True). These are equivalent:
For more details and a list of lookup plugins in ansible-core, seeWorking with plugins. You may also find lookup plugins in collections. You can review a list of lookup plugins installed on your control machine with the commandansible-doc-l-tlookup.


Question: Iterating over a simple list

Answer:
Repeated tasks can be written as standard loops over a simple list of strings. You can define the list directly in the task.
You can define the list in a variables file, or in the ‘vars’ section of your play, then refer to the name of the list in the task.
Either of these examples would be the equivalent of
You can pass a list directly to a parameter for some plugins. Most of the packaging modules, likeyumandapt, have this capability. When available, passing the list to a parameter is better than looping over the task. For example
Check themodule documentationto see if you can pass a list to any particular module’s parameter(s).


Question: Iterating over a list of hashes

Answer:
If you have a list of hashes, you can reference subkeys in a loop. For example:
When combiningconditionalswith a loop, thewhen:statement is processed separately for each item.
SeeBasic conditionals with whenfor examples.


Question: Iterating over a dictionary

Answer:
To loop over a dict, use thedict2items:
Here, we are iterating overserver_configsand printing the key and selected nested fields.
If the values in the dictionary are themselves dictionaries (for example, each group maps
to a dict containing agid), remember that after applyingdict2itemseach loop item
has two attributes:item.keyanditem.value. Access nested fields viaitem.value.
.


Question: Registering variables with a loop

Answer:
You can register the output of a loop as a variable. For example
When you useregisterwith a loop, the data structure placed in the variable will contain aresultsattribute that is a list of all responses from the module. This differs from the data structure returned when usingregisterwithout a loop. Thechanged/failed/skippedattribute that’s beside theresultswill represent the overall state.changed/failedwill betrueif at least one of the iterations triggered a change/failed, whileskippedwill betrueonly if all iterations were skipped.
Subsequent loops over the registered variable to inspect the results may look like
During iteration, the result of the current item will be placed in the variable.


Question: Retrying a task until a condition is met

Answer:
You can use theuntilkeyword to retry a task until a certain condition is met. Here’s an example:
This task runs up to 5 times with a delay of 10 seconds between each attempt. If the result of any attempt has “all systems go” in its stdout, the task succeeds. The default value for “retries” is 3 and “delay” is 5.
To see the results of individual retries, run the play with-vv.
When you run a task withuntiland register the result as a variable, the registered variable will include a key called “attempts”, which records the number of retries for the task.
Ifuntilis not specified, the task will retry until the task succeeds but at mostretriestimes (New in version 2.16).
You can combine theuntilkeyword withlooporwith_
. The result of the task for each element of the loop is registered in the variable and can be used in theuntilcondition. Here is an example:


Question: Looping over inventory

Answer:
Normally the play itself is a loop over your inventory, but sometimes you need a task to do the same over a different set of hosts.
To loop over your inventory, or just a subset of it, you can use a regularloopwith theansible_play_batchorgroupsvariables.
There is also a specific lookup plugininventory_hostnamesthat can be used like this
More information on the patterns can be found inPatterns: targeting hosts and groups.


Question: Ensuring list input forloop: usingqueryrather thanlookup

Answer:
Theloopkeyword requires a list as input, but thelookupkeyword returns a string of comma-separated values by default. Ansible 2.5 introduced a new Jinja2 function namedquerythat always returns a list, offering a simpler interface and more predictable output from lookup plugins when using theloopkeyword.
You can forcelookupto return a list toloopby usingwantlist=True, or you can usequeryinstead.
The following two examples do the same thing.


Question: Adding controls to loops

Answer: Theloop_controlkeyword lets you manage your loops in useful ways.


Question: Limiting loop output withlabel

Answer:
When looping over complex data structures, the console output of your task can be enormous. To limit the displayed output, use thelabeldirective withloop_control.
The output of this task will display just thenamefield for eachiteminstead of the entire contents of the multi-line{{item}}variable.


Question: Pausing within a loop

Answer: To control the time (in seconds) between the execution of each item in a task loop, use thepausedirective withloop_control.


Question: Breaking out of a loop

Answer: Use thebreak_whendirective withloop_controlto exit a loop after any item, based on Jinja2 expressions.


Question: Tracking progress through a loop withindex_var

Answer: To keep track of where you are in a loop, use theindex_vardirective withloop_control. This directive specifies a variable name to contain the current loop index.


Question: Extended loop variables

Answer:
As of Ansible 2.8, you can get extended loop information using theextendedoption to loop control. This option will expose the following information.
To disable theansible_loop.allitemsitem, to reduce memory consumption, setloop_control.extended_allitems:false.


Question: Accessing the name of your loop_var

Answer:
As of Ansible 2.8, you can get the name of the value provided toloop_control.loop_varusing theansible_loop_varvariable
For role authors, writing roles that allow loops, instead of dictating the requiredloop_varvalue, you can gather the value through the following


Question: Iterating over nested lists

Answer:
The simplest way to ‘nest’ loops is to avoid nesting loops, just format the data to achieve the same result.
You can use Jinja2 expressions to iterate over complex lists. For example, a loop can combine nested lists, which simulates a nested loop.


Question: Stacking loops via include_tasks

Answer:
You can nest two looping tasks usinginclude_tasks. However, by default, Ansible sets the loop variableitemfor each loop.
This means the inner, nested loop will overwrite the value ofitemfrom the outer loop.
To avoid this, you can specify the name of the variable for each loop usingloop_varwithloop_control.


Question: Migrating from with_X to loop

Answer:
In most cases, loops work best with theloopkeyword instead ofwith_Xstyle loops. Theloopsyntax is usually best expressed using filters instead of more complex use ofqueryorlookup.
These examples show how to convert many commonwith_style loops toloopand filters.


Answer: with_nestedandwith_cartesianare replaced by loop and theproductfilter.


Question: Tasks that cannot be delegated

Answer:
Some tasks are always executed on the control node. These tasks, includinginclude,add_host, anddebug, cannot be delegated.
You can determine if an action can be delegated from theconnectionattribute documentation.
If theconnectionattribute indicatessupportisFalseorNone, then the action does not use a connection and cannot be delegated.


Question: Templating in delegation context

Answer: Be advised that under delegation, the execution interpreter (normally Python),connection,become, andshellplugin options will now be templated using values from the delegated to host. All variables exceptinventory_hostnamewill now be consumed from this host and not the original task host. If you need variables from the original task host for those options, you must usehostvars[inventory_hostname]['varname'], eveninventory_hostname_shortrefers to the delegated host.


Question: Delegation and parallel execution

Answer:
By default, Ansible tasks are executed in parallel. Delegating a task does not change this and does not handle concurrency issues (multiple forks writing to the same file).
Most commonly, users are affected by this when updating a single file on a single delegated to host for all hosts (using thecopy,template, orlineinfilemodules, for example). They will still operate in parallel forks (default 5) and overwrite each other.
This can be handled in several ways:
By using an intermediate play withserial: 1or usingthrottle: 1at the task level, for more detail seeControlling playbook execution: strategies and more


Question: Basic conditionals withwhen

Answer: The simplest conditional statement applies to a single task. Create the task, then add awhenstatement that applies a test. Thewhenclause is a raw Jinja2 expression without double curly braces (seeReferencing simple variables). When you run the task or playbook, Ansible evaluates the test for all hosts. On any host where the test passes (returns a value of True), Ansible runs that task. For example, if you are installing mysql on multiple machines, some of which have SELinux enabled, you might have a task to configure SELinux to allow mysql to run. You would only want that task to run on machines that have SELinux enabled:


Question: Conditionals based on ansible_facts

Answer:
Often you want to execute or skip a task based on facts. Facts are attributes of individual hosts, including IP address, operating system, the status of a filesystem, and many more. With conditionals based on facts:
SeeCommonly-used factsfor a list of facts that frequently appear in conditional statements. Not all facts exist for all hosts. For example, the ‘lsb_major_release’ fact used in the example below only exists when thelsb_releasepackageis installed on the target host. To see what facts are available on your systems, add a debug task to your playbook:
Here is a sample conditional based on a fact:
If you have multiple conditions, you can group them with parentheses:
You can uselogical operatorsto combine conditions. When you have multiple conditions that all need to be true (that is, a logicaland), you can specify them as a list:
If a fact or variable is a string, and you need to run a mathematical comparison on it, use a filter to ensure that Ansible reads the value as an integer:


Question: Conditions based on registered variables

Answer:
Often in a playbook, you want to execute or skip a task based on the outcome of an earlier task. For example, you might want to configure a service after it is upgraded by an earlier task. To create a conditional based on a registered variable:
You create the name of the registered variable using theregisterkeyword. A registered variable always contains the status of the task that created it as well as any output that the task generated. You can use registered variables in templates and action lines as well as in conditionalwhenstatements. You can access the string contents of the registered variable usingvariable.stdout. For example:
You can use registered results in the loop of a task if the variable is a list. If the variable is not a list, you can convert it into a list, with eitherstdout_linesor withvariable.stdout.split(). You can also split the lines by other fields:
The string content of a registered variable can be empty. If you want to run another task only on hosts where the stdout of your registered variable is empty, check the registered variable’s string contents for emptiness:
Ansible always registers something in a registered variable for every host, even on hosts where a task fails or Ansible skips a task because a condition is not met. To run a follow-up task on these hosts, query the registered variable forisskipped(not for “undefined” or “default”). SeeRegistering variablesfor more information. Here are sample conditionals based on the success or failure of a task. Remember to ignore errors if you want Ansible to continue executing on a host when a failure occurs:


Question: Conditionals based on variables

Answer:
You can also create conditionals based on variables defined in the playbooks or inventory. Because conditionals require boolean input (a test must evaluate as True to trigger the condition), you must apply the|boolfilter to non-boolean variables, such as string variables with content like ‘yes’, ‘on’, ‘1’, or ‘true’. You can define variables like this:
With the variables above, Ansible would run one of these tasks and skip the other:
If a required variable has not been set, you can skip or fail using Jinja2’sdefinedtest. For example:
This is especially useful in combination with the conditional import ofvarsfiles (see below).
As the examples show, you do not need to use{{ }}to use variables inside conditionals, as these are already implied.


Question: Using conditionals in loops

Answer:
If you combine awhenstatement with aloop, Ansible processes the condition separately for each item. This is by design, so you can execute the task on some items in the loop and skip it on other items. For example:
If you need to skip the whole task when the loop variable is undefined, use the|defaultfilter to provide an empty iterator. For example, when looping over a list:
You can do the same thing when looping over a dict:


Question: Loading custom facts

Answer: You can provide your own facts, as described inShould you develop a module?.  To run them, just make a call to your own custom fact gathering module at the top of your list of tasks, and the variables returned there will be accessible for future tasks:


Question: Conditionals with reuse

Answer: You can use conditionals with reusable tasks files, playbooks, or roles. Ansible executes these conditional statements differently for dynamic reuse (includes) and static reuse (imports). SeeReusing Ansible artifactsfor more information on reuse in Ansible.


Question: Selecting variables, files, or templates based on facts

Answer:
Sometimes the facts about a host determine the values you want to use for certain variables or even the file or template you want to select for that host. For example, the names of packages are different on CentOS and Debian. The configuration files for common services are also different on different OS flavors and versions. To load different variables files, templates, or other files based on a fact about the hosts:
Ansible separates variables from tasks, keeping your playbooks from turning into arbitrary code with nested conditionals. This approach results in more streamlined and auditable configuration rules because there are fewer decision points to track.


Question: Debugging conditionals

Answer: If your conditionalwhenstatement is not behaving as you intended, you can add adebugstatement to determine if the condition evaluates totrueorfalse. A common cause of unexpected behavior in conditionals is testing an integer as a string or a string as an integer. To debug a conditional statement, add the entire statement as thevar:value in adebugtask. Ansible then shows the test and how the statement evaluates. For example, here is a set of tasks and sample output:


Question: Commonly-used facts

Answer: The following Ansible facts are frequently used in conditionals.


Question: ansible_facts[‘distribution_major_version’]

Answer: The major version of the operating system. For example, the value is16for Ubuntu 16.04.


Question: Grouping tasks with blocks

Answer:
All tasks in a block inherit directives applied at the block level. Most of what you can apply to a single task (with the exception of loops) can be applied at the block level, so blocks make it much easier to set data or directives common to the tasks. The directive does not affect the block itself, it is only inherited by the tasks enclosed by a block. For example, awhenstatement is applied to the tasks within a block, not to the block itself.
In the example above, the ‘when’ condition will be evaluated before Ansible runs each of the three tasks in the block. All three tasks also inherit the privilege escalation directives, running as the root user. Finally,ignore_errors:trueensures that Ansible continues to execute the playbook even if some of the tasks fail.
Names for blocks have been available since Ansible 2.3. We recommend using names in all tasks, within blocks or elsewhere, for better visibility into the tasks being executed when you run the playbook.


Question: Handling errors with blocks

Answer:
You can control how Ansible responds to task errors using blocks withrescueandalwayssections.
Rescue blocks specify tasks to run when an earlier task in a block fails. This approach is similar to exception handling in many programming languages. Ansible only runs rescue blocks after a task returns a ‘failed’ state.
You can also add analwayssection to a block. Tasks in thealwayssection run no matter what the task status of the previous block is.
Together, these elements offer complex error handling.
The tasks in theblockexecute normally. If any tasks in the block returnfailed, therescuesection executes tasks to recover from the error. Thealwayssection runs regardless of the results of theblockandrescuesections.
If an error occurs in the block and the rescue task succeeds, Ansible reverts the failed status of the original task for the run and continues to run the play as if the original task had succeeded. The rescued task is considered successful and does not triggermax_fail_percentageorany_errors_fatalconfigurations. However, Ansible still reports a failure in the playbook statistics.


Question: Notifying and loops

Answer:
Tasks can use loops to notify handlers. This is particularly useful when combined with variables to trigger multiple dynamic notifications.
Note that the handlers are triggered if the task as a whole is changed. When a loop is used the changed state is set if any of the loop items are changed.  That is, any change triggers all of the handlers.
In the above example both memcached and apache will be restarted if either template file is changed, neither will be restarted if no file changes.


Question: Handler insertion order into the play

Answer:
There is only one global, play-level scope for handlers regardless of where the handlers are defined, either in thehandlers:section or in roles. The order in which handlers are added into the play is as follows:
Handlers from roles in theroles:section.Handlers from thehandlers:section.Handlers from roles statically imported viaimport_roletasks.Handlers from roles dynamically included viainclude_roletasks (available at runtime only after theinclude_roletask executed).
In case handlers having the same name the last one loaded into the play, as per the above order, can be notified and executed.


Question: Controlling when handlers run

Answer:
By default, handlers run after all the tasks in a particular play have been completed. Notified handlers are executed automatically after each of the following sections, in the following order:pre_tasks,roles/tasksandpost_tasks. This approach is efficient, because the handler only runs once, regardless of how many tasks notify it. For example, if multiple tasks update a configuration file and notify a handler to restart Apache, Ansible only bounces Apache once to avoid unnecessary restarts.
If you need handlers to run before the end of the play, add a task to flush them using themeta module, which executes Ansible actions:
Themeta:flush_handlerstask triggers any handlers that have been notified at that point in the play.
Once handlers are executed, either automatically after each mentioned section or manually by theflush_handlersmeta task, they can be notified and run again in later sections of the play.


Question: Defining when tasks change

Answer:
You can control when handlers are notified about task changes using thechanged_whenkeyword.
In the following example, the handler restarts the service each time the configuration file is copied:
SeeDefining “changed”for more aboutchanged_when.


Question: Using variables with handlers

Answer:
You may want your Ansible handlers to use variables. For example, if the name of a service varies slightly by distribution, you want your output to show the exact name of the restarted service for each target machine. Avoid placing variables in the name of the handler. Since handler names are templated early on, Ansible may not have a value available for a handler name like this:
If the variable used in the handler name is not available, the entire play fails. Changing that variable mid-playwill notresult in newly created handler.
Instead, place variables in the task parameters of your handler. You can load the values usinginclude_varslike this:
While handler names can contain a template,listentopics cannot.


Question: Includes and imports in handlers

Answer:
Notifying a dynamic include such asinclude_taskas a handler results in executing all tasks from within the include. It is not possible to notify a handler defined inside a dynamic include.
Having a static include such asimport_taskas a handler results in that handler being effectively rewritten by handlers from within that import before the play execution. A static include itself cannot be notified; the tasks from within that include, on the other hand, can be notified individually.


Question: Meta tasks as handlers

Answer: Since Ansible 2.14meta tasksare allowed to be used and notified as handlers. Note that howeverflush_handlerscannot be used as a handler to prevent unexpected behavior.


Question: Ignoring failed commands

Answer:
By default, Ansible stops executing tasks on a host when a task fails on that host. You can useignore_errorsto continue despite of the failure.
Theignore_errorsdirective only works when the task can run and returns a value of ‘failed’. It does not make Ansible ignore undefined variable errors, connection failures, execution issues (for example, missing packages), or syntax errors.


Question: Ignoring unreachable host errors

Answer:
You can ignore a task failure due to the host instance being ‘UNREACHABLE’ with theignore_unreachablekeyword. Ansible ignores the task errors but continues to execute future tasks against the unreachable host. For example, at the task level:
And at the playbook level:


Question: Resetting unreachable hosts

Answer: If Ansible cannot connect to a host, it marks that host as ‘UNREACHABLE’ and removes it from the list of active hosts for the run. You can usemeta:clear_host_errorsto reactivate all hosts, so subsequent tasks can try to reach them again.


Question: Handlers and failure

Answer:
Ansible runshandlersat the end of each play. If a task notifies a handler but
another task fails later in the play, by default the handler doesnotrun on that host,
which may leave the host in an unexpected state. For example, a task could update
a configuration file and notify a handler to restart some service. If a
task later in the same play fails, the configuration file might be changed but
the service will not be restarted.
You can change this behavior with the--force-handlerscommand-line option,
by includingforce_handlers:Truein a play, or by addingforce_handlers=Trueto ansible.cfg. When handlers are forced, Ansible will run all notified handlers on
all hosts, even hosts with failed tasks. (Note that certain errors could still prevent
the handler from running, such as a host becoming unreachable.)


Question: Ensuring success for command and shell

Answer: Thecommandandshellmodules care about return codes, so if you have a command whose successful exit code is not zero, you can do this:


Question: Aborting a play on all hosts

Answer: Sometimes you want a failure on a single host, or failures on a certain percentage of hosts, to abort the entire play on all hosts. You can stop play execution after the first failure happens withany_errors_fatal. For finer-grained control, you can usemax_fail_percentageto abort the run after a given percentage of hosts has failed.


Question: Aborting on the first error: any_errors_fatal

Answer:
If you setany_errors_fataland a task returns an error, Ansible finishes the fatal task on all hosts in the current batch and then stops executing the play on all hosts. Subsequent tasks and plays are not executed. You can recover from fatal errors by adding arescue sectionto the block. You can setany_errors_fatalat the play or block level.
You can use this feature when all tasks must be 100% successful to continue playbook execution. For example, if you run a service on machines in multiple data centers with load balancers to pass traffic from users to the service, you want all load balancers to be disabled before you stop the service for maintenance. To ensure that any failure in the task that disables the load balancers will stop all other tasks:
In this example, Ansible starts the software upgrade on the front ends only if all of the load balancers are successfully disabled.


Question: Setting a maximum failure percentage

Answer:
By default, Ansible continues to execute tasks as long as there are hosts that have not yet failed. In some situations, such as when executing a rolling update, you may want to abort the play when a certain threshold of failures has been reached. To achieve this, you can set a maximum failure percentage on a play:
Themax_fail_percentagesetting applies to each batch when you use it withserial. In the example above, if more than 3 of the 10 servers in the first (or any) batch of servers failed, the rest of the play would be aborted.


Question: Controlling errors in blocks

Answer: You can also use blocks to define responses to task errors. This approach is similar to exception handling in many programming languages. SeeHandling errors with blocksfor details and examples.


Question: Setting the remote environment in a task

Answer:
You can set the environment directly at the task level.
You can reuse environment settings by defining them as variables in your play and accessing them in a task as you would access any stored Ansible variable.
You can store environment settings for reuse in multiple playbooks by defining them in a group_vars file.
You can set the remote environment at the play level.
These examples show proxy settings, but you can provide any number of settings this way.


Question: Creating reusable files and roles

Answer: Ansible offers four distributed, reusable artifacts: variables files, task files, playbooks, and roles.


Question: When to turn a playbook into a role

Answer: For some use cases, simple playbooks work well. However, starting at a certain level of complexity, roles work better than playbooks. A role lets you store your defaults, handlers, variables, and tasks in separate directories, instead of in a single long document. Roles are easy to share on Ansible Galaxy. For complex use cases, most users find roles easier to read, understand, and maintain than all-in-one playbooks.


Question: Reusing files and roles

Answer:
Ansible offers two ways to reuse files and roles in a playbook: dynamic and static.
Task include and import statements can be used at arbitrary depth.
You can still use the bareroleskeyword at the play level to incorporate a role in a playbook statically. However, the bareincludekeyword, once used for both task files and playbook-level includes, is now deprecated.


Question: Includes: dynamic reuse

Answer:
Including roles, tasks, or variables adds them to a playbook dynamically. Ansible processes included files and roles as they come up in a playbook, so included tasks can be affected by the results of earlier tasks within the top-level playbook. Included roles and tasks are similar to handlers - they may or may not run, depending on the results of other tasks in the top-level playbook.
The primary advantage of usinginclude_*statements is looping. When a loop is used with an include, the included tasks or roles will be executed once for each item in the loop.
The file names for included roles, tasks, and vars are templated before inclusion.
You can pass variables into includes. SeeVariable precedence: where should I put a variable?for more details on variable inheritance and precedence.


Question: Imports: static reuse

Answer:
Importing roles, tasks, or playbooks adds them to a playbook statically. Ansible pre-processes imported files and roles before it runs any tasks in a playbook, so imported content is never affected by other tasks within the top-level playbook.
The file names for imported roles and tasks support templating, but the variables must be available when Ansible is pre-processing the imports. This can be done with thevarskeyword or by using--extra-vars.
You can pass variables to imports. You must pass variables if you want to run an imported file more than once in a playbook. For example:
SeeVariable precedence: where should I put a variable?for more details on variable inheritance and precedence.


Question: Comparing includes and imports: dynamic and static reuse

Answer: Each approach to reusing distributed Ansible artifacts has advantages and limitations. You may choose dynamic reuse for some playbooks and static reuse for others. Although you can use both dynamic and static reuse in a single playbook, it is best to select one approach per playbook. Mixing static and dynamic reuse can introduce difficult-to-diagnose bugs into your playbooks. This table summarizes the main differences so you can choose the best approach for each playbook you create.


Question: Reusing tasks as handlers

Answer:
You can also use includes and imports in theHandlers: running operations on changesection of a playbook. For example, if you want to define how to restart Apache, you only have to do that once for all of your playbooks. You might make arestarts.ymlfile that looks like:
You can trigger handlers from either an import or an include, but the procedure is different for each method of reuse. If you include the file, you must notify the include itself, which triggers all the tasks inrestarts.yml. If you import the file, you must notify the individual task(s) withinrestarts.yml. You can mix direct tasks and handlers with included or imported tasks and handlers.


Question: Triggering included (dynamic) handlers

Answer: Includes are executed at run-time, so the name of the include exists during play execution, but the included tasks do not exist until the include itself is triggered. To use theRestartapachetask with dynamic reuse, refer to the name of the include itself. This approach triggers all tasks in the included file as handlers. For example, with the task file shown above:


Question: Triggering imported (static) handlers

Answer: Imports are processed before the play begins, so the name of the import no longer exists during play execution, but the names of the individual imported tasks do exist. To use theRestartapachetask with static reuse, refer to the name of each task or tasks within the imported file. For example, with the task file shown above:


Question: Role directory structure

Answer:
An Ansible role has a defined directory structure with seven main standard directories. You must include at least one of these directories in each role. You can omit any directories the role does not use. For example:
By default, Ansible will look in most role directories for amain.ymlfile for relevant content (alsomain.yamlandmain):
tasks/main.yml- A list of tasks that the role provides to the play for execution.handlers/main.yml- handlers that are imported into the parent play for use by the role or other roles and tasks in the play.defaults/main.yml- very low precedence values for variables provided by the role (seeUsing variablesfor more information). A role’s own defaults will take priority over other role’s defaults, but any/all other variable sources will override this.vars/main.yml- high precedence variables provided by the role to the play (seeUsing variablesfor more information).files/stuff.txt- one or more files that are available for the role and it’s children.templates/something.j2- templates to use in the role or child roles.meta/main.yml- metadata for the role, including role dependencies and optional Galaxy metadata such as platforms supported. This is required for uploading into galaxy as a standalone role, but not for using the role in your play.
You can add other YAML files in some directories, but they won’t be used by default. They can be included/imported directly or specified when usinginclude_role/import_role.
For example, you can place platform-specific tasks in separate files and refer to them in thetasks/main.ymlfile:
Or call those tasks directly when loading the role, which bypasses themain.ymlfiles:
Directoriesdefaultsandvarsmay also includenested directories. If your variables file is a directory, Ansible reads all variables files and directories inside in alphabetical order. If a nested directory contains variables files as well as directories, Ansible reads the directories first. Below is an example of avars/maindirectory:


Question: Storing and finding roles

Answer:
By default, Ansible looks for roles in the following locations:
in collections, if you are using themin a directory calledroles/, relative to the playbook filein the configuredroles_path. The default search path is~/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles.in the directory where the playbook file is located
If you store your roles in a different location, set theroles_pathconfiguration option so Ansible can find your roles. Checking shared roles into a single location makes them easier to use in multiple playbooks. SeeConfiguring Ansiblefor details about managing settings inansible.cfg.
Alternatively, you can call a role with a fully qualified path:


Question: Using roles at the play level

Answer:
The classic (original) way to use roles is with therolesoption for a given play:
When you use therolesoption at the play level, each role ‘x’ looks for amain.yml(alsomain.yamlandmain) in the following directories:
roles/x/tasks/roles/x/handlers/roles/x/vars/roles/x/defaults/roles/x/meta/Any copy, script, template or include tasks (in the role) can reference files in roles/x/{files,templates,tasks}/ (dir depends on task) without having to path them relatively or absolutely.
When you use therolesoption at the play level, Ansible treats the roles as static imports and processes them during playbook parsing. Ansible executes each play in this order:
Anypre_tasksdefined in the play.Any handlers triggered by pre_tasks.Each role listed inroles:, in the order listed. Any role dependencies defined in the role’smeta/main.ymlrun first, subject to tag filtering and conditionals. SeeUsing role dependenciesfor more details.Anytasksdefined in the play.Any handlers triggered by the roles or tasks.Anypost_tasksdefined in the play.Any handlers triggered by post_tasks.
You can pass other keywords to therolesoption:


Question: Including roles: dynamic reuse

Answer:
You can reuse roles dynamically anywhere in thetaskssection of a play usinginclude_role. While roles added in arolessection run before any other tasks in a play, included roles run in the order they are defined. If there are other tasks before aninclude_roletask, the other tasks will run first.
To include a role:
You can pass other keywords, including variables and tags, when including roles:
When you add atagto aninclude_roletask, Ansible applies the tagonlyto the include itself. This means you can pass--tagsto run only selected tasks from the role, if those tasks themselves have the same tag as the include statement. SeeSelectively running tagged tasks in reusable filesfor details.
You can conditionally include a role:


Question: Importing roles: static reuse

Answer:
You can reuse roles statically anywhere in thetaskssection of a play usingimport_role. The behavior is the same as using theroleskeyword. For example:
You can pass other keywords, including variables and tags when importing roles:
When you add a tag to animport_rolestatement, Ansible applies the tag toalltasks within the role. SeeTag inheritance: adding tags to multiple tasksfor details.


Question: Role argument validation

Answer:
Beginning with version 2.11, you may choose to enable role argument validation based on an argument
specification. This specification is defined in themeta/argument_specs.ymlfile (or with the.yamlfile extension). When this argument specification is defined, a new task is inserted at the beginning of role execution
that will validate the parameters supplied for the role against the specification. If the parameters fail
validation, the role will fail execution.


Question: Specification format

Answer:
The role argument specification must be defined in a top-levelargument_specsblock within the
rolemeta/argument_specs.ymlfile. All fields are lowercase.


Question: Running a role multiple times in one play

Answer:
Ansible only executes each role once in a play, even if you define it multiple times unless the parameters defined on the role are different for each definition. For example, Ansible only runs the rolefooonce in a play like this:
You have two options to force Ansible to run a role more than once.


Question: Passing different parameters

Answer:
If you pass different parameters in each role definition, Ansible runs the role more than once. Providing different variable values is not the same as passing different role parameters. You must use theroleskeyword for this behavior, sinceimport_roleandinclude_roledo not accept role parameters.
This play runs thefoorole twice:
This syntax also runs thefoorole twice;
In these examples, Ansible runsfootwice because each role definition has different parameters.


Answer:
Addallow_duplicates:trueto themeta/main.ymlfile for the role:
In this example, Ansible runsfootwice because we have explicitly enabled it to do so.


Question: Using role dependencies

Answer:
Role dependencies let you automatically pull in other roles when using a role.
Role dependencies are prerequisites, not true dependencies. The roles do not have a parent/child relationship. Ansible loads all listed roles, runs the roles listed underdependenciesfirst, then runs the role that lists them. The play object is the parent of all roles, including roles called by adependencieslist.
Role dependencies are stored in themeta/main.ymlfile within the role directory. This file should contain a list of roles and parameters to insert before the specified role. For example:
Ansible always executes roles listed independenciesbefore the role that lists them. Ansible executes this pattern recursively when you use theroleskeyword. For example, if you list rolefoounderroles:, rolefoolists rolebarunderdependenciesin its meta/main.yml file, and rolebarlists rolebazunderdependenciesin its meta/main.yml, Ansible executesbaz, thenbar, thenfoo.


Question: Running role dependencies multiple times in one play

Answer:
Ansible treats duplicate role dependencies like duplicate roles listed underroles:: Ansible only executes role dependencies once, even if defined multiple times, unless the parameters, tags, or when clause defined on the role are different for each definition. If two roles in a play both list a third role as a dependency, Ansible only runs that role dependency once, unless you pass different parameters, tags, when clause, or useallow_duplicates:truein the role you want to run multiple times. SeeGalaxy role dependenciesfor more details.
For example, a role namedcardepends on a role namedwheelas follows:
And thewheelrole depends on two roles:tireandbrake. Themeta/main.ymlfor wheel would then contain the following:
And themeta/main.ymlfortireandbrakewould contain the following:
The resulting order of execution would be as follows:
To useallow_duplicates:truewith role dependencies, you must specify it for the role listed underdependencies, not for the role that lists it. In the example above,allow_duplicates:trueappears in themeta/main.ymlof thetireandbrakeroles. Thewheelrole does not requireallow_duplicates:true, because each instance defined bycaruses different parameter values.


Question: Embedding modules and plugins in roles

Answer:
If you write a custom module (seeShould you develop a module?) or a plugin (seeDeveloping plugins), you might wish to distribute it as part of a role. For example, if you write a module that helps configure your company’s internal software, and you want other people in your organization to use this module, but do not want to tell everyone how to configure their Ansible library path, you can include the module in your internal_config role.
To add a module or a plugin to a role:
Alongside the ‘tasks’ and ‘handlers’ structure of a role, add a directory named ‘library’ and then include the module directly inside the ‘library’ directory.
Assuming you had this:
The module will be usable in the role itself, as well as any roles that are calledafterthis role, as follows:
If necessary, you can also embed a module in a role to modify a module in Ansible’s core distribution. For example, you can use the development version of a particular module before it is released in production releases by copying the module and embedding the copy in a role. Use this approach with caution, as API signatures may change in core components, and this workaround is not guaranteed to work.
The same mechanism can be used to embed and distribute plugins in a role, using the same schema. For example, for a filter plugin:


Question: Sharing roles: Ansible Galaxy

Answer:
Ansible Galaxyis a free site for finding, downloading, rating, and reviewing all kinds of community-developed Ansible roles and can be a great way to get a jumpstart on your automation projects.
The clientansible-galaxyis included in Ansible. The Galaxy client allows you to download roles from Ansible Galaxy and provides an excellent default framework for creating your own roles.
Read theAnsible Galaxy documentationpage for more information.


Question: Module defaults groups

Answer:
Module default groups allow to provide common parameters to groups of modules that belong together. Collections can define such groups in theirmeta/runtime.ymlfile.
Here is an exampleruntime.ymlfile for thens.collcollection.
This file defines an action group namedns.coll.my_groupand places thesample_modulefromns.collandanother_modulefromanother.collectioninto the group.
This group can now be used in a playbook like this:
For historical reasons and backwards compatibility, there are some special groups:
Check out the documentation for the collection or its meta/runtime.yml to see which action plugins and modules are included in the group.
Use the groups withmodule_defaultsby prefixing the group name withgroup/- for examplegroup/aws.


Question: Hashing values supplied byvars_prompt

Answer:
You can hash the entered value so you can use it, for example, with the user module to define a password:
If you havePasslibinstalled, you can use any crypt scheme the library supports:
des_crypt- DES Cryptbsdi_crypt- BSDi Cryptbigcrypt- BigCryptcrypt16- Crypt16md5_crypt- MD5 Cryptbcrypt- BCryptsha1_crypt- SHA-1 Cryptsun_md5_crypt- Sun MD5 Cryptsha256_crypt- SHA-256 Cryptsha512_crypt- SHA-512 Cryptapr_md5_crypt- Apache’s MD5-Crypt variantphpass- PHPass’ Portable Hashpbkdf2_digest- Generic PBKDF2 Hashescta_pbkdf2_sha1- Cryptacular’s PBKDF2 hashdlitz_pbkdf2_sha1- Dwayne Litzenberger’s PBKDF2 hashscram- SCRAM Hashbsd_nthash- FreeBSD’s MCF-compatible nthash encoding
The only parameters accepted are ‘salt’ or ‘salt_size’. You can use your own salt by defining
‘salt’, or have one generated automatically using ‘salt_size’. By default, Ansible generates a salt
of size 8.
If you do not have Passlib installed, Ansible uses thecryptlibrary as a fallback. Ansible supports at most four crypt schemes, depending on your platform at most the following crypt schemes are supported:
bcrypt- BCryptmd5_crypt- MD5 Cryptsha256_crypt- SHA-256 Cryptsha512_crypt- SHA-512 Crypt


Question: Allowing special characters invars_promptvalues

Answer: Some special characters, such as{and%can create templating errors. If you need to accept special characters, use theunsafeoption:


Question: Creating valid variable names

Answer:
Not all strings are valid Ansible variable names. A variable name can only include letters, numbers, and underscores.Python keywordsorplaybook keywordsare not valid variable names. A variable name cannot begin with a number.
Variable names can begin with an underscore. In many programming languages, variables that begin with an underscore are private. This is not true in Ansible. Ansible treats variables that begin with an underscore the same as any other variable. Do not rely on this convention for privacy or security.
This table gives examples of valid and invalid variable names:
Ansible defines certainvariablesinternally. You cannot define these variables.
Avoid variable names that overwrite Jinja2 global functions listed inWorking with playbooks, such aslookup,query,q,now, andundef.


Question: Defining simple variables

Answer: You can define a simple variable using standard YAML syntax. For example:


Question: Referencing simple variables

Answer:
After you define a variable, use Jinja2 syntax to reference it. Jinja2 variables use double curly braces. For example, the expressionMyampgoesto{{max_amp_value}}demonstrates the most basic form of variable substitution. You can use Jinja2 syntax in playbooks. The following example shows a variable that defines the location of a file, which can vary from one system to another:
Ansible allows Jinja2 loops and conditionals intemplatesbut not in playbooks. You cannot create a loop of tasks. Ansible playbooks are pure machine-parseable YAML.


Question: When to quote variables (a YAML gotcha)

Answer:
If you start a value with{{foo}}, you must quote the whole expression to create valid YAML syntax. If you do not quote the whole expression, the YAML parser cannot interpret the syntax. The parser cannot determine if it is a variable or the start of a YAML dictionary. For guidance on writing YAML, see theYAML Syntaxdocumentation.
If you use a variable without quotes, like this:
You will see:ERROR!SyntaxErrorwhileloadingYAML.If you add quotes, Ansible works correctly:


Question: Defining variables as lists

Answer: You can define variables with multiple values using YAML lists. For example:


Question: Referencing list variables

Answer:
If you use a variable defined as a list (also called an array), you can use individual, specific items from that list. The first item in a list is item 0, the second item is item 1, and so on. For example:
The value of this expression would be “northeast”.


Question: Dictionary variables

Answer: A dictionary stores data in key-value pairs. Usually, you use dictionaries to store related data, such as the information contained in an ID or a user profile.


Question: Defining variables as key-value dictionaries

Answer: You can define more complex variables using YAML dictionaries. A YAML dictionary maps keys to values. For example:


Question: Referencing key-value dictionary variables

Answer:
If you use a variable defined as a key-value dictionary (also called a hash), you can use individual, specific items from that dictionary using either bracket notation or dot notation:
Both of these examples reference the same value (“one”). Bracket notation always works. Dot notation can cause problems because some keys collide with attributes and methods of python dictionaries. Use bracket notation if you use keys that start and end with two underscores, which are reserved for special meanings in python, or are any of the known public attributes:
add,append,as_integer_ratio,bit_length,capitalize,center,clear,conjugate,copy,count,decode,denominator,difference,difference_update,discard,encode,endswith,expandtabs,extend,find,format,fromhex,fromkeys,get,has_key,hex,imag,index,insert,intersection,intersection_update,isalnum,isalpha,isdecimal,isdigit,isdisjoint,is_integer,islower,isnumeric,isspace,issubset,issuperset,istitle,isupper,items,iteritems,iterkeys,itervalues,join,keys,ljust,lower,lstrip,numerator,partition,pop,popitem,real,remove,replace,reverse,rfind,rindex,rjust,rpartition,rsplit,rstrip,setdefault,sort,split,splitlines,startswith,strip,swapcase,symmetric_difference,symmetric_difference_update,title,translate,union,update,upper,values,viewitems,viewkeys,viewvalues,zfill.


Question: Combining variables

Answer: To merge variables that contain lists or dictionaries, you can use the following approaches.


Question: Combining list variables

Answer: You can use theset_factmodule to combine lists into a newmerged_listvariable as follows:


Question: Combining dictionary variables

Answer:
To merge dictionaries, use thecombinefilter. For example:
For more details, seeansible.builtin.combine.


Question: Using the merge_variables lookup

Answer:
To merge variables that match the given prefixes, suffixes, or regular expressions, you can use thecommunity.general.merge_variableslookup. For example:
For more details and example usage, refer to thecommunity.general.merge_variables lookup documentation.


Question: Registering variables

Answer:
You can create a variable from the output of an Ansible task with the task keywordregister. You can use the registered variable in any later task in your play. For example:
For more examples of using registered variables in conditions on later tasks, seeConditionals. Registered variables may be simple variables, list variables, dictionary variables, or complex nested data structures. The documentation for each module includes aRETURNsection that describes the return values for that module. To see the values for a particular task, run your playbook with-v.
Registered variables are stored in memory. You cannot cache registered variables for use in future playbook runs. A registered variable is valid only on the host for the rest of the current playbook run, including subsequent plays within the same playbook run.
Registered variables are host-level variables. When you register a variable in a task with a loop, the registered variable contains a value for each item in the loop. The data structure placed in the variable during the loop contains aresultsattribute, which is a list of all responses from the module. For a more in-depth example of how this works, see theLoopssection on using register with a loop.
If a task fails or is skipped, Ansible still registers a variable with a failure or skipped status, unless the task is skipped based on tags. SeeTagsfor information on adding and using tags.


Question: Referencing nested variables

Answer:
Many registered variables andfactsare nested YAML or JSON data structures. You cannot access values from these nested data structures with the simple{{foo}}syntax. You must use either bracket notation or dot notation. For example, to reference an IP address from your facts using bracket notation:
To reference an IP address from your facts using dot notation:


Question: Transforming variables with Jinja2 filters

Answer: Jinja2 filters let you transform the value of a variable within a template expression. For example, thecapitalizefilter capitalizes any value passed to it; theto_yamlandto_jsonfilters change the format of your variable values. Jinja2 includes manybuilt-in filters, and Ansible supplies many more filters. To find more examples of filters, seeUsing filters to manipulate data.


Question: Where to set variables

Answer: You can define variables in a variety of places, such as in inventory, in playbooks, in reusable files, in roles, and at the command line. Ansible loads every possible variable it finds, then chooses the variable to apply based onvariable precedence rules.


Question: Defining variables in inventory

Answer: You can define different variables for each host individually, or set shared variables for a group of hosts in your inventory. For example, if all machines in the[boston]group use ‘boston.ntp.example.com’ as an NTP server, you can set a group variable. TheHow to build your inventorypage has details on settinghost variablesandgroup variablesin inventory.


Question: Defining variables in a play

Answer:
You can define variables directly in a playbook play:
When you define variables in a play, they are visible only to tasks executed in that play.


Question: Defining variables in included files and roles

Answer:
You can define variables in reusable variables files or in reusable roles. If you define variables in reusable variable files, the sensitive variables are separated from playbooks. This separation enables you to store your playbooks in a source control software and even share the playbooks, without the risk of exposing passwords or other sensitive and personal data. For information about creating reusable files and roles, seeReusing Ansible artifacts.
This example shows how you can include variables defined in an external file:
The contents of each variables file is a simple YAML dictionary. For example:
You can keep per-host and per-group variables in similar files. To learn about organizing your variables, seeOrganizing host and group variables.


Question: Defining variables at runtime

Answer: You can define variables when you run your playbook by passing variables at the command line using the--extra-vars(or-e) argument. You can also request user input with avars_prompt(seeInteractive input: prompts). If you pass variables at the command line, use a single quoted string that contains one or more variables in one of the formats below.


Question: Variable precedence: where should I put a variable?

Answer:
You can set multiple variables with the same name in many different places. If you do this, Ansible loads every possible variable it finds, and then chooses the variable to apply based on variable precedence. In other words, the different variables will override each other in a certain order.
Teams and projects that agree on guidelines for defining variables (where to define certain types of variables) usually avoid variable precedence concerns. You should define each variable in one place. Determine where to define a variable, and keep it simple. For examples, seeTips on where to set variables.
Some behavioral parameters that you can set in variables you can also set in Ansible configuration, as command-line options, and using playbook keywords. For example, you can define the user that Ansible uses to connect to remote devices as a variable withansible_user, in a configuration file withDEFAULT_REMOTE_USER, as a command-line option with-u, and with the playbook keywordremote_user. If you define the same parameter in a variable and by another method, the variable overrides the other setting. This approach allows host-specific settings to override more general settings. For examples and more details on the precedence of these various settings, seeControlling how Ansible behaves: precedence rules.


Question: Understanding variable precedence

Answer:
Ansible does apply variable precedence, and you might have a use for it. Here is the order of precedence from least to greatest (the last listed variables override all other variables):
In general, Ansible gives precedence to variables that were defined more recently, more actively, and with more explicit scope. Variables in the defaults folder inside a role are easily overridden. Anything in the vars directory of the role overrides previous versions of that variable in the namespace. Host or inventory variables override role defaults, but explicit includes such as the vars directory or aninclude_varstask override inventory variables.
Ansible merges different variables set in inventory so that more specific settings override more generic settings. For example,ansible_ssh_userspecified as a group_var is overridden byansible_userspecified as a host_var. For details about the precedence of variables set in inventory, seeHow variables are merged.
Footnotes
The previous text describes the default confighash_behavior=replace. Switch tomergeto overwrite only partially.


Question: Tips on where to set variables

Answer:
You should choose where to define a variable based on the kind of control you might want over values.
Set variables in inventory that deal with geography or behavior. Since groups are frequently the entity that maps roles to hosts, you can often set variables on the group instead of defining them on a role. Remember that child groups override parent groups, and host variables override group variables. SeeDefining variables in inventoryfor details on setting host and group variables.
Set common defaults in agroup_vars/allfile. SeeOrganizing host and group variablesfor details on how to organize host and group variables in your inventory. You generally place group variables alongside your inventory file, but they can also be returned by dynamic inventory (seeWorking with dynamic inventory) or defined in AWX or on theRed Hat Ansible Automation Platformfrom the UI or API:
Set location-specific variables ingroup_vars/my_locationfiles. All groups are children of theallgroup, so variables set here override those set ingroup_vars/all:
If one host used a different NTP server, you could set that in a host_vars file, which would override the group variable:
Set defaults in roles to avoid undefined-variable errors. If you share your roles, other users can rely on the reasonable defaults you added in theroles/x/defaults/main.ymlfile, or they can easily override those values in inventory or at the command line. SeeRolesfor more info. For example:


Question: Using advanced variable syntax

Answer: For information about advanced YAML syntax used to declare variables and have more control over the data placed in YAML files used by Ansible, seeAdvanced playbook syntax.


Question: Package requirements for fact gathering

Answer:
On some distros, you may see missing fact values or facts set to default values because the packages that support gathering those facts are not installed by default. You can install the necessary packages on your remote hosts using the OS package manager. Known dependencies include:
Linux Network fact gathering -  Depends on  theipbinary, commonly included in theiproute2package.


Question: Adding custom facts

Answer: The setup module in Ansible automatically discovers a standard set of facts about each host. If you want to add custom values to your facts, you can write a custom facts module, set temporary facts with aansible.builtin.set_facttask, or provide permanent custom facts using the facts.d directory.


Question: Information about Ansible: magic variables

Answer:
You can access information about Ansible operations, including the Python version being used, the hosts and groups in inventory, and the directories for playbooks and roles, using “magic” variables. Like connection variables, magic variables areSpecial Variables. Magic variable names are reserved - do not set variables with these names. The variableenvironmentis also reserved.
The most commonly used magic variables arehostvars,groups,group_names, andinventory_hostname. Withhostvars, you can access variables defined for any host in the play, at any point in a playbook. You can access Ansible facts using thehostvarsvariable too, but only after you have gathered (or cached) facts.  Note that variables defined at play objects are not defined for specific hosts and therefore are not mapped to hostvars.
If you want to configure your database server using the value of a ‘fact’ from another node, or the value of an inventory variable assigned to another node, you can usehostvarsin a template or on an action line:
Withgroups, a list of all the groups (and hosts) in the inventory, you can enumerate all hosts within a group. For example:
You can usegroupsandhostvarstogether to find all the IP addresses in a group.
You can use this approach to point a frontend proxy server to all the hosts in your app servers group, to set up the correct firewall rules between servers, and so on. You must either cache facts or gather facts for those hosts before the task that fills out the template.