Drill 05: Infrastructure

Real-world YAML: antora configs, CI pipelines, container orchestration.

Run This Drill

bash ~/atelier/_bibliotheca/domus-captures/docs/modules/ROOT/examples/yq-drills/05-infrastructure.sh

Drill Script

#!/bin/bash
# YQ DRILL 05: INFRASTRUCTURE PATTERNS
# Paste this entire script into your terminal
# Topics: antora.yml, GitHub Actions, docker-compose

# Simulated GitHub Actions workflow
cat << 'EOF' > /tmp/yq-gha.yaml
name: CI
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: "20"
      - name: Install
        run: npm ci
      - name: Build
        run: npm run build
  test:
    runs-on: ubuntu-latest
    needs: build
    steps:
      - uses: actions/checkout@v4
      - name: Run tests
        run: npm test
EOF

# Simulated docker-compose
cat << 'EOF' > /tmp/yq-compose.yaml
version: "3.8"
services:
  wazuh-manager:
    image: wazuh/wazuh-manager:4.7.0
    ports:
      - "1514:1514"
      - "1515:1515"
      - "55000:55000"
    environment:
      WAZUH_MANAGER_IP: 10.50.1.70
    volumes:
      - wazuh-data:/var/ossec/data
    restart: always
  wazuh-indexer:
    image: wazuh/wazuh-indexer:4.7.0
    ports:
      - "9200:9200"
    environment:
      OPENSEARCH_JAVA_OPTS: "-Xms512m -Xmx512m"
    volumes:
      - indexer-data:/var/lib/wazuh-indexer
    restart: always
  grafana:
    image: grafana/grafana:10.2.0
    ports:
      - "3000:3000"
    restart: unless-stopped
volumes:
  wazuh-data:
  indexer-data:
EOF

echo "=================================================================="
echo "             YQ DRILL 05: INFRASTRUCTURE                          "
echo "=================================================================="
echo ""

# ---------------------------------------------------------------------------
echo "------------------------------------------------------------------"
echo "DRILL 5.1: GITHUB ACTIONS — LIST JOBS"
echo "------------------------------------------------------------------"
echo ""
echo "Command: yq '.jobs | keys' /tmp/yq-gha.yaml"
yq '.jobs | keys' /tmp/yq-gha.yaml
echo ""

# ---------------------------------------------------------------------------
echo "------------------------------------------------------------------"
echo "DRILL 5.2: GITHUB ACTIONS — GET ALL USES"
echo "------------------------------------------------------------------"
echo ""
echo "Command: yq '.jobs[].steps[].uses | select(. != null)' /tmp/yq-gha.yaml"
yq '.jobs[].steps[].uses | select(. != null)' /tmp/yq-gha.yaml
echo ""

# ---------------------------------------------------------------------------
echo "------------------------------------------------------------------"
echo "DRILL 5.3: GITHUB ACTIONS — FIND RUN COMMANDS"
echo "------------------------------------------------------------------"
echo ""
echo "Command: yq '.jobs[].steps[] | select(has(\"run\")) | .run' /tmp/yq-gha.yaml"
yq '.jobs[].steps[] | select(has("run")) | .run' /tmp/yq-gha.yaml
echo ""

# ---------------------------------------------------------------------------
echo "------------------------------------------------------------------"
echo "DRILL 5.4: DOCKER-COMPOSE — LIST SERVICES"
echo "------------------------------------------------------------------"
echo ""
echo "Command: yq '.services | keys' /tmp/yq-compose.yaml"
yq '.services | keys' /tmp/yq-compose.yaml
echo ""

# ---------------------------------------------------------------------------
echo "------------------------------------------------------------------"
echo "DRILL 5.5: DOCKER-COMPOSE — ALL PORTS"
echo "------------------------------------------------------------------"
echo ""
echo "Command: yq '.services[].ports[]' /tmp/yq-compose.yaml"
yq '.services[].ports[]' /tmp/yq-compose.yaml
echo ""

# ---------------------------------------------------------------------------
echo "------------------------------------------------------------------"
echo "DRILL 5.6: DOCKER-COMPOSE — FILTER BY RESTART"
echo "------------------------------------------------------------------"
echo ""
echo "Command: yq '.services | to_entries[] | select(.value.restart == \"always\") | .key' /tmp/yq-compose.yaml"
yq '.services | to_entries[] | select(.value.restart == "always") | .key' /tmp/yq-compose.yaml
echo ""

# ---------------------------------------------------------------------------
echo "------------------------------------------------------------------"
echo "DRILL 5.7: DOCKER-COMPOSE — UPDATE IMAGE TAG"
echo "------------------------------------------------------------------"
echo ""
echo "Command: yq '.services.grafana.image = \"grafana/grafana:11.0.0\"' /tmp/yq-compose.yaml | yq '.services.grafana.image'"
yq '.services.grafana.image = "grafana/grafana:11.0.0"' /tmp/yq-compose.yaml | yq '.services.grafana.image'
echo ""

# ---------------------------------------------------------------------------
echo "------------------------------------------------------------------"
echo "DRILL 5.8: CROSS-FORMAT — YAML TO TSV"
echo "------------------------------------------------------------------"
echo ""
echo "Command: yq -o=json '...' /tmp/yq-compose.yaml | jq -r '...' | column -t"
yq -o=json '.services | to_entries | map({name: .key, image: .value.image, restart: .value.restart})' /tmp/yq-compose.yaml |
  jq -r '.[] | [.name, .image, .restart] | @tsv' |
  column -t
echo ""

# ---------------------------------------------------------------------------
echo "------------------------------------------------------------------"
echo "DRILL 5.9: REAL REPOS — ANTORA ATTRIBUTES"
echo "Run this if you have domus-captures cloned"
echo "------------------------------------------------------------------"
echo ""
ANTORA="$HOME/atelier/_bibliotheca/domus-captures/docs/asciidoc/antora.yml"
if [[ -f "$ANTORA" ]]; then
    echo "Command: yq '.asciidoc.attributes | keys' $ANTORA"
    yq '.asciidoc.attributes | keys' "$ANTORA" | head -15
    echo "  ... (truncated)"
    echo ""
    echo "Command: Extract IPs via yq→jq pipeline"
    yq -o=json '.asciidoc.attributes' "$ANTORA" |
      jq -r 'to_entries[] | select(.value | tostring | test("[0-9]+\\.[0-9]+\\.[0-9]+")) | "\(.key): \(.value)"' |
      head -10
    echo ""
else
    echo "(Skipped — domus-captures not found at expected path)"
    echo ""
fi

# ---------------------------------------------------------------------------
echo "------------------------------------------------------------------"
echo "YOUR TURN - TRY THESE:"
echo "------------------------------------------------------------------"
echo ""
echo "1. Add a lint step to the GH Actions build job:"
echo "   yq '.jobs.build.steps += [{\"name\": \"Lint\", \"run\": \"npm run lint\"}]' /tmp/yq-gha.yaml"
echo ""
echo "2. Add a new service to docker-compose:"
echo "   yq -i '.services.nginx = {\"image\": \"nginx:alpine\", \"ports\": [\"80:80\"]}' /tmp/yq-compose.yaml"
echo ""
echo "3. Compare antora.yml attribute counts across your repos:"
echo "   for f in ~/atelier/_bibliotheca/domus-*/docs/asciidoc/antora.yml; do"
echo "     repo=\$(basename \"\$(dirname \"\$(dirname \"\$(dirname \"\$f\")\")\")\")"
echo "     count=\$(yq '.asciidoc.attributes | length // 0' \"\$f\")"
echo "     printf \"%-30s %s\\n\" \"\$repo\" \"\$count\""
echo "   done"
echo ""
echo "------------------------------------------------------------------"
echo "KEY TAKEAWAYS:"
echo "1. yq reads GH Actions, docker-compose, k8s natively"
echo "2. .jobs[].steps[] iterates all steps across jobs"
echo "3. to_entries[] on services gives {key: name, value: config}"
echo "4. yq -o=json | jq is the power pipeline"
echo "5. Always preview without -i first, then apply"
echo "------------------------------------------------------------------"