Artifacts: dsci@007aefe.1789617896. File: answer.md


artifacts

## 📁 File structure ``` . ├── jobs.yaml # pipeline definition (only jobs list) └── ansible_job/ # one DSCI job ├── config.yaml # default job parameters (can be overridden) ├── job.bash # job script – orchestrates the tasks └── tasks/ ├── install_ansible/ │ └── task.bash # installs Ansible in the execution container/host └── run_playbook/ └── task.bash # runs the supplied Ansible playbook on the remote host ``` --- ## 🗂️ `jobs.yaml` – pipeline definition Only the list of jobs (and optional input parameters) is placed here – **no logic**. ```yaml # jobs.yaml jobs: - id: ansible_job path: ansible_job/ # optional – override any defaults from ansible_job/config.yaml #params: # remote_user: root # inventory_path: ./inventory.ini # playbook_path: ./site.yml # extra_vars: "env=prod version=1.2.3" ``` --- ## ⚙️ `ansible_job/config.yaml` – default job parameters These values are used when the pipeline does **not** provide a `params:` block for the job. Any key can be overridden from `jobs.yaml` (or by the CI system when the pipeline is launched). ```yaml # ansible_job/config.yaml remote_user: ubuntu # SSH user that Ansible will use inventory_path: ./inventory.ini # Path to the Ansible inventory file (relative to the job dir) playbook_path: ./site.yml # Path to the main playbook (relative to the job dir) extra_vars: "" # Optional extra‑vars string (e.g. "env=prod version=1.2") ``` --- ## 🏁 `ansible_job/job.bash` – job entry point The job only orchestrates tasks. All “real” work lives in the tasks below. ```bash # ansible_job/job.bash #!/usr/bin/env bash set -euo pipefail # ------------------------------------------------------------------------- # 1️⃣ Install Ansible (if it is not already available) # ------------------------------------------------------------------------- run_task install_ansible # ------------------------------------------------------------------------- # 2️⃣ Execute the supplied playbook # ------------------------------------------------------------------------- run_task run_playbook \ playbook "$(config playbook_path)" \ inventory "$(config inventory_path)" \ extra_vars "$(config extra_vars)" ``` > **Explanation** > * `$(config )` reads a job‑parameter (default or overridden). > * `run_task [NAME VALUE …]` launches a task and forwards the > variables that the task can later read with `$(task_var )`. --- ## 🔧 `ansible_job/tasks/install_ansible/task.bash` – make sure Ansible exists ```bash # ansible_job/tasks/install_ansible/task.bash #!/usr/bin/env bash set -euo pipefail echo "🔧 Checking if Ansible is installed …" if command -v ansible-playbook >/dev/null 2>&1; then echo "✅ Ansible already available." exit 0 fi echo "⚙️ Ansible not found – installing now." # Try the most common package managers (apt, yum, dnf, apk) if command -v apt-get >/dev/null 2>&1; then apt-get update && apt-get install -y --no-install-recommends ansible elif command -v yum >/dev/null 2>&1; then yum install -y epel-release && yum install -y ansible elif command -v dnf >/dev/null 2>&1; then dnf install -y ansible elif command -v apk >/dev/null 2>&1; then apk add --no-cache ansible else echo "❌ No known package manager – please install Ansible manually." exit 1 fi echo "✅ Ansible installation finished." ``` --- ## 🚀 `ansible_job/tasks/run_playbook/task.bash` – run the playbook on the remote host ```bash # ansible_job/tasks/run_playbook/task.bash #!/usr/bin/env bash set -euo pipefail # ------------------------------------------------------------------------- # Pull variables that were passed from the job # ------------------------------------------------------------------------- playbook=$(task_var playbook) inventory=$(task_var inventory) extra_vars=$(task_var extra_vars) # ------------------------------------------------------------------------- # Prepare a log file inside the shared artifacts directory # ------------------------------------------------------------------------- log_file="${HOME}/artifacts/ansible_run.log" mkdir -p "$(dirname "$log_file")" echo "▶️ Running Ansible playbook" echo " Playbook : $playbook" echo " Inventory: $inventory" [ -n "$extra_vars" ] && echo " Extra‑vars: $extra_vars" # ------------------------------------------------------------------------- # Execute ansible‑playbook, tee output to the log file # ------------------------------------------------------------------------- if [ -n "$extra_vars" ]; then ansible-playbook -i "$inventory" "$playbook" --extra-vars "$extra_vars" | tee "$log_file" else ansible-playbook -i "$inventory" "$playbook" | tee "$log_file" fi rc=$? # ------------------------------------------------------------------------- # Export a small state for downstream jobs (if any) # ------------------------------------------------------------------------- if [ $rc -eq 0 ]; then echo "✅ Playbook completed successfully." update_state '{ "ansible_status": "success", "log_path": "'"$log_file"'" }' else echo "❌ Playbook failed (exit code $rc)." update_state '{ "ansible_status": "failed", "log_path": "'"$log_file"'", "exit_code": '"$rc"' }' fi exit $rc ``` > **What this task does** > 1. Retrieves the variables supplied by the job (`playbook`, `inventory`, `extra_vars`). > 2. Runs `ansible-playbook` and captures the full console output in `~/artifacts/ansible_run.log`. > 3. Emits a **state** (`ansible_status`, `log_path`, optional `exit_code`) that any later job can read via `config()`. --- ## 📦 Sharing results with another job (optional) If you add a second job after `ansible_job` you can read the state like this: ```yaml # jobs.yaml (add a second job) jobs: - id: ansible_job path: ansible_job/ - id: report_job path: report_job/ ``` `report_job/job.bash` (example): ```bash #!/usr/bin/env bash set -euo pipefail # Pull the state that the previous job stored under its id ansible_status=$(config | jq -r '._dsci_.ansible_job.ansible_status') log_path=$(config | jq -r '._dsci_.ansible_job.log_path') echo "🔎 Ansible job finished with status: $ansible_status" echo "🗒️ Log file is available at: $log_path" # (You could, for instance, send the log somewhere, post a comment, etc.) ``` --- ## ✅ How it works – the DSCI flow in a nutshell | Layer | What you write | |------|----------------| | **Pipeline (YAML)** | `jobs.yaml` – only a list of jobs (`id` + `path` + optional `params`). | | **Job** | `job.bash` – sequentially calls `run_task …`. | | **Task** | Real Bash logic (`task.bash`). Uses `$(task_var …)` for variables, `$(config …)` for job‑wide parameters, `update_state …` to share data, and writes any files to `~/artifacts/` for cross‑job sharing. | | **State / Artifacts** | `update_state` → accessible to later jobs via `config`. Files in `~/artifacts/` survive across jobs. | No third‑party actions, no complex YAML matrices – just a tiny `jobs.yaml` and normal Bash scripts. --- ### 🎉 Ready to run! Place the directory layout exactly as shown, commit the files, and let DSCI execute the pipeline. The job will: 1. Ensure Ansible is present. 2. Run the supplied playbook against the remote host(s) defined in `inventory.ini`. 3. Store the full console output in `~/artifacts/ansible_run.log`. 4. Export a concise state (`ansible_status`, `log_path`, `exit_code`) for any downstream job to consume.