Skip to content

⚠️ Split Helm chart into operator and providers charts with optional dependency #17

⚠️ Split Helm chart into operator and providers charts with optional dependency

⚠️ Split Helm chart into operator and providers charts with optional dependency #17

Workflow file for this run

name: Smoke Test
on:
pull_request:
branches:
- main
- 'release-*'
push:
branches:
- main
workflow_dispatch:
permissions:
contents: read
jobs:
smoke-test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
- name: Install kubectl
run: |
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv kubectl /usr/local/bin/
- name: Install Helm
run: |
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
- name: Build Docker image
run: |
# Build the operator image with a specific tag for smoke test
CONTROLLER_IMG=cluster-api-operator TAG=smoke-test make docker-build
echo "Built image: cluster-api-operator-amd64:smoke-test"
# Tag the image for easier reference
docker tag cluster-api-operator-amd64:smoke-test cluster-api-operator:smoke-test
- name: Build charts
run: |
make release-chart
# Extract HELM_CHART_TAG from Makefile
HELM_CHART_TAG=$(make -s -f Makefile -p | grep '^HELM_CHART_TAG :=' | cut -d' ' -f3)
echo "HELM_CHART_TAG=$HELM_CHART_TAG" >> $GITHUB_ENV
echo "Detected HELM_CHART_TAG: $HELM_CHART_TAG"
- name: Create kind cluster
run: |
chmod +x ./hack/ensure-kind.sh
./hack/ensure-kind.sh
# Create kind cluster with Docker socket mount for CAPD
cat <<EOF > /tmp/kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraMounts:
- hostPath: /var/run/docker.sock
containerPath: /var/run/docker.sock
EOF
kind create cluster --name capi-operator-smoke-test --config /tmp/kind-config.yaml --wait 5m
kubectl cluster-info --context kind-capi-operator-smoke-test
- name: Load Docker image to kind
run: |
# Load the built image into kind cluster
kind load docker-image cluster-api-operator:smoke-test --name capi-operator-smoke-test
echo "Loaded image cluster-api-operator:smoke-test into kind cluster"
- name: Add Helm repositories
run: |
helm repo add jetstack https://charts.jetstack.io
helm repo update
- name: Install cert-manager
run: |
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--set installCRDs=true \
--wait \
--timeout 5m
- name: Install Cluster API Operator
run: |
# Use exact chart filename based on HELM_CHART_TAG
CHART_PACKAGE="out/package/cluster-api-operator-${HELM_CHART_TAG}.tgz"
echo "Using chart package: $CHART_PACKAGE"
# Verify the file exists
if [ ! -f "$CHART_PACKAGE" ]; then
echo "Error: Chart package not found: $CHART_PACKAGE"
ls -la out/package/
exit 1
fi
helm install capi-operator "$CHART_PACKAGE" \
--create-namespace \
-n capi-operator-system \
--set image.manager.repository=cluster-api-operator \
--set image.manager.tag=smoke-test \
--set image.manager.pullPolicy=IfNotPresent \
--wait \
--timeout 90s
- name: Wait for CAPI Operator to be ready
run: |
kubectl wait --for=condition=Available --timeout=300s -n capi-operator-system deployment/capi-operator-cluster-api-operator
- name: Deploy providers using cluster-api-operator-providers chart
run: |
# Create values file for providers
cat <<EOF > /tmp/providers-values.yaml
core:
cluster-api:
namespace: capi-system
bootstrap:
kubeadm:
namespace: capi-kubeadm-bootstrap-system
controlPlane:
kubeadm:
namespace: capi-kubeadm-control-plane-system
infrastructure:
docker:
namespace: capd-system
EOF
# Use exact providers chart filename based on HELM_CHART_TAG
PROVIDERS_CHART_PACKAGE="out/package/cluster-api-operator-providers-${HELM_CHART_TAG}.tgz"
echo "Using providers chart package: $PROVIDERS_CHART_PACKAGE"
# Verify the file exists
if [ ! -f "$PROVIDERS_CHART_PACKAGE" ]; then
echo "Error: Providers chart package not found: $PROVIDERS_CHART_PACKAGE"
ls -la out/package/
exit 1
fi
helm install capi-providers "$PROVIDERS_CHART_PACKAGE" \
-f /tmp/providers-values.yaml \
--wait \
--timeout 3m
- name: Wait for providers to be ready
run: |
echo "=== Waiting for Core Provider to be ready ==="
kubectl wait --for=condition=Ready --timeout=300s -n capi-system coreprovider/cluster-api || true
echo -e "\n=== Waiting for Bootstrap Provider to be ready ==="
kubectl wait --for=condition=Ready --timeout=300s -n capi-kubeadm-bootstrap-system bootstrapprovider/kubeadm || true
echo -e "\n=== Waiting for Control Plane Provider to be ready ==="
kubectl wait --for=condition=Ready --timeout=300s -n capi-kubeadm-control-plane-system controlplaneprovider/kubeadm || true
echo -e "\n=== Waiting for Infrastructure Provider to be ready ==="
kubectl wait --for=condition=Ready --timeout=300s -n capd-system infrastructureprovider/docker || true
# Additional wait for deployments
echo -e "\n=== Waiting for provider deployments ==="
kubectl wait --for=condition=Available --timeout=300s -n capi-system deployment/capi-controller-manager || true
kubectl wait --for=condition=Available --timeout=300s -n capi-kubeadm-bootstrap-system deployment/capi-kubeadm-bootstrap-controller-manager || true
kubectl wait --for=condition=Available --timeout=300s -n capi-kubeadm-control-plane-system deployment/capi-kubeadm-control-plane-controller-manager || true
kubectl wait --for=condition=Available --timeout=300s -n capd-system deployment/capd-controller-manager || true
# Wait for webhooks to be ready
echo -e "\n=== Waiting for webhook services ==="
kubectl wait --for=jsonpath='{.status.loadBalancer}' --timeout=300s -n capi-kubeadm-bootstrap-system service/capi-kubeadm-bootstrap-webhook-service || true
kubectl wait --for=jsonpath='{.status.loadBalancer}' --timeout=300s -n capi-kubeadm-control-plane-system service/capi-kubeadm-control-plane-webhook-service || true
- name: Verify installation
run: |
echo "=== Cluster API Operator Status ==="
kubectl get pods -n capi-operator-system
echo -e "\n=== Core Provider Status ==="
kubectl get coreprovider -A -o wide
kubectl describe coreprovider -n capi-system cluster-api || true
echo -e "\n=== Bootstrap Provider Status ==="
kubectl get bootstrapprovider -A -o wide
kubectl describe bootstrapprovider -n capi-kubeadm-bootstrap-system kubeadm || true
echo -e "\n=== Control Plane Provider Status ==="
kubectl get controlplaneprovider -A -o wide
kubectl describe controlplaneprovider -n capi-kubeadm-control-plane-system kubeadm || true
echo -e "\n=== Infrastructure Provider Status ==="
kubectl get infrastructureprovider -A -o wide
kubectl describe infrastructureprovider -n capd-system docker || true
echo -e "\n=== All Pods ==="
kubectl get pods -A | grep -E "(capi-|capd-)"
echo -e "\n=== Webhook Services ==="
kubectl get svc -A | grep webhook
echo -e "\n=== Webhook Certificates ==="
kubectl get certificate,certificaterequest -A | grep -E "(capi-|capd-)"
echo -e "\n=== CRDs ==="
kubectl get crds | grep -E "(cluster.x-k8s.io|operator.cluster.x-k8s.io)"
- name: Check provider health
run: |
# Check if core provider is ready
CORE_READY=$(kubectl get coreprovider -n capi-system cluster-api -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}')
if [ "$CORE_READY" != "True" ]; then
echo "Core provider is not ready"
kubectl get coreprovider -n capi-system cluster-api -o yaml
exit 1
fi
# Check if bootstrap provider is ready
BOOTSTRAP_READY=$(kubectl get bootstrapprovider -n capi-kubeadm-bootstrap-system kubeadm -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}')
if [ "$BOOTSTRAP_READY" != "True" ]; then
echo "Bootstrap provider is not ready"
kubectl get bootstrapprovider -n capi-kubeadm-bootstrap-system kubeadm -o yaml
exit 1
fi
# Check if control plane provider is ready
CONTROLPLANE_READY=$(kubectl get controlplaneprovider -n capi-kubeadm-control-plane-system kubeadm -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}')
if [ "$CONTROLPLANE_READY" != "True" ]; then
echo "Control plane provider is not ready"
kubectl get controlplaneprovider -n capi-kubeadm-control-plane-system kubeadm -o yaml
exit 1
fi
# Check if infrastructure provider is ready
INFRA_READY=$(kubectl get infrastructureprovider -n capd-system docker -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}')
if [ "$INFRA_READY" != "True" ]; then
echo "Infrastructure provider is not ready"
kubectl get infrastructureprovider -n capd-system docker -o yaml
exit 1
fi
echo "All providers are ready!"
# Additional webhook readiness check
echo -e "\n=== Checking webhook endpoints ==="
kubectl get endpoints -A | grep webhook
- name: Download cluster manifest
run: |
echo "=== Downloading cluster manifest ==="
curl -L https://raw.githubusercontent.com/kubernetes-sigs/cluster-api/refs/heads/main/test/infrastructure/docker/examples/simple-cluster.yaml -o simple-cluster.yaml
# Show the manifest for debugging
echo "=== Cluster manifest ==="
cat simple-cluster.yaml
- name: Create workload cluster
run: |
echo "=== Pre-creation diagnostics ==="
echo "Checking webhook services..."
kubectl get svc -A | grep webhook
echo -e "\nChecking webhook endpoints..."
kubectl get endpoints -A | grep webhook
echo -e "\nChecking webhook certificates..."
kubectl get secret -A | grep webhook-service-cert
echo -e "\n=== Creating workload cluster ==="
kubectl apply -f simple-cluster.yaml
echo -e "\n=== Cluster resources created ==="
kubectl get cluster,dockercluster,kubeadmcontrolplane,machinedeployment -A
- name: Wait for cluster to be ready
run: |
echo "=== Waiting for cluster to be provisioned ==="
kubectl wait --for=condition=Ready --timeout=600s cluster/capi-quickstart
echo "=== Waiting for control plane to be initialized ==="
kubectl wait --for=condition=Ready --timeout=600s kubeadmcontrolplane -l cluster.x-k8s.io/cluster-name=capi-quickstart
echo "=== Waiting for first control plane node ==="
kubectl wait --for=jsonpath='{.status.readyReplicas}'=1 --timeout=600s kubeadmcontrolplane -l cluster.x-k8s.io/cluster-name=capi-quickstart
echo "=== Cluster status ==="
kubectl get cluster capi-quickstart -o wide
kubectl get machines -l cluster.x-k8s.io/cluster-name=capi-quickstart
- name: Get workload cluster kubeconfig
run: |
echo "=== Getting workload cluster kubeconfig ==="
# For Docker provider, use kind to get kubeconfig
kind get kubeconfig --name capi-quickstart > capi-quickstart.kubeconfig
echo "=== Testing kubeconfig ==="
kubectl --kubeconfig=capi-quickstart.kubeconfig cluster-info
- name: Verify kubectl commands work on workload cluster
run: |
echo "=== Testing kubectl get po on workload cluster ==="
kubectl --kubeconfig=capi-quickstart.kubeconfig get po -A
echo -e "\n=== Testing kubectl get nodes ==="
kubectl --kubeconfig=capi-quickstart.kubeconfig get nodes
echo -e "\n=== Waiting for system pods to be ready ==="
kubectl --kubeconfig=capi-quickstart.kubeconfig wait --for=condition=Ready --timeout=300s pods -n kube-system -l k8s-app=kube-proxy
kubectl --kubeconfig=capi-quickstart.kubeconfig wait --for=condition=Ready --timeout=300s pods -n kube-system -l component=kube-apiserver
kubectl --kubeconfig=capi-quickstart.kubeconfig wait --for=condition=Ready --timeout=300s pods -n kube-system -l component=kube-controller-manager
kubectl --kubeconfig=capi-quickstart.kubeconfig wait --for=condition=Ready --timeout=300s pods -n kube-system -l component=kube-scheduler
- name: Deploy and test sample application
run: |
echo "=== Deploying nginx test application ==="
kubectl --kubeconfig=capi-quickstart.kubeconfig create deployment nginx --image=nginx:alpine --replicas=2
echo "=== Waiting for deployment to be ready ==="
kubectl --kubeconfig=capi-quickstart.kubeconfig wait --for=condition=Available --timeout=120s deployment/nginx
echo "=== Verifying pods are running ==="
kubectl --kubeconfig=capi-quickstart.kubeconfig get po -l app=nginx
echo "=== Creating a service ==="
kubectl --kubeconfig=capi-quickstart.kubeconfig expose deployment nginx --port=80 --type=ClusterIP
echo "=== Verifying service ==="
kubectl --kubeconfig=capi-quickstart.kubeconfig get svc nginx
- name: Verify cluster functionality
run: |
echo "=== Final cluster verification ==="
echo "Cluster nodes:"
kubectl --kubeconfig=capi-quickstart.kubeconfig get nodes -o wide
echo -e "\nAll pods:"
kubectl --kubeconfig=capi-quickstart.kubeconfig get po -A
echo -e "\nAll services:"
kubectl --kubeconfig=capi-quickstart.kubeconfig get svc -A
echo -e "\nCluster info:"
kubectl --kubeconfig=capi-quickstart.kubeconfig cluster-info
- name: Collect debug information on failure
if: failure()
run: |
echo "=== Events ==="
kubectl get events -A --sort-by='.lastTimestamp' | tail -50
echo -e "\n=== CAPI Operator Logs ==="
kubectl logs -n capi-operator-system deployment/capi-operator-cluster-api-operator --tail=100 || true
echo -e "\n=== Core Provider Logs ==="
kubectl logs -n capi-system deployment/capi-controller-manager --tail=100 || true
echo -e "\n=== Bootstrap Provider Logs ==="
kubectl logs -n capi-kubeadm-bootstrap-system deployment/capi-kubeadm-bootstrap-controller-manager --tail=100 || true
echo -e "\n=== Control Plane Provider Logs ==="
kubectl logs -n capi-kubeadm-control-plane-system deployment/capi-kubeadm-control-plane-controller-manager --tail=100 || true
echo -e "\n=== Infrastructure Provider Logs ==="
kubectl logs -n capd-system deployment/capd-controller-manager --tail=100 || true
echo -e "\n=== Webhook Services and Endpoints ==="
kubectl get svc,endpoints -A | grep webhook || true
echo -e "\n=== Webhook Certificates ==="
kubectl get certificate,certificaterequest,secret -A | grep -E "(webhook|serving-cert)" || true
echo -e "\n=== Cluster Resources ==="
kubectl get cluster,dockercluster,kubeadmcontrolplane,machine,dockermachine -A -o wide || true
echo -e "\n=== Describe Cluster ==="
kubectl describe cluster capi-quickstart || true
echo -e "\n=== Describe Machines ==="
kubectl describe machines -l cluster.x-k8s.io/cluster-name=capi-quickstart || true
echo -e "\n=== Docker Containers ==="
docker ps -a | grep -E "(smoke-test|kind)" || true
echo -e "\n=== Kind Clusters ==="
kind get clusters || true
echo -e "\n=== Describe Failed Pods ==="
kubectl get pods -A | grep -v Running | grep -v Completed | tail -n +2 | while read namespace name ready status restarts age; do
echo "Describing pod $name in namespace $namespace"
kubectl describe pod -n $namespace $name
echo "---"
done
- name: Clean up
if: always()
run: |
echo "=== Cleaning up kind clusters ==="
# List all kind clusters before cleanup
echo "Current kind clusters:"
kind get clusters || true
# Delete workload cluster
echo "Deleting workload cluster: capi-quickstart"
kind delete cluster --name capi-quickstart || true
# Delete management cluster
echo "Deleting management cluster: capi-operator-smoke-test"
kind delete cluster --name capi-operator-smoke-test || true
# Verify all clusters are deleted
echo "Remaining kind clusters:"
kind get clusters || true