# 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) ```bash 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 ```bash 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: ```bash 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 ```bash 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.