200 lines
7.5 KiB
Markdown
200 lines
7.5 KiB
Markdown
# Assignment
|
|
|
|
The Nautilus DevOps team want to install and set up a simple httpd web server on all app servers in Stratos DC. They also want to deploy a sample web page using Ansible. Therefore, write the required playbook to complete this task as per details mentioned below.
|
|
|
|
|
|
We already have an inventory file under /home/thor/ansible directory on jump host. Write a playbook playbook.yml under /home/thor/ansible directory on jump host itself. Using the playbook perform below given tasks:
|
|
|
|
|
|
Install httpd web server on all app servers, and make sure its service is up and running.
|
|
|
|
|
|
Create a file /var/www/html/index.html with content:
|
|
|
|
|
|
This is a Nautilus sample file, created using Ansible!
|
|
|
|
|
|
Using lineinfile Ansible module add some more content in /var/www/html/index.html file. Below is the content:
|
|
|
|
Welcome to Nautilus Group!
|
|
|
|
|
|
Also make sure this new line is added at the top of the file.
|
|
|
|
|
|
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 0655 on all app servers.
|
|
|
|
|
|
Note: 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.
|
|
|
|
# Solution
|
|
|
|
# Ansible Playbook — httpd + sample page with `lineinfile`
|
|
|
|
Create `/home/thor/ansible/playbook.yml` so `ansible-playbook -i inventory playbook.yml` installs
|
|
httpd, starts it, and builds an `index.html` with a line prepended at the top — 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
|
|
|
|
```bash
|
|
cat /home/thor/ansible/inventory
|
|
```
|
|
|
|
Confirm it lists the app servers with their connection variables, and that
|
|
`ansible_become_pass` is present — the play needs root and you can't pass `-K`.
|
|
|
|
## 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: Create index.html with sample content
|
|
ansible.builtin.copy:
|
|
dest: /var/www/html/index.html
|
|
content: |
|
|
This is a Nautilus sample file, created using Ansible!
|
|
owner: apache
|
|
group: apache
|
|
mode: '0655'
|
|
|
|
- name: Add welcome line at the top of index.html
|
|
ansible.builtin.lineinfile:
|
|
path: /var/www/html/index.html
|
|
line: 'Welcome to Nautilus Group!'
|
|
insertbefore: BOF
|
|
owner: apache
|
|
group: apache
|
|
mode: '0655'
|
|
EOF
|
|
```
|
|
|
|
Resulting file content:
|
|
|
|
```
|
|
Welcome to Nautilus Group!
|
|
This is a Nautilus sample file, created using Ansible!
|
|
```
|
|
|
|
## How it works
|
|
|
|
### Task order is a hard dependency
|
|
|
|
The four tasks must run in this sequence:
|
|
|
|
1. **Install httpd** — this creates the `apache` user *and* the `/var/www/html/` directory. Both are
|
|
needed by later tasks.
|
|
2. **Start/enable the service** — httpd must exist before it can be managed.
|
|
3. **Create the file** — the directory now exists and `apache` is a valid owner.
|
|
4. **Prepend the line** — the file must exist before `lineinfile` can modify it.
|
|
|
|
Reordering breaks things concretely: a `copy` before the install fails with "Destination directory
|
|
does not exist" or "failed to look up user apache"; a `lineinfile` before the `copy` has nothing to
|
|
insert into.
|
|
|
|
### Task 1 & 2 — install and run
|
|
|
|
- **`yum` with `state: present`** — installs if missing, no-ops otherwise (idempotent: `changed`
|
|
first run, `ok` after). `state: latest` would upgrade on every run, which isn't what's asked.
|
|
- **`service` with `state: started` *and* `enabled: yes`** — two independent settings.
|
|
`started` = running now; `enabled` = starts on boot. "Up and running" needs `started`; `enabled`
|
|
makes it survive reboots. Both are standard for this requirement.
|
|
|
|
### Task 3 — `copy` with inline `content`
|
|
|
|
Using `copy` with the **`content:`** parameter writes a literal string to `dest` — no source file on
|
|
the controller needed. The `|` block scalar preserves the text exactly and appends a trailing
|
|
newline, so the next task's line lands cleanly above it.
|
|
|
|
(`copy` also accepts `src:` for pushing an existing file; `content:` is the right choice when the
|
|
text is defined inline, as here.)
|
|
|
|
### Task 4 — `lineinfile` with `insertbefore: BOF`
|
|
|
|
This is the crux of requirement 3. `lineinfile` ensures a **single line** is present in a file:
|
|
|
|
- **`line: 'Welcome to Nautilus Group!'`** — the exact text to guarantee.
|
|
- **`insertbefore: BOF`** — `BOF` is a special value meaning **Beginning Of File**. It places the
|
|
line as the very first line, which is precisely "added at the top." Without it, `lineinfile`
|
|
appends to the end by default — the file would still contain both lines, but in the wrong order,
|
|
and validation would fail.
|
|
|
|
(The mirror value is `insertafter: EOF` for the end of the file.)
|
|
|
|
`lineinfile` is also **idempotent**: on re-runs it finds the line already present and reports `ok`
|
|
rather than inserting a duplicate.
|
|
|
|
### `copy` vs `lineinfile` — why both
|
|
|
|
They do different jobs. `copy` establishes the file's whole content from scratch (requirement 2);
|
|
`lineinfile` surgically inserts one line into an existing file (requirement 3). The task explicitly
|
|
asks for `lineinfile` for the second piece, so this two-step approach matches the requirements
|
|
directly rather than just writing both lines in one `copy`.
|
|
|
|
### Ownership and permissions
|
|
|
|
- **`owner: apache` / `group: apache`** — the `apache` account exists only *after* the httpd package
|
|
is installed, which is why task 1 must come first.
|
|
- **`mode: '0655'`** — **quoted**. Unquoted octal like `0655` is a classic YAML misparse that
|
|
silently produces the wrong permissions. Note this is `0655`, not the more familiar `0644` or
|
|
`0755` — copy it exactly.
|
|
|
|
Both are set on the `copy` **and** the `lineinfile` task. Setting them on the final task is what
|
|
guarantees the end state, since `lineinfile` rewrites the file; specifying them on both makes the
|
|
result deterministic regardless of which task last touched the file.
|
|
|
|
### `become: yes`
|
|
|
|
Installing packages, managing systemd services, writing under root-owned `/var/www/html/`, and
|
|
running `chown` all require root. The play escalates once at play level, with the sudo password
|
|
coming from `ansible_become_pass` in the inventory.
|
|
|
|
## Verify
|
|
|
|
```bash
|
|
cd /home/thor/ansible
|
|
|
|
# Connectivity
|
|
ansible -i inventory all -m ping
|
|
|
|
# The actual validation command
|
|
ansible-playbook -i inventory playbook.yml
|
|
|
|
# Service running and enabled
|
|
ansible -i inventory all -b -m command -a "systemctl is-active httpd"
|
|
ansible -i inventory all -b -m command -a "systemctl is-enabled httpd"
|
|
|
|
# Content order, ownership, permissions
|
|
ansible -i inventory all -b -m command -a "cat /var/www/html/index.html"
|
|
ansible -i inventory all -b -m command -a "ls -l /var/www/html/index.html"
|
|
```
|
|
|
|
Expected — playbook `failed=0`; `is-active` → `active` and `is-enabled` → `enabled`; `cat` showing
|
|
**`Welcome to Nautilus Group!` on the first line** followed by the sample-file line; and `ls -l`
|
|
showing `-rw-r-xr-x` (0655) with `apache apache`.
|
|
|
|
> The line **order** is the thing to check most carefully — if the welcome line appears at the
|
|
> bottom, `insertbefore: BOF` is missing or misspelled. "failed to look up user apache" ⇒ a file task
|
|
> ran before the httpd install. |