Files

6.4 KiB

Assignment

The Nautilus DevOps team needs to copy data from the jump host to all application servers in Stratos DC using Ansible. Execute the task with the following details:

a. Create an inventory file /home/thor/ansible/inventory on jump_host and add all application servers as managed nodes.

b. Create a playbook /home/thor/ansible/playbook.yml on the jump host to copy the /usr/src/dba/index.html file to all application servers, placing it at /opt/dba.

Note: Validation will run the playbook using the command ansible-playbook -i inventory playbook.yml. Ensure the playbook functions properly without any extra arguments.

Solution

Ansible Inventory + Playbook — copy index.html to all App Servers

Set up the jump host so ansible-playbook -i inventory playbook.yml copies /usr/src/dba/index.html to /opt/dba on all three Stratos DC application servers — 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 > /home/thor/ansible/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 > /home/thor/ansible/playbook.yml <<'EOF'
---
- name: Copy index.html to all application servers
  hosts: all
  become: yes
  tasks:
    - name: Ensure /opt/dba exists
      ansible.builtin.file:
        path: /opt/dba
        state: directory
        mode: '0755'

    - name: Copy index.html to /opt/dba
      ansible.builtin.copy:
        src: /usr/src/dba/index.html
        dest: /opt/dba/index.html
        mode: '0644'
EOF

How it works

The inventory — all three managed nodes

Each app server in Stratos DC gets its own line under the [app_servers] group, keyed by the server name from the wiki (stapp01, stapp02, stapp03). Those names resolve from the jump host, so the inventory name doubles as the connection target — no ansible_host needed. Confirm with getent hosts stapp01 if you want certainty.

Variable Purpose
ansible_user SSH username, different per server.
ansible_ssh_pass SSH password (these servers use password auth, not keys).
ansible_become_pass The sudo password, needed because the playbook uses become: yes.
ansible_connection Transport plugin — set once for the whole group via [app_servers:vars].

Verify every credential against your lab's wiki. The user/password pairs shown follow the common Stratos DC pattern, but treat them as values to confirm rather than facts.

The [app_servers:vars] block sets ansible_connection once for all members instead of repeating it on every line — the same result, less duplication.

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

Why become: yes is required here

/opt/dba is root-owned. The SSH users (tony, steve, banner) can't write there directly, so the play escalates to root with become: yes. That in turn means sudo may demand a password — which is why ansible_become_pass is set per host in the inventory. Without it, the run would hang or fail with "Missing sudo password," and you can't pass -K because no extra arguments are allowed.

If your lab's app-server users have passwordless sudo, ansible_become_pass is harmless and simply unused. Including it covers both cases.

The two tasks

  1. ansible.builtin.file with state: directory — guarantees /opt/dba exists before the copy. The copy module won't create missing parent directories, so if /opt/dba weren't already present the copy would fail with "Destination directory does not exist." This task makes the playbook robust either way, and it's idempotent (reports ok when the directory already exists).

  2. ansible.builtin.copy — transfers the file:

    • src: /usr/src/dba/index.html — a path on the control node (the jump host). The copy module reads from the controller by default; that's exactly what "copy data from the jump host" means here. (Copying between two paths on the remote machine would instead need remote_src: yes — not the case here.)
    • dest: /opt/dba/index.html — the explicit target path. Writing the filename out is clearer than relying on dest: /opt/dba/ directory-expansion behavior.
    • mode: '0644' — quoted so YAML treats it as a string; unquoted octal like 0644 is a classic misparse.

Why hosts: all

The inventory contains only the three app servers, so all targets exactly them — and it can't break if the group name and the playbook's hosts: value ever drift apart. Using hosts: app_servers also works given this inventory; all is simply the more failure-proof choice.

Host key checking

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

cat > /home/thor/ansible/ansible.cfg <<'EOF'
[defaults]
host_key_checking = False
EOF

sshpass must also be installed on the jump host for password auth; it usually is, and Ansible's error names it explicitly if not.

Verify

cd /home/thor/ansible

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

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

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

# Confirm the file landed on all three
ansible -i inventory all -b -m command -a "ls -l /opt/dba/index.html"

Expected — ping returning SUCCESS/pong for stapp01, stapp02, and stapp03; the playbook finishing with failed=0 for all three hosts; and the final check listing /opt/dba/index.html on each server.

UNREACHABLE means a hostname didn't resolve or credentials don't match the wiki. "Missing sudo password" means ansible_become_pass is absent or wrong for that host. Permission denied on the copy means become: yes didn't take effect.