mirror of
https://github.com/GoodOlClint/PSProxmoxVE.git
synced 2026-08-13 15:46:52 +00:00
226f9d8a12
Terraform state was stored in the container's working directory (fresh checkout), so it was lost between CI jobs. The cleanup job couldn't destroy resources because it had no state. Now stores state at /opt/pve-integration/work/terraform.tfstate via -state flag on all terraform commands. This persists across the provision → test → cleanup job chain in GitHub Actions. Also: - Force cleanup now removes state from both local and shared paths - Added -reconfigure to terraform init (avoids backend mismatch errors) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
233 lines
8.5 KiB
YAML
233 lines
8.5 KiB
YAML
name: Integration Tests
|
|
|
|
# Real integration tests against a live Proxmox VE instance.
|
|
#
|
|
# Architecture:
|
|
# build → GitHub-hosted, dotnet publish → upload artifact
|
|
# container-image → GitHub-hosted, build+push Docker image to GHCR
|
|
# provision → self-hosted, provisions ALL nested PVE VMs via run-integration.sh
|
|
# test → self-hosted, runs Pester tests via run-integration.sh
|
|
# cleanup → self-hosted, tears down all VMs via run-integration.sh (always runs)
|
|
# cleanup-images → GitHub-hosted, prunes old GHCR container images
|
|
#
|
|
# The provision/test/cleanup logic lives in tests/infrastructure/scripts/run-integration.sh
|
|
# which is the single source of truth shared between CI and local dev containers.
|
|
#
|
|
# Required repository secrets (for provisioning):
|
|
# PVE_ENDPOINT - Parent PVE API URL (e.g. https://pve.example.com:8006)
|
|
# PVE_API_TOKEN - Parent PVE API token (for Terraform + uploads)
|
|
# PVE_TEST_PASSWORD - Root password for nested PVE instances (used for both provision and tests)
|
|
#
|
|
# Required repository variables:
|
|
# PVE_TARGET_NODE - Parent PVE node name (variable, not secret, to avoid log masking)
|
|
#
|
|
# Optional secrets (for skip_provision mode):
|
|
# PVETEST_HOST - Hostname or IP of a pre-existing nested PVE
|
|
#
|
|
# WARNING: Integration tests create and destroy real resources on the target
|
|
# node. Never run against production.
|
|
|
|
concurrency:
|
|
group: integration-tests
|
|
cancel-in-progress: false
|
|
|
|
on:
|
|
push:
|
|
branches: [ main ]
|
|
# NOTE: pull_request trigger intentionally removed. Integration tests
|
|
# run on a self-hosted runner with access to secrets and a live PVE
|
|
# node. Fork PRs must not execute code on that runner. Integration
|
|
# tests run automatically on push to main after merge.
|
|
workflow_dispatch:
|
|
inputs:
|
|
skip_provision:
|
|
description: 'Skip provisioning (use existing PVE from PVETEST_HOST secret)'
|
|
required: false
|
|
type: boolean
|
|
default: false
|
|
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
|
|
env:
|
|
SCRIPTS_DIR: tests/infrastructure/scripts
|
|
TEST_IMAGE: ghcr.io/goodolclint/psproxmoxve-integration
|
|
CACHE_DIR: /opt/pve-integration
|
|
|
|
jobs:
|
|
# ── Build module artifact (GitHub-hosted) ────────────────────────────
|
|
build:
|
|
if: github.actor != 'dependabot[bot]'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- name: Setup .NET
|
|
uses: actions/setup-dotnet@v5
|
|
with:
|
|
dotnet-version: '10.0.x'
|
|
|
|
- name: Build module
|
|
run: dotnet publish src/PSProxmoxVE/PSProxmoxVE.csproj --configuration Release --framework netstandard2.0 --output ./publish/netstandard2.0
|
|
|
|
- name: Clean publish output
|
|
run: rm -f ./publish/netstandard2.0/*.deps.json
|
|
|
|
- name: Upload module artifact
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: module-integration
|
|
path: ./publish/netstandard2.0/
|
|
|
|
# ── Build test container image (GitHub-hosted) ───────────────────────
|
|
container-image:
|
|
if: github.actor != 'dependabot[bot]'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 20
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- name: Log in to GHCR
|
|
uses: docker/login-action@v4
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Build and push
|
|
uses: docker/build-push-action@v7
|
|
with:
|
|
context: .
|
|
file: tests/Dockerfile.test
|
|
target: dev-infra
|
|
push: true
|
|
tags: ${{ env.TEST_IMAGE }}:${{ github.sha }},${{ env.TEST_IMAGE }}:latest
|
|
|
|
# ── Provision all nested PVE VMs + storage VM (self-hosted) ─────────
|
|
provision:
|
|
if: inputs.skip_provision != true
|
|
needs: [build, container-image]
|
|
runs-on: [self-hosted, proxmox, integration]
|
|
timeout-minutes: 45
|
|
container:
|
|
image: ghcr.io/goodolclint/psproxmoxve-integration:${{ github.sha }}
|
|
credentials:
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
volumes:
|
|
- /opt/pve-integration:/opt/pve-integration
|
|
# WARNING: The Docker socket is mounted to allow storage containers to be
|
|
# managed from within the job container. This grants root-equivalent access
|
|
# to the runner's Docker daemon. Only use on dedicated, isolated self-hosted
|
|
# runners — never on shared runners.
|
|
- /var/run/docker.sock:/var/run/docker.sock
|
|
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- name: Provision PVE instances
|
|
shell: bash
|
|
env:
|
|
PVE_ENDPOINT: ${{ secrets.PVE_ENDPOINT }}
|
|
PVE_API_TOKEN: ${{ secrets.PVE_API_TOKEN }}
|
|
PVE_TARGET_NODE: ${{ vars.PVE_TARGET_NODE }}
|
|
PVE_PASSWORD: ${{ secrets.PVE_TEST_PASSWORD }}
|
|
run: bash ${SCRIPTS_DIR}/run-integration.sh provision
|
|
|
|
# ── Integration tests (self-hosted, per PVE version) ────────────────
|
|
test:
|
|
needs: [build, provision]
|
|
runs-on: [self-hosted, proxmox, integration]
|
|
timeout-minutes: 20
|
|
container:
|
|
image: ghcr.io/goodolclint/psproxmoxve-integration:${{ github.sha }}
|
|
credentials:
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
volumes:
|
|
- /opt/pve-integration:/opt/pve-integration
|
|
strategy:
|
|
fail-fast: false
|
|
max-parallel: 2
|
|
matrix:
|
|
pve_version: ['9', '8']
|
|
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- name: Download module artifact
|
|
uses: actions/download-artifact@v8
|
|
with:
|
|
name: module-integration
|
|
path: ./publish/netstandard2.0/
|
|
|
|
- name: Run integration tests (PVE ${{ matrix.pve_version }})
|
|
shell: bash
|
|
env:
|
|
PVE_PASSWORD: ${{ secrets.PVE_TEST_PASSWORD }}
|
|
MODULE_ARTIFACT: ./publish/netstandard2.0
|
|
SKIP_PROVISION: ${{ inputs.skip_provision || 'false' }}
|
|
PVETEST_HOST: ${{ secrets.PVETEST_HOST }}
|
|
PVETEST_PASSWORD: ${{ secrets.PVE_TEST_PASSWORD }}
|
|
run: bash ${SCRIPTS_DIR}/run-integration.sh test ${{ matrix.pve_version }}
|
|
|
|
- name: Upload test results
|
|
if: always()
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: integration-test-results-pve${{ matrix.pve_version }}
|
|
path: TestResults/
|
|
|
|
# ── Cleanup: destroy all VMs (always runs) ──────────────────────────
|
|
cleanup:
|
|
needs: [provision, test]
|
|
if: always() && needs.provision.result != 'skipped' && github.actor != 'dependabot[bot]'
|
|
runs-on: [self-hosted, proxmox, integration]
|
|
timeout-minutes: 15
|
|
container:
|
|
image: ghcr.io/goodolclint/psproxmoxve-integration:${{ github.sha }}
|
|
credentials:
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
volumes:
|
|
- /opt/pve-integration:/opt/pve-integration
|
|
# WARNING: The Docker socket is mounted to allow storage containers to be
|
|
# stopped from within the job container. This grants root-equivalent access
|
|
# to the runner's Docker daemon. Only use on dedicated, isolated self-hosted
|
|
# runners — never on shared runners.
|
|
- /var/run/docker.sock:/var/run/docker.sock
|
|
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- name: Cleanup PVE instances
|
|
shell: bash
|
|
env:
|
|
PVE_ENDPOINT: ${{ secrets.PVE_ENDPOINT }}
|
|
PVE_API_TOKEN: ${{ secrets.PVE_API_TOKEN }}
|
|
PVE_TARGET_NODE: ${{ vars.PVE_TARGET_NODE }}
|
|
PVE_PASSWORD: ${{ secrets.PVE_TEST_PASSWORD }}
|
|
# Terraform state is stored on the shared mount (/opt/pve-integration/work/)
|
|
# so it persists between CI jobs.
|
|
run: bash ${SCRIPTS_DIR}/run-integration.sh cleanup
|
|
|
|
# ── Clean up old container images from GHCR ──────────────────────────
|
|
cleanup-images:
|
|
needs: test
|
|
if: always() && github.actor != 'dependabot[bot]'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
env:
|
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
|
steps:
|
|
- name: Delete old container image versions
|
|
uses: actions/delete-package-versions@v5
|
|
with:
|
|
package-name: psproxmoxve-integration
|
|
package-type: container
|
|
min-versions-to-keep: 3
|
|
delete-only-untagged-versions: false
|
|
token: ${{ secrets.GITHUB_TOKEN }}
|