Chapter 2 RH294 RHEL Automation with Ansible

Chapter 2. Implementing Ansible Playbook


ONLY FOR SELF STUDY, NO COMMERCIAL USAGE!!!

Building inventory

  • An inventory defines a collection of hosts that Ansible manages.
    • hosts can be assigned to groups
    • group can contain child groups
    • hosts can be members of multiple groups
    • inventory can set variable to select a range of hosts/groups
    • static host inventory(INI-style or YAML)
    • Dynamic host inventory(Ansible plug-in)
Static Inventory
  • txt file that support a number of different formats, including INI-style(most common) or YAML
  • hostname cannot have space, like [New York] would not work, correct should be [Newyork]
  1. A list of hostnames or IP addresses of managed hosts, each on a single line:

    web1.example.com
    web2.example.com
    db1.example.com
    db2.example.com
    192.0.2.42
    
  2. Organize managed hosts into host groups.
    In the following example, the host inventory defines two host groups: webservers and db-servers.

    [webservers]
    web1.example.com
    web2.example.com
    192.0.2.42
    
    [db-servers]
    db1.example.com
    db2.example.com
    
  3. Hosts can be in multiple groups. (role of the host, its physical location, whether it is in production or not, and so on).

    [webservers]
    web1.example.com
    web2.example.com
    192.0.2.42
    
    [db-servers]
    db1.example.com
    db2.example.com
    
    [east-datacenter]
    web1.example.com
    db1.example.com
    
    [production]
    web1.example.com
    web2.example.com
    db1.example.com
    db2.example.com
    
    [development]
    192.0.2.42
    
  4. Nested Groups

    • creating a host group name with the :children suffix. The following example creates a new group called north-america, which includes all hosts from the usa and canada groups.
    • A group can have both managed hosts and child groups as members. For example, in the previous inventory you could add a [north-america] section that has its own list of managed hosts. That list of hosts would be merged with the additional hosts that the north-america group inherits from its child groups.
    [usa]
    washington1.example.com
    washington2.example.com
    
    [canada]
    ontario01.example.com
    ontario02.example.com
    
    [north-america:children]
    canada
    usa
    
    [north-america]
    washington03.example.com
    
Simplifying Host Specifications with Ranges

Ranges have the following syntax:

[START:END]

Ranges match all values from START to END, inclusively. Consider the following examples:

  • 192.168.[4:7].[0:255] matches all IPv4 addresses in the 192.168.4.0/22 network (192.168.4.0 through 192.168.7.255).
  • server[01:20].example.com matches all hosts named server01.example.com through server20.example.com.
  • [a:c].dns.example.com matches hosts named a.dns.example.com, b.dns.example.com, and c.dns.example.com.
  • 2001:db8::[a:f] matches all IPv6 addresses from 2001:db8::a through 2001:db8::f.

NTOE: If leading zeros are included in numeric ranges, they are used in the pattern. The second example above does not match server1.example.com but does match server07.example.com.

Verifying the Inventory

ansible-navigator inventory command to query an inventory file.

[student@workstation ~]$ ansible-navigator inventory --help
Usage: ansible-navigator inventory [options]

inventory: Explore an inventory

Options (global):
 -h     --help                                   Show this help message and exit
 --version                                       Show the application version and exit
 --rad  --ansible-runner-artifact-dir            The directory path to store artifacts generated by ansible-runner
 --rac  --ansible-runner-rotate-artifacts-count  Keep ansible-runner artifact directories, for last n runs, if set to 0
                                                 artifact directories won't be deleted
 --rt   --ansible-runner-timeout                 The timeout value after which ansible-runner will forcefully stop the
                                                 execution
 --cdcp --collection-doc-cache-path              The path to collection doc cache (default:
                                                 /home/student/.cache/ansible-navigator/collection_doc_cache.db)
 --ce   --container-engine                       Specify the container engine (auto=podman then docker)
                                                 (auto|podman|docker) (default: auto)
 --co   --container-options                      Extra parameters passed to the container engine command
 --dc   --display-color                          Enable the use of color for mode interactive and stdout (true|false)
                                                 (default: true)
 --ecmd --editor-command                         Specify the editor command (default: vi +{line_number} {filename})
 --econ --editor-console                         Specify if the editor is console based (true|false) (default: true)
 --ee   --execution-environment                  Enable or disable the use of an execution environment (true|false)
                                                 (default: true)
 --eei  --execution-environment-image            Specify the name of the execution environment image (default:
                                                 registry.redhat.io/ansible-automation-platform-22/ee-supported-
                                                 rhel8:latest)
 --eev  --execution-environment-volume-mounts    Specify volume to be bind mounted within an execution environment
                                                 (--eev /home/user/test:/home/user/test:Z)
 --la   --log-append                             Specify if log messages should be appended to an existing log file,
                                                 otherwise a new log file will be created per session (true|false)
                                                 (default: true)
 --lf   --log-file                               Specify the full path for the ansible-navigator log file (default:
                                                 /home/student/ansible-navigator.log)
 --ll   --log-level                              Specify the ansible-navigator log level
                                                 (debug|info|warning|error|critical) (default: warning)
 -m     --mode                                   Specify the user-interface mode (stdout|interactive) (default:
                                                 interactive)
 --osc4 --osc4                                   Enable or disable terminal color changing support with OSC 4
                                                 (true|false) (default: true)
 --penv --pass-environment-variable              Specify an existing environment variable to be passed through to and
                                                 set within the execution environment (--penv MY_VAR)
 --pa   --pull-arguments                         Specify any additional parameters that should be added to the pull
                                                 command when pulling an execution environment from a container
                                                 registry. e.g. --pa='--tls-verify=false'
 --pp   --pull-policy                            Specify the image pull policy always:Always pull the image,
                                                 missing:Pull if not locally available, never:Never pull the image,
                                                 tag:if the image tag is 'latest', always pull the image, otherwise
                                                 pull if not locally available (always|missing|never|tag) (default:
                                                 tag)
 --senv --set-environment-variable               Specify an environment variable and a value to be set within the
                                                 execution environment (--senv MY_VAR=42)
 --tz   --time-zone                              Specify the IANA time zone to use or 'local' to use the system time
                                                 zone (default: utc)

Options (inventory subcommand):
 --hi   --help-inventory                         Help options for ansible-inventory command in stdout mode (true|false)
 -i     --inventory                              Specify an inventory file path or comma separated host list
 --ic   --inventory-column                       Specify a host attribute to show in the inventory view

Note: With '--mode stdout', 'ansible-navigator inventory' additionally supports the same parameters as the 'ansible-
inventory' command. For more information about these, try 'ansible-navigator inventory --help-inventory --mode stdout'

Check local ‘inventory’ file:

[user@controlnode ~]$ ansible-navigator inventory -i inventory

# The examples assume that a file named `inventory` exists in the current directory and that the file uses ranges to simplify the `[usa]` and `[canada]` group definitions

[student@workstation playbook-inventory]$ cat inventory 
[Webserver]
servera.lab.example.com
serverb.lab.example.com
serverc.lab.example.com
serverd.lab.example.com

[Raleigh]
servera.lab.example.com
serverb.lab.example.com

[Mountainview]
serverc.lab.example.com

[London]
serverd.lab.example.com

[Development]
servera.lab.example.com

[Testing]
serverb.lab.example.com

[Production]
serverc.lab.example.com
serverd.lab.example.com

[US:children]
Raleigh
Mountainview

Verify if the host in the inventory:
[user@controlnode ~]$ ansible-navigator inventory -i inventory -m stdout --host servera.lab.example.com

Lists all hosts in the inventory:

[user@controlnode ~]$ ansible-navigator inventory -i inventory -m stdout --list

[student@workstation playbook-inventory]$ ansible-navigator inventory -i inventory -m stdout --list
{
    "Development": {
        "hosts": [
            "servera.lab.example.com"
        ]
    },
    "London": {
        "hosts": [
            "serverd.lab.example.com"
        ]
    },
    "Mountainview": {
        "hosts": [
            "serverc.lab.example.com"
        ]
    },
    "Production": {
        "hosts": [
            "serverc.lab.example.com",
            "serverd.lab.example.com"
        ]
    },
    "Raleigh": {
        "hosts": [
            "servera.lab.example.com",
            "serverb.lab.example.com"
        ]
    },
    "Testing": {
        "hosts": [
            "serverb.lab.example.com"
        ]
    },
    "US": {
        "children": [
            "Mountainview",
            "Raleigh"
        ]
    },
    "Webserver": {
        "hosts": [
            "servera.lab.example.com",
            "serverb.lab.example.com",
            "serverc.lab.example.com",
            "serverd.lab.example.com"
        ]
    },
    "_meta": {
        "hostvars": {}
    },
    "all": {
        "children": [
            "Development",
            "London",
            "Production",
            "Testing",
            "US",
            "Webserver",
            "ungrouped"
        ]
    }
}

The following command lists all hosts in a group.

[user@controlnode ~]$ ansible-navigator inventory -i inventory -m stdout --graph US

[student@workstation playbook-inventory]$ ansible-navigator inventory -i inventory -m stdout --graph US
@US:
  |--@Mountainview:
  |  |--serverc.lab.example.com
  |--@Raleigh:
  |  |--servera.lab.example.com
  |  |--serverb.lab.example.com
  

[student@workstation playbook-inventory]$ ansible-navigator inventory -i inventory -m stdout --graph all
@all:
  |--@Development:
  |  |--servera.lab.example.com
  |--@London:
  |  |--serverd.lab.example.com
  |--@Production:
  |  |--serverc.lab.example.com
  |  |--serverd.lab.example.com
  |--@Testing:
  |  |--serverb.lab.example.com
  |--@US:
  |  |--@Mountainview:
  |  |  |--serverc.lab.example.com
  |  |--@Raleigh:
  |  |  |--servera.lab.example.com
  |  |  |--serverb.lab.example.com
  |--@Webserver:
  |  |--servera.lab.example.com
  |  |--serverb.lab.example.com
  |  |--serverc.lab.example.com
  |  |--serverd.lab.example.com
  |--@ungrouped:

Run the ansible-navigator inventory command to interactively browse inventory hosts and groups:

[user@controlnode ~]$ ansible-navigator inventory -i inventory
  Title             Description
0│Browse groups     Explore each inventory group and group members members
1│Browse hosts      Explore the inventory with a list of all hosts


Type `:0` to select "Browse Groups":

Type `:1` to select "Browse Hosts"

Press the ESC key to exit the Groups menu.

Ensure that host groups do not use the same names as hosts in the inventory or you will get a warning when runs commands.

Overriding the Location of the Inventory

The /etc/ansible/hosts file is considered the system’s default static inventory file. However, normal practice is not to use that file but to specify a different location for your inventory files as following:

ansible-navigator --inventory <pathname>

ansible-navigator -i <pathname>

You can also define a different default location for the inventory file in your Ansible configuration file.

Dynamic Inventories

By using Ansible plug-ins, Ansible inventory information can also be dynamically generated, using information provided by external databases.

For example, a dynamic inventory program could contact your Red Hat Satellite server or Amazon EC2 account, and use information stored there to construct an Ansible inventory. It can populate the inventory with up-to-date information provided by the service as new hosts are added, and old hosts are removed.

REFERENCES How to build your inventory: Ansible Documentation

Managing Ansible Configuration Files

Ansible configuration file

You can create and edit two files in each of your Ansible project directories that configure the behavior of Ansible and the ansible-navigator command.

  • ansible.cfg, which configures the behavior of several Ansible tools.
  • ansible-navigator.yml, which changes default options for the ansible-navigator command.
Ansible setting

use the following two sections:

  • [defaults], which sets defaults for Ansible operation
  • [privilege_escalation], which configures how Ansible performs privilege escalation on managed hosts

The following is a sample ansible.cfg file:

[defaults]
inventory = ./inventory 
remote_user = user 
ask_pass = false 

[privilege_escalation]
become = true 
become_method = sudo 
become_user = root 
become_ask_pass = false 
inventroyThe inventory parameter specifies the path to a static inventory file, or to a directory containing multiple static inventory files and dynamic inventory scripts.
remote_userThe remote_user parameter specifies the username that Ansible uses to connect to the managed hosts. In a container-based automation execution environment run by ansible-navigator, this defaults to root.
ask_passThe ask_pass parameter specifies whether to prompt for an SSH password. Defaults to false. Set this parameter to true for password-based SSH authentication, or to false for SSH public key authentication. If you use the ansible-navigator command, then setting this parameter to true requires disabling playbook artifacts and using the standard output mode.
ssh-keygen to create a public key and then ssh-copy-id user@host.example.com to copy the public key to the managed host host.example.com
becomeThe become parameter specifies whether to automatically switch users on the managed host (typically to root) after connecting. Defaults to false. Although you can enable privilege escalation for all plays by setting this parameter to true, you might decide to only enable privilege escalation on the plays, blocks, or tasks that require elevated privileges.
become_methodThe become_method parameter specifies how to switch users. Defaults to sudo, although other methods, such as su, are available.
config file: /etc/sudoers or create file under folder/etc/sudoers.d, command: visudo

## Allows people in group wheel to run all commands %wheel ALL=(ALL) ALL
## Same thing without a password
# %wheel ALL=(ALL) NOPASSWD: ALL
become_userThe become_user parameter specifies which user to switch to on the managed host. Defaults to root.
become_ask_passThe become_ask_pass parameter specifies whether to prompt for a password for the become_method parameter. Defaults to false. If you use the ansible-navigator command, then setting this parameter to true requires disabling playbook artifacts and using the standard output mode.

NOTE:

  • The ansible-playbook command can also use a .ansible.cfg file in your home directory or the /etc/ansible/ansible.cfg file, but these local files on your system are not used by the ansible-navigator command.

  • If the managed hosts would not have SSH key-based authentication configured yet, you would have to run like following:

    ansible-navigator run --ask-pass -pae false -m stdout <ping-internetweb.yml> the command prompts to authenticate as the remote user.

Determining Current config

ansible-navigator config command run from a /home/student/project/ directory that contains an ansible.cfg file:

   Name                        Default Source                            Current
...output omitted...
44│Default ask pass            True    default                           False
45│Default ask vault pass      True    default                           False
46│Default become              False   /home/student/project/ansible.cfg True
47│Default become ask pass     False   /home/student/project/ansible.cfg True
 ...output omitted...
50│Default become method       False   /home/student/project/ansible.cfg sudo
51│Default become user         False   /home/student/project/ansible.cfg root
 ...output omitted...

In the preceding example, each line describes an Ansible configuration parameter.

  • The True value in the Default column for the Default ask pass and Default ask vault pass parameters means that the parameters are using their default values. The current value for both parameters is False and the values are displayed in the Current column.
  • The Default become and Default become ask pass parameters have been manually configured to True in the /home/student/project/ansible.cfg configuration file. The Default column is False for these two parameters. The Source column provides the path to the configuration file which defines these parameters, and the Current column shows that the value for these two parameters is True.
  • The Default become method parameter has the current value of sudo, and the Default become user parameter has the current value of root.
Ansible-navigator setting

Creating a configuration file (or settings file) for ansible-navigator to override the default values of its configuration settings. The settings file can be in JSON (.json) or YAML (.yml or .yaml) format.

Automation content navigator looks for a settings file in the following order and uses the first file that it finds:

  • If the ANSIBLE_NAVIGATOR_CONFIG environment variable is set, then use the configuration file at the location it specifies.
  • An ansible-navigator.yml file in your current Ansible project directory.
  • A .ansible-navigator.yml file in your home directory (notice that the file name contains a “dot” at the start of the name).

Just like the Ansible configuration file, each project can have its own automation content navigator settings file.

The following ansible-navigator.yml file configures some common settings:

---
ansible-navigator:
  execution-environment: 
    image: utility.lab.example.com/ee-supported-rhel8:latest 
    pull:
      policy: missing 
  playbook-artifact: 
    enable: false 
  mode: stdout 
execution-environmentThe execution-environment section configures settings for the automation execution environment that the ansible-navigator command uses.
imageThe image key defines the container image name to use for the automation execution environment.
policyThe policy key nested below the pull section states to only pull the container image if it does not already exist on the local machine.
playbook-artifactThe playbook-artifact section configures settings for the JSON files that Ansible generates every time you run a playbook. Each generated JSON file records information about a specific playbook run. You can use these files to review the results of a playbook run or to troubleshoot playbook issues.
enableThe enable key nested below the playbook-artifact section disables generating playbook artifacts when using the ansible-navigator run command. Playbook artifacts must be disabled when you require a prompt for a password when running a playbook. You can temporarily override this setting from the command line with the --pae option.
modeThe mode key defines the output mode for the ansible-navigator command. The value for this key should be set to either interactive (the default) or stdout. You can temporarily override this setting from the command line with the -m option.

Additional Ref:
Developing Advanced Automation with Red Hat Ansible Automation Platform (DO374). Refer to https://ansible.readthedocs.io/projects/navigator/settings/ for more documentation on the settings that you can use in this file.

Configuration File Comments

Both the ansible.cfg file and ansible-navigator.yml support the number sign (#) at the start of a line as a comment character.

In addition, the ansible.cfg file supports the semicolon (😉 as a comment character. The semicolon character comments out everything to the right of it on the line.

Writing and Running Ansible Playbooks

Format of Ansible Playbooks
  • The power of Ansible is that you can use playbooks to run multiple, complex tasks against a set of targeted hosts in an easily repeatable manner.

  • A task is the application of a module to perform a specific unit of work. A play is a sequence of tasks to be applied, in order, to one or more hosts selected from your inventory. A playbook is a text file containing a list of one or more plays to run in a specific order.

  • The following example contains one play with a single task.

    ---
    - name: Configure important user consistently
      hosts: servera.lab.example.com
      tasks:
        - name: Newbie exists with UID 4000
          ansible.builtin.user:
            name: newbie
            uid: 4000
            state: present
    
    • A playbook is a text file written in YAML format(.yml file)

    • Uses indentation with space characters to indicate the structure of its data (Do not use TAB characters). YAML does not place strict requirements on how many spaces are used for the indentation, but two basic rules apply:

      • Data elements at the same level in the hierarchy (such as items in the same list) must have the same indentation.

      • Items that are children of another item must be indented more than their parents.

    • You can also add blank lines for readability.

    • For vi text editor to easily edit your playbooks. add the following line to your $HOME/.vimrc file, and when vi detects that you are editing a YAML file, it performs a 2-space indentation when you press the Tab key and automatically indents subsequent lines.

      autocmd FileType yaml setlocal ai ts=2 sw=2 et
      
  • Rules of playbooks

    • Usually start with three dashes(—), might end with three dots(…) but often being omitted.

    • The play itself is a collection of key-value pairs. Keys in the same play should have the same indentation. The following example shows a YAML snippet with three keys. The first two keys have simple values. The third has a list of three items as a value. The Ansible always run plays in order.

        name: just an example
        hosts: webservers
        tasks:
      	- name: Web server is enabled
            ansible.builtin.service:
              name: httpd
              enabled: true
      
          - name: NTP server is enabled
            ansible.builtin.service:
              name: chronyd
              enabled: true
      
          - name: Postfix is enabled
            ansible.builtin.service:
              name: postfix
              enabled: true
      
  • Finding Modules for tasks

    • The ansible-core package provides a single Ansible Content Collection named ansible.builtin. These modules are always available to you. Visit https://docs.ansible.com/ansible/latest/collections/ansible/builtin/ for a list of modules contained in the ansible.builtin collection.
    • ansible-navigator collections command show Red Hat Ansible Automation Platform 2.2, ee-supported-rhel8, includes a number of other Ansible Content Collections.
    • Other ansible contents:(installed in the collections directory of your Ansible project, no formal support by RH)
      • The automation hub offered through the Red Hat Hybrid Cloud Console at https://console.redhat.com/ansible/automation-hub
      • A private automation hub managed by your organization
      • The community’s Ansible Galaxy website at https://galaxy.ansible.com
Running Playbooks
  • ansible-navigator run

  • The following example shows the contents of a simple playbook, and then the result of running it.

    [user@controlnode playdemo]$ cat webserver.yml
    ---
    - name: Play to set up web server
      hosts: servera.lab.example.com
      tasks:
      - name: Latest httpd version installed
        ansible.builtin.dnf:
          name: httpd
          state: latest
    ...output omitted...
    
    [user@controlnode playdemo]$ ansible-navigator run \
    > -m stdout webserver.yml
    
    PLAY [Play to set up web server] ************************************************
    
    TASK [Gathering Facts] *********************************************************
    ok: [servera.lab.example.com]
    
    TASK [Latest httpd version installed] ******************************************
    changed: [servera.lab.example.com]
    
    PLAY RECAP *********************************************************************
    servera.lab.example.com    : ok=2    changed=1    unreachable=0    failed=0   skipped=0    rescued=0    ignored=0
    

    The value of the name key for each play and task is displayed when the playbook is run. (The Gathering Facts task is a special task that the ansible.builtin.setup module usually runs automatically at the start of a play.

    You should also see that the Latest httpd version installed task is changed for servera.lab.example.com. This means that the task changed something on that host to ensure that its specification was met. In this case, it means that the httpd package was not previously installed or was not the latest version.

    In general, tasks in Ansible Playbooks are idempotent, and it is safe to run a playbook multiple times. If the targeted managed hosts are already in the correct state, no changes should be made. For example, assume that the playbook from the previous example is run again:

    [user@controlnode playdemo]$ ansible-navigator run \
    > -m stdout webserver.yml
    
    PLAY [Play to set up web server] ************************************************
    
    TASK [Gathering Facts] *********************************************************
    ok: [servera.lab.example.com]
    
    TASK [Latest httpd version installed] ******************************************
    ok: [servera.lab.example.com]
    
    PLAY RECAP *********************************************************************
    servera.lab.example.com    : ok=2    changed=0    unreachable=0    failed=0   skipped=0    rescued=0    ignored=0
    

    This time, all tasks passed with status ok and no changes were reported.

Increasing Output Verbosity

The default output does not provide detailed task execution information. The -v option provides additional information, with up to four levels.

Table 2.2. Configuring the Output Verbosity of Playbook Execution

OptionDescription
-vDisplays task results.
-vvDisplays task results and task configuration.
-vvvDisplays extra information about connections to managed hosts.
-vvvvAdds extra verbosity options to the connection plug-ins, including users being used on the managed hosts to execute scripts, and what scripts have been executed.
Syntax Verification

ansible-navigator run --syntax-check command to validate the syntax of a playbook. The following example shows the successful syntax validation of a playbook.

[user@controlnode playdemo]$ ansible-navigator run \
> -m stdout webserver.yml --syntax-check
playbook: /home/user/playdemo/webserver.yml

When syntax validation fails, a syntax error is reported. The output also includes the approximate location of the syntax issue in the playbook. The following example shows the failed syntax validation of a playbook where the space separator is missing after the name attribute for the play.

[user@controlnode playdemo]$ ansible-navigator run \
> -m stdout webserver.yml --syntax-check

ERROR! Syntax Error while loading YAML.
  mapping values are not allowed in this context

The error appears to have been in ...output omitted... line 3, column 8, but may
be elsewhere in the file depending on the exact syntax problem.

The offending line appears to be:

- name:Play to set up web server
  hosts: servera.lab.example.com
       ^ here
Executing a Dry Run

ansible-navigator run --check option to run a playbook in check mode, which performs a “dry run” of the playbook. it does not make any actual changes to managed hosts. (Sometimes the Dry run report a failure but actually Run would finished OK, eg. the Dru Run can not start a service so the later service check step failed but the Real Run would not have the problem.)

In this case, the dry run reports that the task would make a change on the managed host for the latest httpd version to be installed.

[user@controlnode playdemo]$ ansible-navigator run \
> -m stdout webserver.yml --check

PLAY [Play to set up web server] ***********************************************

TASK [Gathering Facts] *********************************************************
ok: [servera.lab.example.com]

TASK [Latest httpd version installed] ******************************************
changed: [servera.lab.example.com]

PLAY RECAP *********************************************************************
servera.lab.example.com    : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
REFERENCES

Intro to playbooks — Ansible Documentation

Working with playbooks — Ansible Documentation

Validating tasks: check mode and diff mode — Ansible Documentation

Implementing Multiple Plays

Writing a playbook that contains multiple plays is very straightforward. Each play in the playbook is written as a top-level list item in the playbook. Each play is a list item containing the usual play keywords.

Remote Users in Plays
  • Ansible determines which user account to use when connecting to a managed host based on the following list, selecting the first username it finds in this order:

    • The ansible_user variable set for the host or group, if set.

    • The remote_user from the current play, if set.

      remote_user: remoteuser
      
    • The remote_user from the ansible.cfg configuration file, if set.

If no value has been set for any of the preceding settings, and you are running playbooks by using ansible-navigator with an execution environment, Ansible uses root. (If you are using ansible-playbook, Ansible uses the name of the user that ran the command.)

Privilege Escalation in Plays
  • Use the become Boolean keyword to enable(yes/true) or disable(no/false) privilege escalation for an individual play or task.

  • use the become_method keyword in the play to specify the privilege escalation method to use for that play

  • use the become_user keyword in the play to define the user account to use for privilege escalation in that specific play.

  • The following example demonstrates some of these keywords in a play:

    - name: /etc/hosts is up-to-date
      hosts: datacenter-west
      remote_user: automation
      become: true
      become_method: sudo
      become_user: root
    
      tasks:
        - name: server.example.com in /etc/hosts
          ansible.builtin.lineinfile:
            path: /etc/hosts
            line: '192.0.2.42 server.example.com server'
            state: present
    
Selecting Modules

Table 2.3. Ansible Modules

CategoryModules
Filesansible.builtin.copy: Copy a local file to the managed host.ansible.builtin.file: Set permissions and other properties of files.ansible.builtin.lineinfile: Ensure a particular line is or is not in a file.ansible.posix.synchronize: Synchronize content using rsync.
Softwareansible.builtin.package: Manage packages using the automatically detected package manager native to the operating system.ansible.builtin.dnf: Manage packages using the DNF package manager.ansible.builtin.apt: Manage packages using the APT package manager.ansible.builtin.pip: Manage Python packages from PyPI.
Systemansible.posix.firewalld: Manage arbitrary ports and services using firewalld.ansible.builtin.reboot: Reboot a machine.ansible.builtin.service: Manage services.ansible.builtin.user: Add, remove, and manage user accounts.
Net Toolsansible.builtin.get_url: Download files over HTTP, HTTPS, or FTP.ansible.builtin.uri: Interact with web services.
Module Documentation
  • run the ansible-navigator doc -l command to displays a list of module short names and a synopsis of their functions.
  • runansible-navigator doc *module_name* command to display detailed documentation for a module. (interactive mode and can use -m stdout to show pages)
  • ansible-navigator collections to use interactive mode to browse module
  • ansible-navigator -s doc *module_name* to show summary of a module
[user@controlnode ~]$ ansible-navigator doc -l
add_host                                                Add a host (and alt...
amazon.aws.aws_az_facts                                 Gather information ...
amazon.aws.aws_az_info                                  Gather information ...
amazon.aws.aws_caller_info                              Get information abo...
amazon.aws.aws_s3                                       manage objects in S...
...output omitted...
vyos.vyos.vyos_user                                     Manage the collecti...
vyos.vyos.vyos_vlan                                     Manage VLANs on VyO...
wait_for                                                Waits for a conditi...
wait_for_connection                                     Waits until remote ...
yum                                                     Manages packages wi...
yum_repository                                          Add or remove YUM r...
Example
---
- name: Enable intranet services
  hosts: servera.lab.example.com
  become: true
  tasks:
    - name: Latest version of httpd and firewalld installed
      ansible.builtin.dnf:
        name:
          - httpd
          - firewalld
        state: latest

    - name: Test html page is installed
      ansible.builtin.copy:
        content: "Welcome to the example.com intranet!\n"
        dest: /var/www/html/index.html

    - name: Firewall enabled and running
      ansible.builtin.service:
        name: firewalld
        enabled: true
        state: started

    - name: Firewall permits access to httpd service
      ansible.posix.firewalld:
        service: http
        permanent: true
        state: enabled
        immediate: true

    - name: Web server enabled and running
      ansible.builtin.service:
        name: httpd
        enabled: true
        state: started

- name: Test intranet web server
  hosts: workstation.lab.example.com
  become: false
  tasks:
    - name: Connect to intranet web server
      ansible.builtin.uri:
        url: http://servera.lab.example.com
        return_content: true
        status_code: 200
  1. The directory has already been populated with an ansible.cfg configuration file and an inventory file named inventory. The managed host, servera.lab.example.com, is already defined in this inventory file.

  2. Create a playbook named /home/student/playbook-multi/intranet.yml and add the lines needed to start the first play. It should target the managed host servera.lab.example.com and enable privilege escalation.

  3. As the first task in the first play, define a task that ensures that the httpd and firewalld packages are up-to-date.

  4. Add a task to the first play’s list that ensures that the correct content is in the /var/www/html/index.html file.

  5. Define two more tasks in the play to ensure that the firewalld service is running and starts on boot, and allows connections to the httpd service.

  6. Add a final task to the first play that ensures that the httpd service is running and starts at boot.

  7. In the /home/student/playbook-multi/intranet.yml file, define a second play that targets workstation.lab.example.com and tests the intranet web server. By testing from the workstation.lab.example.com machine, you can verify that the servera.lab.example.com machine allows external web requests through the firewall. This play does not require privilege escalation.

  8. Add a single task to the second play, and use the ansible.builtin.uri module to request content from http://servera.lab.example.com. The task should verify a return HTTP status code of 200. Configure the task to place the returned content in the task results variable.

    Run the playbook using the ansible-navigator run command.

    [student@workstation playbook-multi]$ ansible-navigator run \
    > -m stdout intranet.yml
    
    PLAY [Enable intranet services] ************************************************
    
    TASK [Gathering Facts] *********************************************************
    ok: [servera.lab.example.com]
    
    TASK [Latest version of httpd and firewalld installed] *************************
    changed: [servera.lab.example.com]
    
    TASK [Test html page is installed] *********************************************
    changed: [servera.lab.example.com]
    
    TASK [Firewall enabled and running] ********************************************
    changed: [servera.lab.example.com]
    
    TASK [Firewall permits access to httpd service] ********************************
    changed: [servera.lab.example.com]
    
    TASK [Web server enabled and running] ******************************************
    changed: [servera.lab.example.com]
    
    PLAY [Test intranet web server] ************************************************
    
    TASK [Gathering Facts] *********************************************************
    ok: [workstation.lab.example.com]
    
    TASK [Connect to intranet web server] ******************************************
    ok: [workstation.lab.example.com]
    
    PLAY RECAP *********************************************************************
    servera.lab.example.com    : ok=6    changed=5    unreachable=0    failed=0  ...
    workstation.lab.example.com : ok=2    changed=0    unreachable=0    failed=0 ...
    

    Use the curl command to verify that an HTTP GET request to http://servera.lab.example.com provides the correct content.

    [student@workstation playbook-multi]$ curl http://servera.lab.example.com
    Welcome to the example.com intranet!
    
Running Arbitrary Commands on Managed Hosts

The ansible.builtin.command module is the simplest of these commands. Its cmd argument specifies the command that you want to run.

The following example task runs /opt/bin/makedb.sh on managed hosts.

- name: Run the /opt/bin/makedb.sh command
  ansible.builtin.command:
    cmd: /opt/bin/makedb.sh

Unlike most modules, ansible.builtin.command is not idempotent. Every time the task is specified in a play, it runs and it reports that it changed something on the managed host, even if nothing needed to be changed.

You can try to make the task safer by configuring it only to run based on the existence of a file. The creates option causes the task to run only if a file is missing; the assumption is that if the task runs, it creates that file. The removes option causes the task to run only if a file is present; the assumption is that if the task runs, it removes that file.

For example, the following task only runs if /opt/db/database.db is not present:

- name: Initialize the database
  ansible.builtin.command:
    cmd: /opt/bin/makedb.sh
    creates: /opt/db/database.db

The ansible.builtin.command module cannot access shell environment variables or perform shell operations such as input/output redirection or pipelines. When you need to perform shell processing, you can use the ansible.builtin.shell module. Like the ansible.builtin.command module, you pass the commands to be executed as arguments to the module.

Both ansible.builtin.command and ansible.builtin.shell modules require a working Python installation on the managed host. A third module, ansible.builtin.raw, can run commands directly using the remote shell, bypassing the module subsystem. This is useful when you are managing systems that cannot have Python installed (for example, a network router). It can also be used to install Python on a managed host.

IMPORTANT NOTE:

When possible, try to avoid the ansible.builtin.command, ansible.builtin.shell, and ansible.builtin.raw modules in playbooks, even though they might seem simple to use. Because these run arbitrary commands on the managed hosts, it is very easy to write non-idempotent playbooks with these modules.

If you must use them, it is probably best to use the ansible.builtin.command module first, resorting to ansible.builtin.shell or ansible.builtin.raw only if you need their special features.

As another example, the following task using the ansible.builtin.shell module is not idempotent. Every time the play is run, it rewrites /etc/resolv.conf even if it already consists of the line nameserver 192.0.2.1. A task that is not idempotent displays the changed status every time the task is run.

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

You can create idempotent tasks in several ways using the ansible.builtin.shell module, and sometimes making those changes and using ansible.builtin.shell is the best approach. But in this case, a better solution would be to use ansible-navigator doc to discover the ansible.builtin.copy module and use that to get the desired effect.

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

- name: Idempotent approach with copy module
  ansible.builtin.copy:
    dest: /etc/resolv.conf
    content: "nameserver 192.0.2.1\n"

The ansible.builtin.copy module tests to see if the state has already been met, and if so, it makes no changes. The ansible.builtin.shell module allows a lot of flexibility, but also requires more attention to ensure that it runs with idempotency.

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

YAML Syntax

The last part of this section investigates some variations of YAML or Ansible Playbook syntax that you might encounter.

YAML Comments

Comments can also be used to aid readability. In YAML, everything to the right of the number sign (#) is a comment. If there is content to the left of the comment, precede the hash with a space.

# This is a YAML comment
some data # This is also a YAML comment
YAML Strings

Strings in YAML do not normally need to be put in quotation marks even if the string contains no spaces. You can enclose strings in either double or single quotation marks.

this is a string
'this is another string'
"this is yet another a string"

You can write multiline strings in either of two ways. You can use the vertical bar (|) character to denote that newline characters within the string are to be preserved. (keep the original format of sentence, not single sentence once folded.)

include_newlines: |
        Example Company
        123 Main Street
        Atlanta, GA 30303

You can also write multiline strings using the greater-than (>) character to indicate that newline characters are to be converted to spaces and that leading white spaces in the lines are to be removed. This method is often used to break long strings at space characters so that they can span multiple lines for better readability. (break down a single long sentence into pieces)

fold_newlines: >
        This is an example
        of a long string,
        that will become
        a single sentence once folded.
YAML Dictionaries

You have seen collections of key-value pairs written as an indented block, as follows:

  name: svcrole
  svcservice: httpd
  svcport: 80

Dictionaries can also be written in an inline block format enclosed in braces, as follows:

  {name: svcrole, svcservice: httpd, svcport: 80}

Avoid the inline block format because it is harder to read. However, there is at least one situation in which it is more commonly used. The use of roles is discussed later in this course. When a playbook includes a list of roles, it is more common to use this syntax to make it easier to distinguish roles included in a play from the variables being passed to a role.

YAML Lists

You have also seen lists written with the normal single-dash syntax:

  hosts:
    - servera
    - serverb
    - serverc

Lists also have an inline format enclosed in square braces, as follows:

hosts: [servera, serverb, serverc]

You should avoid this syntax because it is usually harder to read.

REFERENCES

Intro to playbooks — Ansible Documentation

Working with playbooks — Ansible Documentation

Module Maintenance & Support — Ansible Documentation

Adding modules and plugins locally — Ansible Documentation

YAML Syntax — Ansible Documentation

Ansible.Builtin — Ansible Documentation

Chapter 2 TEST

The /home/student/playbook-review working directory has been created on the workstation machine for the Ansible project. The directory has already been populated with an ansible.cfg configuration file and an inventory file. The managed host, serverb.lab.example.com, is already defined in this inventory file.

Instructions

  1. Change into the /home/student/playbook-review directory and create a new playbook called internet.yml. Add the necessary entries to start a first play named Enable internet services and specify its intended managed host, serverb.lab.example.com. Add the necessary entry to enable privilege escalation, and one to start a task list.

  2. Add the necessary entries to the /home/student/playbook-review/internet.yml file to define a task that installs the latest versions of the firewalld, httpd, mariadb-server, php, and php-mysqlnd packages. Indent the beginning of the entry four spaces.

  3. Add the necessary entries to the /home/student/playbook-review/internet.yml file to define the firewall configuration tasks. They should ensure that the firewalld service is enabled and running, and that access is allowed to the http service. Indent the beginning of these entries four spaces.

  4. Add the necessary entries to ensure the httpd and mariadb services are enabled and running. Indent the beginning of these entries four spaces.

  5. Add the necessary entry that uses the ansible.builtin.copy module to copy the /home/student/playbook-review/index.php file to the /var/www/html/ directory on the managed host. Ensure the file mode is set to 0644. Indent the beginning of these entries four spaces.

  6. Define another play in the /home/student/playbook-review/internet.yml file for a task to be performed on the control node. This play tests access to the web server that should be running on the serverb.lab.example.com managed host. This play does not require privilege escalation, and runs on the workstation.lab.example.com managed host.

  7. Add the necessary entry that tests the web service running on serverb from the control node using the ansible.builtin.uri module. Look for a return status code of 200. Indent the beginning of the entry four spaces.

    internet.yml:

    ---
    - name: Enable internet services
      hosts: serverb.lab.example.com
      become: true
    
      tasks:
        - name: Install latest packages for APPs
          ansible.builtin.dnf:
            name:
              - firewalld
              - httpd
              - mariadb-server
              - php
              - php-mysqlnd
            state: latest
    
        - name: Firewall configuration tasks(running)
          ansible.builtin.service:
            name: firewalld
            state: started
            enabled: true
    
        - name: Enable access to httpd
          ansible.posix.firewalld:
            service: http
            permanent: true
            state: enabled
            immediate: true
    
        - name: Ensure httpd running
          ansible.builtin.service:
            name: httpd
            state: started
            enabled: true
    
        - name: Ensure mariadb running
          ansible.builtin.service:
            name: mariadb
            state: started
            enabled: true
    
    
        - name: Copy index.html to /var/www/html folder
          ansible.builtin.copy:
            src: /home/student/playbook-review/index.php
            dest: /var/www/html
            mode: 0644
    
    - name: Access the internet from workstation to serverb
      hosts: workstation
      become: false
      
      tasks:
        - name: Connect to serverb web
          ansible.builtin.uri:
            url: http://serverb.lab.example.com
            return_content: true
            status_code: 200
    
    
    
  8. Validate the syntax of the internet.yml playbook.

    [student@workstation playbook-review]$ ansible-navigator run \
    > -m stdout internet.yml --syntax-check
    playbook: /home/student/playbook-review/internet.yml
    
  9. Use the ansible-navigator run command to run the playbook. Read through the generated output to ensure that all tasks completed successfully.

    [student@workstation playbook-review]$ ansible-navigator run -m stdout internet.yml
    
    PLAY [Enable internet services] ************************************************
    
    TASK [Gathering Facts] *********************************************************
    ok: [serverb.lab.example.com]
    
    TASK [Install latest packages for APPs] ****************************************
    ok: [serverb.lab.example.com]
    
    TASK [Firewall configuration tasks(running)] ***********************************
    ok: [serverb.lab.example.com]
    
    TASK [Enable access to httpd] **************************************************
    ok: [serverb.lab.example.com]
    
    TASK [Ensure httpd running] ****************************************************
    changed: [serverb.lab.example.com]
    
    TASK [Ensure mariadb running] **************************************************
    changed: [serverb.lab.example.com]
    
    TASK [Copy index.html to /var/www/html folder] *********************************
    changed: [serverb.lab.example.com]
    
    PLAY [Access the internet from workstation to serverb] *************************
    
    TASK [Gathering Facts] *********************************************************
    ok: [workstation]
    
    TASK [Connect to serverb web] **************************************************
    ok: [workstation]
    
    PLAY RECAP *********************************************************************
    serverb.lab.example.com    : ok=7    changed=5    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    workstation                : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    

TO BE CONTINUED…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值