Skip to content

CI/CD Integration

Overview

Solti-Monitoring roles include GitHub Actions workflows for automated testing on every commit and pull request.

GitHub Actions Workflows

Lint Workflow

Purpose: Check YAML, Markdown, and Ansible syntax

Trigger: Push to main/dev, pull requests Duration: ~2 minutes

# .github/workflows/lint.yml
name: Lint

on:
  push:
    branches: [main, dev]
  pull_request:

jobs:
  yaml-lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: YAML Lint
        uses: ibiqlik/action-yamllint@v3

  markdown-lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Markdown Lint
        uses: nosborn/github-action-markdown-cli@v3

  ansible-lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Ansible Lint
        uses: ansible/ansible-lint-action@v6

Molecule CI Workflow

Purpose: Full molecule testing with multiple platforms

Trigger: Pull requests to main Duration: ~10 minutes Platforms: Debian 12, Rocky 9, Ubuntu 24

# .github/workflows/ci.yml
name: Molecule CI

on:
  pull_request:
    branches: [main]

jobs:
  molecule:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        distro:
          - debian:12
          - rockylinux:9
          - ubuntu:24.04
      fail-fast: false

    steps:
      - uses: actions/checkout@v3

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.x'

      - name: Install dependencies
        run: |
          pip install molecule molecule-plugins[podman]
          pip install ansible-core ansible-lint

      - name: Run Molecule
        run: molecule test -s github
        env:
          MOLECULE_DISTRO: ${{ matrix.distro }}
          PY_COLORS: '1'
          ANSIBLE_FORCE_COLOR: '1'

Super-Linter Workflow

Purpose: Comprehensive validation of all file types

Trigger: Push to dev branch only Duration: ~5 minutes

# .github/workflows/superlinter.yml
name: Super-Linter

on:
  push:
    branches: [dev]

jobs:
  super-lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Lint Code Base
        uses: github/super-linter@v5
        env:
          VALIDATE_ALL_CODEBASE: true
          DEFAULT_BRANCH: main
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          VALIDATE_YAML: true
          VALIDATE_ANSIBLE: true
          VALIDATE_MARKDOWN: true
          VALIDATE_BASH: true
          VALIDATE_PYTHON: true

Workflow Strategy

Branch Protection

main (protected)
  ├─ Requires: lint + molecule pass
  ├─ Requires: 1 approval
  └─ No direct push

dev (lightly protected)
  ├─ Runs: lint + superlinter
  └─ Direct push allowed

Workflow Triggers

On Push: - main branch: lint only (fast feedback) - dev branch: lint + superlinter

On Pull Request: - To main: lint + molecule (full validation) - To dev: lint only

Manual: - workflow_dispatch enabled for all workflows

Testing Strategy

Fast Feedback Loop

Developer pushes to dev
  └─> Lint runs (~2 min)
      └─> Quick syntax check

Developer creates PR to main
  └─> Lint + Molecule run (~12 min)
      └─> Full platform testing

Matrix Testing

Test each role across multiple platforms:

strategy:
  matrix:
    role:
      - influxdb
      - loki
      - telegraf
      - alloy
    distro:
      - debian:12
      - rockylinux:9
      - ubuntu:24.04
  fail-fast: false  # Test all combinations

Optimization Techniques

Caching

Python Dependencies:

- name: Cache Python packages
  uses: actions/cache@v3
  with:
    path: ~/.cache/pip
    key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}

Molecule Cache:

- name: Cache Molecule
  uses: actions/cache@v3
  with:
    path: ~/.cache/molecule
    key: ${{ runner.os }}-molecule-${{ hashFiles('**/molecule.yml') }}

Conditional Jobs

jobs:
  molecule:
    # Only run on actual code changes
    if: |
      contains(github.event.head_commit.message, 'feat:') ||
      contains(github.event.head_commit.message, 'fix:')

Parallel Execution

jobs:
  lint:
    # Runs independently
  molecule:
    # Runs in parallel with lint
  super-lint:
    # Only after lint passes
    needs: lint

Local CI Simulation

Pre-commit Hooks

Simulate CI locally before pushing:

# .git/hooks/pre-commit
#!/bin/bash
set -e

echo "Running local CI checks..."

# Lint
yamllint .
ansible-lint

# Quick molecule test
molecule test -s default --destroy=never

echo "✅ All checks passed"

Act (GitHub Actions Locally)

# Install act
brew install act  # macOS
# or download from github.com/nektos/act

# Run workflows locally
act push
act pull_request
act -j molecule

Secrets Management

Required Secrets

None for basic testing, but optional for advanced features:

# .github/workflows/deploy.yml
env:
  ANSIBLE_VAULT_PASSWORD: ${{ secrets.VAULT_PASSWORD }}
  PROXMOX_API_TOKEN: ${{ secrets.PROXMOX_TOKEN }}

Setting Secrets

# Via GitHub UI
Settings  Secrets  Actions  New repository secret

# Or via gh CLI
gh secret set VAULT_PASSWORD < ~/.secrets/vault_password

Status Badges

Add to README.md:

[![Lint](https://github.com/jackaltx/solti-monitoring/actions/workflows/lint.yml/badge.svg)](https://github.com/jackaltx/solti-monitoring/actions/workflows/lint.yml)

[![Molecule](https://github.com/jackaltx/solti-monitoring/actions/workflows/ci.yml/badge.svg)](https://github.com/jackaltx/solti-monitoring/actions/workflows/ci.yml)

Debugging Workflows

Enable Debug Logging

env:
  ACTIONS_STEP_DEBUG: true
  ACTIONS_RUNNER_DEBUG: true

View Logs

# Via gh CLI
gh run list
gh run view RUN_ID
gh run view RUN_ID --log

Re-run Failed Jobs

# Via gh CLI
gh run rerun RUN_ID

# Or in GitHub UI
Actions  Select run  Re-run failed jobs

Advanced Workflows

Scheduled Testing

# Test weekly even without changes
on:
  schedule:
    - cron: '0 2 * * 0'  # Sunday 2 AM

Deploy on Release

on:
  release:
    types: [published]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Publish to Ansible Galaxy
        run: ansible-galaxy collection publish

Notification Integration

- name: Notify Slack on Failure
  if: failure()
  uses: 8398a7/action-slack@v3
  with:
    status: ${{ job.status }}
    webhook_url: ${{ secrets.SLACK_WEBHOOK }}

GitLab CI Integration

For GitLab instead of GitHub:

# .gitlab-ci.yml
stages:
  - lint
  - test

lint:
  stage: lint
  image: python:3.11
  script:
    - pip install ansible-lint yamllint
    - yamllint .
    - ansible-lint

molecule:
  stage: test
  image: python:3.11
  services:
    - docker:dind
  variables:
    DOCKER_DRIVER: overlay2
  script:
    - pip install molecule molecule-plugins[docker]
    - molecule test
  only:
    - merge_requests
    - main

Best Practices

1. Test What You Deploy

CI tests should mirror production: - Same OS versions - Same configuration - Same deployment method

2. Fast Feedback First

Run quick tests first:

jobs:
  lint:       # 2 minutes
  syntax:     # 3 minutes
  molecule:   # 10 minutes, runs after lint
    needs: [lint, syntax]

3. Fail Fast When Appropriate

strategy:
  fail-fast: true  # Stop on first failure for lint
  fail-fast: false # Continue for molecule (test all platforms)

4. Cache Aggressively

Cache everything that doesn't change often: - Python packages - Ansible collections - Container images

5. Meaningful Commit Messages

Trigger conditional workflows based on commits:

feat: add influxdb clustering    # Triggers full test
docs: update README              # Skips expensive tests

Troubleshooting CI

Common Issues

Issue: Molecule timeout

# Increase timeout
timeout-minutes: 30  # Default is 360

Issue: Container pull rate limits

# Use GitHub container registry
image: ghcr.io/username/debian:12

Issue: Flaky tests

# Retry failed tests
- uses: nick-invision/retry@v2
  with:
    timeout_minutes: 10
    max_attempts: 3
    command: molecule test

Next Steps

  • Verification Tasks: Writing effective tests for CI
  • Operations: Production deployment workflows
  • Testing Framework: Complete testing documentation