7.3 KiB
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:
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
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 BLOCKand# END ANSIBLE MANAGED BLOCKaround 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.htmlif it doesn't exist. A fresh httpd install typically has noindex.html, and without this flagblockinfilewould fail with "Destination does not exist." -
block: |— the literal block scalar preserves the text exactly, including line breaks. Note the double space inThis 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.apacheis 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
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.