Prerequisite Check Examples¶
Real-world implementations of prerequisite validation patterns.
Production-Ready Code
These examples are extracted from production systems and demonstrate the check-then-execute pattern across different environments.
Kubernetes Deployment Prerequisites¶
#!/bin/bash
set -euo pipefail
check_prerequisites() {
local namespace="$1"
local errors=()
echo "Checking prerequisites for deployment to $namespace..."
# Tool checks
command -v kubectl >/dev/null 2>&1 || errors+=("kubectl not found")
command -v helm >/dev/null 2>&1 || errors+=("helm not found")
command -v jq >/dev/null 2>&1 || errors+=("jq not found")
# Access checks
kubectl auth can-i create deployments -n "$namespace" >/dev/null 2>&1 \
|| errors+=("No permission to create deployments in $namespace")
kubectl auth can-i create services -n "$namespace" >/dev/null 2>&1 \
|| errors+=("No permission to create services in $namespace")
# State checks
kubectl get namespace "$namespace" >/dev/null 2>&1 \
|| errors+=("Namespace $namespace does not exist")
# Resource checks
local available_memory
available_memory=$(kubectl top nodes --no-headers | awk '{sum+=$4} END {print sum}')
[[ "$available_memory" -gt 1000 ]] \
|| errors+=("Insufficient cluster memory: ${available_memory}Mi available")
# Report results
if [[ ${#errors[@]} -gt 0 ]]; then
echo "Prerequisites failed:"
printf ' - %s\n' "${errors[@]}"
return 1
fi
echo "All prerequisites passed"
return 0
}
# Gate: all prerequisites must pass before proceeding
check_prerequisites "$NAMESPACE" || exit 1
# Execution phase: safe to proceed
helm upgrade --install myapp ./chart -n "$NAMESPACE"
GitHub Actions Prerequisite Job¶
jobs:
prerequisites:
runs-on: ubuntu-latest
outputs:
ready: ${{ steps.check.outputs.ready }}
steps:
- uses: actions/checkout@v4
- name: Check prerequisites
id: check
run: |
errors=()
# Check required secrets
[ -n "${{ secrets.DEPLOY_KEY }}" ] || errors+=("DEPLOY_KEY secret not set")
[ -n "${{ secrets.REGISTRY_TOKEN }}" ] || errors+=("REGISTRY_TOKEN secret not set")
# Check required files
[ -f "Dockerfile" ] || errors+=("Dockerfile not found")
[ -f "k8s/deployment.yaml" ] || errors+=("k8s/deployment.yaml not found")
# Check configuration
if [ -f ".env.example" ] && [ ! -f ".env" ]; then
errors+=(".env file missing (copy from .env.example)")
fi
# Report
if [ ${#errors[@]} -gt 0 ]; then
echo "## Prerequisites Failed" >> "$GITHUB_STEP_SUMMARY"
for error in "${errors[@]}"; do
echo "- $error" >> "$GITHUB_STEP_SUMMARY"
done
echo "ready=false" >> "$GITHUB_OUTPUT"
exit 1
fi
echo "## Prerequisites Passed" >> "$GITHUB_STEP_SUMMARY"
echo "ready=true" >> "$GITHUB_OUTPUT"
deploy:
needs: prerequisites
if: needs.prerequisites.outputs.ready == 'true'
runs-on: ubuntu-latest
steps:
- name: Deploy
run: ./deploy.sh
Go Prerequisite Validation¶
type DeploymentPrerequisites struct {
KubeconfigPath string
Namespace string
ImageTag string
DryRun bool
}
type PrerequisiteError struct {
Category string
Message string
}
func (p *DeploymentPrerequisites) Validate() []PrerequisiteError {
var errors []PrerequisiteError
// Configuration checks
if p.Namespace == "" {
errors = append(errors, PrerequisiteError{
Category: "config",
Message: "namespace is required",
})
}
if p.ImageTag == "" {
errors = append(errors, PrerequisiteError{
Category: "config",
Message: "image tag is required",
})
}
// Tool checks
if _, err := exec.LookPath("kubectl"); err != nil {
errors = append(errors, PrerequisiteError{
Category: "tools",
Message: "kubectl not found in PATH",
})
}
// Access checks (skip if dry run)
if !p.DryRun {
if err := checkKubeAccess(p.KubeconfigPath, p.Namespace); err != nil {
errors = append(errors, PrerequisiteError{
Category: "access",
Message: fmt.Sprintf("kubernetes access check failed: %v", err),
})
}
}
// State checks
if !p.DryRun {
if !namespaceExists(p.Namespace) {
errors = append(errors, PrerequisiteError{
Category: "state",
Message: fmt.Sprintf("namespace %s does not exist", p.Namespace),
})
}
}
return errors
}
func Deploy(prereqs *DeploymentPrerequisites) error {
// Gate: validate all prerequisites
if errors := prereqs.Validate(); len(errors) > 0 {
return fmt.Errorf("prerequisites failed: %v", errors)
}
// Execution: safe to proceed
return executeDeployment(prereqs)
}
Database Migration Prerequisites¶
func CheckMigrationPrerequisites(db *sql.DB, targetVersion int) error {
checks := []struct {
name string
check func() error
}{
{
name: "database connection",
check: func() error {
return db.Ping()
},
},
{
name: "migration lock available",
check: func() error {
locked, err := isMigrationLocked(db)
if err != nil {
return err
}
if locked {
return errors.New("another migration is in progress")
}
return nil
},
},
{
name: "current version known",
check: func() error {
_, err := getCurrentVersion(db)
return err
},
},
{
name: "migration files exist",
check: func() error {
current, _ := getCurrentVersion(db)
for v := current + 1; v <= targetVersion; v++ {
if !migrationFileExists(v) {
return fmt.Errorf("migration file for version %d not found", v)
}
}
return nil
},
},
{
name: "backup exists",
check: func() error {
if !backupExistsForToday() {
return errors.New("no backup found for today - run backup first")
}
return nil
},
},
}
for _, c := range checks {
if err := c.check(); err != nil {
return fmt.Errorf("prerequisite '%s' failed: %w", c.name, err)
}
}
return nil
}