Chapter 6: Deploying Files to Managed Hosts

Exercise: Deploying files to managed hosts

The end-of-chapter lab combines both halves of the chapter: find the facts you need, build a template from them, deploy it, check it with stat, copy a second file beside it and link a third. Solutions are hidden under each task. Try each one yourself first.

The project ~/file-review has an ansible.cfg, an inventory with one group, servers, that contains serverb.lab.example.com, and a login banner in files/issue.

Deploying files to managed hosts

  • Build a template file from host facts.
  • Deploy it, and other files and links, from one playbook.

Prerequisites: Complete control-node setup and the preceding lessons in this chapter. Run commands as student on workstation unless a step names another machine.

From the project directory, run the relevant home-lab check. For an exercise with several checkpoints, grade each state before changing or removing it:

lab grade file-review

The grader reads project files and host state. A passing report covers the listed checks; also perform the task’s independent connection, repeat-run, and reboot checks where requested.

Add the OS distribution to the login message. Predict which files and tasks should change.

Record the published result first. The grader checks the original requirements, so a changed name or value may intentionally fail those checks.

Provide a useful login message and consistent banner on the inventory hosts.

  • serverb_facts.yml must expose the facts needed to identify memory and processor count.
  • templates/motd.j2, deployed by motd.yml, must show those host-specific values in root-owned /etc/motd with mode 0644.
  • Publish files/issue as root-owned /etc/issue, mode 0644; /etc/issue.net must be a symbolic link to it, replacing the existing regular file.
  • Record the file metadata and confirm the login message. Banner display also depends on the SSH daemon's Banner setting.

Review the inventory

[student@workstation ~]$ cd ~/file-review
[student@workstation file-review]$ cat inventory
[servers]
serverb.lab.example.com

Find the facts for memory and processors

You need the names of the facts that hold serverb's total memory and its number of processors. Write a small playbook, serverb_facts.yml, that prints all of ansible_facts, run it, and find them.

---
- name: Display ansible_facts
  hosts: serverb.lab.example.com
  tasks:
    - name: Display facts
      ansible.builtin.debug:
        var: ansible_facts
[student@workstation file-review]$ ansible-navigator run -m stdout serverb_facts.yml
...output omitted...
        "memtotal_mb": 960,
...output omitted...
        "processor_count": 1,
...output omitted...

The facts are ansible_facts['memtotal_mb'] and ansible_facts['processor_count']. Your numbers depend on how the VM is sized.

Write the message-of-the-day template

Create the directory templates and, in it, motd.j2. When devops logs in to serverb, the message should show the system's total memory and processor count.

System total memory: {{ ansible_facts['memtotal_mb'] }} MiB.
System processor count: {{ ansible_facts['processor_count'] }}

Start the playbook

Create motd.yml with one play for all hosts in the inventory. It logs in as devops and uses privilege escalation for the whole play.

---
- name: Configure system
  hosts: all
  remote_user: devops
  become: true
  tasks:

Deploy the template

Add a task that deploys templates/motd.j2 to /etc/motd, owned by root:root, mode 0644.

    - name: Configure a custom /etc/motd
      ansible.builtin.template:
        src: templates/motd.j2
        dest: /etc/motd
        owner: root
        group: root
        mode: 0644

Check the file with stat

Add a task that uses ansible.builtin.stat to verify that /etc/motd exists and registers the result, then a task that prints the registered variable.

    - name: Check file exists
      ansible.builtin.stat:
        path: /etc/motd
      register: motd

    - name: Display stat results
      ansible.builtin.debug:
        var: motd

Copy the login banner

Add a task that copies files/issue to /etc/issue, with the same owner, group and mode as /etc/motd.

    - name: Copy custom /etc/issue file
      ansible.builtin.copy:
        src: files/issue
        dest: /etc/issue
        owner: root
        group: root
        mode: 0644

Link /etc/issue.net to /etc/issue

Add a task that makes /etc/issue.net a symbolic link to /etc/issue. /etc/issue.net already exists as a regular file, so the link has to replace it.

    - name: Ensure /etc/issue.net is a symlink to /etc/issue
      ansible.builtin.file:
        src: /etc/issue
        dest: /etc/issue.net
        state: link
        owner: root
        group: root
        force: true

force: true lets the module replace the existing regular file with the link.

Check the syntax and run

[student@workstation file-review]$ ansible-navigator run \
> -m stdout motd.yml --syntax-check
playbook: /home/student/file-review/motd.yml
[student@workstation file-review]$ ansible-navigator run -m stdout motd.yml
...output omitted...
TASK [Configure a custom /etc/motd] ********************************************
changed: [serverb.lab.example.com]

TASK [Check file exists] *******************************************************
ok: [serverb.lab.example.com]

TASK [Display stat results] ****************************************************
ok: [serverb.lab.example.com] => {
    "motd": {
        "changed": false,
        "failed": false,
...output omitted...

TASK [Copy custom /etc/issue file] *********************************************
changed: [serverb.lab.example.com]

TASK [Ensure /etc/issue.net is a symlink to /etc/issue] ************************
changed: [serverb.lab.example.com]

PLAY RECAP *********************************************************************
serverb.lab.example.com    : ok=6    changed=3    unreachable=0    failed=0  ...

Confirm the result

Log in to serverb as devops. You should see the banner from /etc/issue before the login completes, and the message of the day after it.

[student@workstation file-review]$ ssh devops@serverb.lab.example.com
------------------------------- PRIVATE SYSTEM -----------------------------
*   Access to this computer system is restricted to authorised users only. *
*                                                                          *
*      Customer information is confidential and must not be disclosed.     *
----------------------------------------------------------------------------
System total memory: 960 MiB.
System processor count: 1
...output omitted...
[devops@serverb ~]$ ls -l /etc/issue.net
lrwxrwxrwx. 1 root root 10 ... /etc/issue.net -> /etc/issue
[devops@serverb ~]$ logout

With key-based login, sshd prints /etc/issue.net only if its Banner option points at it, which the default configuration does not. You always see the message of the day; check the banner file with cat /etc/issue and the link with ls -l /etc/issue.net.

Grade and finish

Check your work with lab grade file-review, then put the exercise away with lab finish file-review.

---
- name: Configure system
  hosts: all
  remote_user: devops
  become: true
  tasks:
    - name: Configure a custom /etc/motd
      ansible.builtin.template:
        src: templates/motd.j2
        dest: /etc/motd
        owner: root
        group: root
        mode: 0644

    - name: Check file exists
      ansible.builtin.stat:
        path: /etc/motd
      register: motd

    - name: Display stat results
      ansible.builtin.debug:
        var: motd

    - name: Copy custom /etc/issue file
      ansible.builtin.copy:
        src: files/issue
        dest: /etc/issue
        owner: root
        group: root
        mode: 0644

    - name: Ensure /etc/issue.net is a symlink to /etc/issue
      ansible.builtin.file:
        src: /etc/issue
        dest: /etc/issue.net
        state: link
        owner: root
        group: root
        force: true