# Assignment The Nautilus DevOps team wants to install and set up a simple httpd web server on all app servers in Stratos DC. Additionally, they want to deploy a sample web page for now using Ansible only. Therefore, write the required playbook to complete this task. Find more details about the task below. We already have an inventory file under /home/thor/ansible directory on jump host. Create a playbook.yml under /home/thor/ansible directory on jump host itself. Using the playbook, install httpd web server on all app servers. Additionally, make sure its service should up and running. Using blockinfile Ansible module add some content in /var/www/html/index.html file. Below is the content: Welcome to XfusionCorp! This is Nautilus sample file, created using Ansible! Please do not modify this file manually! The /var/www/html/index.html file's user and group owner should be apache on all app servers. The /var/www/html/index.html file's permissions should be 0777 on all app servers. Note: i. Validation will try to run the playbook using command ansible-playbook -i inventory playbook.yml so please make sure the playbook works this way without passing any extra arguments. ii. Do not use any custom or empty marker for blockinfile module. # Solution # Ansible Playbook — install httpd + deploy sample page on all App Servers Create `/home/thor/ansible/playbook.yml` so `ansible-playbook -i inventory playbook.yml` installs httpd, starts it, and writes a sample `index.html` with specific ownership and permissions — with **no extra arguments**. > Note: this is an Ansible task, not Kubernetes — no manifests to pipe into `kubectl`. The heredoc > below writes the playbook. ## Step 0 — The inventory already exists; leave it alone The task states an inventory is already present. **Do not recreate or overwrite it** — just confirm what's in it: ```bash cat /home/thor/ansible/inventory ``` Check that it lists the app servers with their connection variables. If it lacks `ansible_become_pass` and the app-server users require a sudo password, add that per host — the playbook needs privilege escalation and you can't pass `-K` at runtime. ## Step 1 — Playbook ```bash cat > /home/thor/ansible/playbook.yml <<'EOF' --- - name: Install httpd and deploy sample web page hosts: all become: yes tasks: - name: Install httpd package ansible.builtin.yum: name: httpd state: present - name: Start and enable httpd service ansible.builtin.service: name: httpd state: started enabled: yes - name: Add sample content to index.html ansible.builtin.blockinfile: path: /var/www/html/index.html create: yes block: | Welcome to XfusionCorp! This is Nautilus sample file, created using Ansible! Please do not modify this file manually! owner: apache group: apache mode: '0777' EOF ``` ## How it works ### Why `become: yes` Every task here is privileged: installing a package writes to system directories and the RPM database, managing a systemd service requires root, and `/var/www/html/` is root-owned. The SSH users are unprivileged, so the whole play escalates with `become: yes` at the play level rather than repeating it per task. Since validation runs the bare command with no `-K`, the sudo password must come from `ansible_become_pass` in the **existing** inventory. If the play fails with "Missing sudo password," that variable is what's missing. ### Task 1 — install httpd `ansible.builtin.yum` with **`state: present`** installs the package if absent and does nothing otherwise, making it idempotent (`changed` on first run, `ok` after). `state: latest` would upgrade on every run, which isn't what's asked. ### Task 2 — service up and running `ansible.builtin.service` handles both halves of the requirement: - **`state: started`** — ensures httpd is running **right now**. - **`enabled: yes`** — ensures it starts automatically **on boot**. These are independent settings; "up and running" is satisfied by `started`, and `enabled` makes it durable across reboots. Including both is the standard, complete answer. ### Task 3 — `blockinfile` with default markers `blockinfile` inserts (or updates) a **block** of text delimited by marker comments, so the block can be managed idempotently on re-runs — Ansible finds its own markers and replaces the content between them rather than appending duplicates. - **No `marker:` parameter is specified**, per note (ii). Omitting it uses the default, `# {mark} ANSIBLE MANAGED BLOCK`, which produces `# BEGIN ANSIBLE MANAGED BLOCK` and `# END ANSIBLE MANAGED BLOCK` around your text. Supplying a custom or empty marker would violate the requirement — and an empty marker would break idempotency, since Ansible could no longer locate its block. - **`create: yes`** — creates `/var/www/html/index.html` if it doesn't exist. A fresh httpd install typically has no `index.html`, and without this flag `blockinfile` would fail with "Destination does not exist." - **`block: |`** — the literal block scalar preserves the text **exactly**, including line breaks. Note the double space in `This is Nautilus sample file` — that's reproduced verbatim from the requirement, since validation may compare the content character for character. - **`owner: apache` / `group: apache`** — the required ownership. `apache` is the user httpd runs as on RHEL/CentOS-family systems, and the account exists only **after** the httpd package is installed — which is why the install task must come first. Reordering would fail with "chown failed: failed to look up user apache." - **`mode: '0777'`** — quoted so YAML parses it as a string. Unquoted octal (`0777`) is a classic misparse that silently yields the wrong permissions. ### Ordering matters The three tasks form a dependency chain: **install** creates the `apache` user and `/var/www/html/`; **service** brings httpd up; **blockinfile** then writes into a directory that exists and assigns ownership to a user that exists. Ansible runs tasks top to bottom, so this order is the correctness requirement, not just style. ### `hosts: all` The inventory holds the app servers, so `all` targets exactly them and can't break if the group name and the playbook's `hosts:` value drift apart. ## Verify ```bash cd /home/thor/ansible # Connectivity first ansible -i inventory all -m ping # The actual validation command ansible-playbook -i inventory playbook.yml # httpd installed and running ansible -i inventory all -b -m command -a "systemctl is-active httpd" # File content, ownership, and permissions ansible -i inventory all -b -m command -a "ls -l /var/www/html/index.html" ansible -i inventory all -b -m command -a "cat /var/www/html/index.html" ``` Expected — the playbook finishing with `failed=0`; `systemctl is-active httpd` returning `active` on each server; `ls -l` showing `-rwxrwxrwx` with `apache apache`; and `cat` showing the three lines wrapped in `# BEGIN ANSIBLE MANAGED BLOCK` / `# END ANSIBLE MANAGED BLOCK`. > Those BEGIN/END marker lines are **expected and correct** — they're the default markers required by > note (ii). A "failed to look up user apache" error means the blockinfile task ran before httpd was > installed. "Missing sudo password" means the inventory needs `ansible_become_pass`.