docs: add 100 Days of DevOps challenge notes
This commit is contained in:
147
100 - days of devops/devops-83.md
Normal file
147
100 - days of devops/devops-83.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# Assignment
|
||||
|
||||
An Ansible playbook needs completion on the jump host, where a team member left off. Below are the details:
|
||||
|
||||
|
||||
|
||||
The inventory file /home/thor/ansible/inventory requires adjustments. The playbook must run on App Server 3 in Stratos DC. Update the inventory accordingly.
|
||||
|
||||
|
||||
Create a playbook /home/thor/ansible/playbook.yml. Include a task to create an empty file /tmp/file.txt on App Server 3.
|
||||
|
||||
|
||||
Note: Validation will run the playbook using the command ansible-playbook -i inventory playbook.yml. Ensure the playbook works without any additional arguments.
|
||||
|
||||
# Solution
|
||||
|
||||
# Ansible Inventory + Playbook — create `/tmp/file.txt` on App Server 3
|
||||
|
||||
Complete the setup on the jump host so `ansible-playbook -i inventory playbook.yml` runs against
|
||||
`stapp03` and creates an empty file — 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 0 — See what's already there
|
||||
|
||||
The inventory "requires adjustments," so inspect it before overwriting:
|
||||
|
||||
```bash
|
||||
cat /home/thor/ansible/inventory
|
||||
```
|
||||
|
||||
Note any existing hostnames/groups — if the playbook or validation expects a particular group name,
|
||||
keep it. Otherwise the version below replaces it cleanly.
|
||||
|
||||
## Step 1 — Inventory
|
||||
|
||||
```bash
|
||||
cat > /home/thor/ansible/inventory <<'EOF'
|
||||
[app_servers]
|
||||
stapp03 ansible_user=banner ansible_ssh_pass=BigGr33n ansible_connection=ssh
|
||||
EOF
|
||||
```
|
||||
|
||||
## Step 2 — Playbook
|
||||
|
||||
```bash
|
||||
cat > /home/thor/ansible/playbook.yml <<'EOF'
|
||||
---
|
||||
- name: Create an empty file on App Server 3
|
||||
hosts: all
|
||||
tasks:
|
||||
- name: Create /tmp/file.txt
|
||||
ansible.builtin.file:
|
||||
path: /tmp/file.txt
|
||||
state: touch
|
||||
mode: '0644'
|
||||
EOF
|
||||
```
|
||||
|
||||
## How it works
|
||||
|
||||
### The inventory
|
||||
|
||||
- **Hostname `stapp03`** — App Server 3's server name per the wiki. It's resolvable from the jump
|
||||
host, so the inventory name doubles as the connection target; **no `ansible_host` is needed**.
|
||||
Confirm with `getent hosts stapp03` if you want to be sure.
|
||||
- **`ansible_user` / `ansible_ssh_pass`** — the SSH credentials. These servers use password auth, so
|
||||
both are required. **Verify the values against your lab's wiki** — the ones shown follow the
|
||||
common Stratos DC pattern but should be confirmed, not assumed.
|
||||
- **`ansible_connection=ssh`** — the transport plugin; the default for remote hosts, stated
|
||||
explicitly.
|
||||
|
||||
Because validation runs the bare command (no `-u`, `-k`, or `--private-key`), **every** connection
|
||||
detail must live in the inventory file itself.
|
||||
|
||||
### The playbook
|
||||
|
||||
- **`hosts: all`** — deliberately chosen over `hosts: stapp03`. Since the inventory contains only
|
||||
App Server 3, `all` targets exactly that host, and it stays correct regardless of what the group is
|
||||
named. Using a specific name risks a "no hosts matched" skip if the inventory group and the
|
||||
playbook's `hosts:` value ever drift apart.
|
||||
- **`ansible.builtin.file` with `state: touch`** — creates the file if absent, leaving it empty.
|
||||
This is the right module for "create an empty file"; `copy` with empty `content` would also work
|
||||
but `file`/`touch` expresses the intent directly.
|
||||
- **`mode: '0644'`** — standard read/write-owner, read-others permissions. Quoted so YAML treats it
|
||||
as a string, not an octal-looking integer (a classic gotcha: unquoted `0644` can be misparsed).
|
||||
- **No `become`** — `/tmp` is world-writable, so the SSH user can create the file without
|
||||
privilege escalation. Adding `become: yes` would invite a sudo-password prompt and could break the
|
||||
no-extra-arguments requirement.
|
||||
|
||||
### A note on idempotency
|
||||
|
||||
`state: touch` updates the file's timestamps on every run, so Ansible reports **changed** each
|
||||
time rather than **ok**. That's fine for this task. If you want true idempotency:
|
||||
|
||||
```yaml
|
||||
- name: Create /tmp/file.txt
|
||||
ansible.builtin.file:
|
||||
path: /tmp/file.txt
|
||||
state: touch
|
||||
mode: '0644'
|
||||
modification_time: preserve
|
||||
access_time: preserve
|
||||
```
|
||||
|
||||
This leaves timestamps alone when the file already exists, so re-runs report `ok`.
|
||||
|
||||
### Host key checking
|
||||
|
||||
A first-time SSH connection can fail on host-key verification. The safest fix — because it needs no
|
||||
extra command-line arguments 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 present on the jump host for `ansible_ssh_pass` to work. It's usually
|
||||
pre-installed; if not, Ansible's error names it explicitly.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
cd /home/thor/ansible
|
||||
|
||||
# Inventory parses
|
||||
ansible-inventory -i inventory --list
|
||||
|
||||
# Connectivity + credentials in one shot
|
||||
ansible -i inventory all -m ping
|
||||
|
||||
# The actual validation command
|
||||
ansible-playbook -i inventory playbook.yml
|
||||
|
||||
# Confirm the file exists on the target
|
||||
ansible -i inventory all -m command -a "ls -l /tmp/file.txt"
|
||||
```
|
||||
|
||||
Expected — ping returns `"ping": "pong"` with `SUCCESS`, the playbook completes with
|
||||
`ok=2 changed=1` and no failures, and the final check lists `/tmp/file.txt` on stapp03.
|
||||
|
||||
> `UNREACHABLE` means the hostname didn't resolve or the credentials don't match the wiki. A
|
||||
> `PLAY RECAP` showing `skipped` or "no hosts matched" means the playbook's `hosts:` value doesn't
|
||||
> align with the inventory — `hosts: all` avoids that class of failure.
|
||||
Reference in New Issue
Block a user