Files

6.5 KiB

Assignment

The Nautilus DevOps team is testing various Ansible modules on servers in Stratos DC. They're currently focusing on file creation on remote hosts using Ansible. Here are the details:

a. Create an inventory file ~/playbook/inventory on jump host and include all app servers.

b. Create a playbook ~/playbook/playbook.yml to create a blank file /opt/app.txt on all app servers.

c. Set the permissions of the /opt/app.txt file to 0755.

d. Ensure the user/group owner of the /opt/app.txt file is tony on app server 1, steve on app server 2 and banner on app server 3.

Note: Validation will execute the playbook using the command ansible-playbook -i inventory playbook.yml, so ensure the playbook functions correctly without any additional arguments.

Solution

Ansible Inventory + Playbook — create /opt/app.txt with per-host ownership

Set up the jump host so ansible-playbook -i inventory playbook.yml creates a blank /opt/app.txt on all three Stratos DC app servers, mode 0755, owned by a different user on each host — with no extra arguments.

Note: this is an Ansible task, not Kubernetes — no manifests to pipe into kubectl. The heredocs below write the two files.

Step 1 — Inventory (all three app servers)

cat > ~/playbook/inventory <<'EOF'
[app_servers]
stapp01 ansible_user=tony   ansible_ssh_pass=Ir0nM@n  ansible_become_pass=Ir0nM@n
stapp02 ansible_user=steve  ansible_ssh_pass=Am3ric@  ansible_become_pass=Am3ric@
stapp03 ansible_user=banner ansible_ssh_pass=BigGr33n ansible_become_pass=BigGr33n

[app_servers:vars]
ansible_connection=ssh
EOF

Step 2 — Playbook

cat > ~/playbook/playbook.yml <<'EOF'
---
- name: Create /opt/app.txt on all app servers
  hosts: all
  become: yes
  tasks:
    - name: Create blank file with correct mode and ownership
      ansible.builtin.file:
        path: /opt/app.txt
        state: touch
        mode: '0755'
        owner: "{{ ansible_user }}"
        group: "{{ ansible_user }}"
EOF

How it works

The neat trick: {{ ansible_user }} for per-host ownership

Requirement (d) wants a different owner per servertony on stapp01, steve on stapp02, banner on stapp03. Notice those are exactly the SSH users already defined per host in the inventory. So instead of writing three separate tasks with when: conditionals, the playbook references the variable:

owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"

Ansible evaluates ansible_user per host during the play, so it resolves to tony on stapp01, steve on stapp02, and banner on stapp03 automatically. One task, three correct outcomes — and it stays correct if a host is added or a username changes, since the inventory is the single source of truth.

group uses the same value because these systems create a matching primary group for each user (user tony → group tony), which is the Linux default. If your lab's groups differ, set group explicitly per host instead.

The alternative — hardcoding with conditionals — would look like this and is strictly worse:

# NOT recommended, shown for contrast
    - name: Set owner on stapp01
      ansible.builtin.file:
        path: /opt/app.txt
        owner: tony
      when: inventory_hostname == "stapp01"
    # ...repeated for each host

The inventory

Each app server is keyed by its wiki server name (stapp01, stapp02, stapp03), which resolves from the jump host — so the inventory name doubles as the connection target and no ansible_host is needed. Confirm with getent hosts stapp01 if you want certainty.

Variable Purpose
ansible_user SSH username — and the file owner, via the templating above.
ansible_ssh_pass SSH password (password auth, not keys).
ansible_become_pass Sudo password, needed because the play uses become: yes.
ansible_connection Transport plugin, set once for the group via [app_servers:vars].

Verify every credential against your lab's wiki. The pairs shown follow the common Stratos DC pattern but should be confirmed rather than assumed.

Since validation runs the bare command (no -u, -k, -K), all connection and escalation details must live in the inventory.

Why become: yes is required

/opt is root-owned, so the SSH users can't create a file there directly — the play escalates with become: yes. Escalation is also what makes owner:/group: work at all: changing a file's ownership requires root (chown is privileged). Without become, you'd get permission errors on both the create and the chown.

Because sudo may prompt for a password and you can't pass -K, ansible_become_pass is set per host in the inventory. (If the lab has passwordless sudo, the variable is simply unused — harmless either way.)

The file module options

  • state: touch — creates the file if absent, leaving it blank. Exactly "create a blank file."
  • mode: '0755' — quoted so YAML reads it as a string; unquoted octal like 0755 is a classic misparse that silently produces the wrong permissions.
  • owner / group — applied by the module after creation, which is why root privileges are needed.

Note state: touch bumps timestamps on every run, so re-runs report changed rather than ok. That's fine here; add modification_time: preserve and access_time: preserve if you want strict idempotency.

Host key checking

First-time SSH connections can fail on host-key verification. The safest fix — needing no extra command-line arguments — is an ansible.cfg beside the playbook:

cat > ~/playbook/ansible.cfg <<'EOF'
[defaults]
host_key_checking = False
EOF

sshpass must also be installed on the jump host for password auth.

Verify

cd ~/playbook

# All three hosts listed
ansible-inventory -i inventory --list

# Connectivity + credentials across every server
ansible -i inventory all -m ping

# The actual validation command
ansible-playbook -i inventory playbook.yml

# Confirm mode and per-host ownership
ansible -i inventory all -b -m command -a "ls -l /opt/app.txt"

Expected — ping returning SUCCESS for all three; the playbook finishing with failed=0; and the final listing showing -rwxr-xr-x with owner/group tony tony on stapp01, steve steve on stapp02, and banner banner on stapp03.

"Missing sudo password" ⇒ ansible_become_pass absent or wrong. A chown failure ⇒ become: yes didn't take. Wrong owner ⇒ check that ansible_user in the inventory matches the required owner for that host.