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_passis harmless and simply unused. Including it covers both cases.
The two tasks
-
ansible.builtin.filewithstate: directory— guarantees/opt/dbaexists before the copy. Thecopymodule won't create missing parent directories, so if/opt/dbaweren'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 (reportsokwhen the directory already exists). -
ansible.builtin.copy— transfers the file:src: /usr/src/dba/index.html— a path on the control node (the jump host). Thecopymodule 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 needremote_src: yes— not the case here.)dest: /opt/dba/index.html— the explicit target path. Writing the filename out is clearer than relying ondest: /opt/dba/directory-expansion behavior.mode: '0644'— quoted so YAML treats it as a string; unquoted octal like0644is 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.
UNREACHABLEmeans a hostname didn't resolve or credentials don't match the wiki. "Missing sudo password" meansansible_become_passis absent or wrong for that host. Permission denied on the copy meansbecome: yesdidn't take effect.