172 lines
7.3 KiB
Markdown
172 lines
7.3 KiB
Markdown
# 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`. |