diff --git a/.github/actions/smoke-test/action.yaml b/.github/actions/smoke-test/action.yaml new file mode 100644 index 0000000..32bb91a --- /dev/null +++ b/.github/actions/smoke-test/action.yaml @@ -0,0 +1,46 @@ +name: 'Smoke Test' +description: 'Install, verify, uninstall, and debug the developer quickstart' + +inputs: + timeout: + description: 'Timeout for install/uninstall scripts' + required: false + default: '300s' + overlay: + description: 'Overlay name for component verification (matches .github/config/overlays/.env)' + required: false + default: 'base' + +runs: + using: 'composite' + steps: + - name: Run install script + shell: bash + env: + LOCAL_DIR: . + TIMEOUT: ${{ inputs.timeout }} + run: ./install.sh + + - name: Verify deployments + shell: bash + env: + OVERLAY: ${{ inputs.overlay }} + run: .github/scripts/verify-install.sh + + - name: Run uninstall script + shell: bash + env: + LOCAL_DIR: . + TIMEOUT: ${{ inputs.timeout }} + run: ./uninstall.sh + + - name: Verify uninstall + shell: bash + run: .github/scripts/verify-uninstall.sh + + - name: Debug on failure + if: failure() + shell: bash + env: + OVERLAY: ${{ inputs.overlay }} + run: .github/scripts/debug.sh diff --git a/.github/config/kind-config.yaml b/.github/config/kind-config.yaml new file mode 100644 index 0000000..89ded6b --- /dev/null +++ b/.github/config/kind-config.yaml @@ -0,0 +1,17 @@ +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +nodes: + - role: control-plane + kubeadmConfigPatches: + - | + kind: InitConfiguration + nodeRegistration: + kubeletExtraArgs: + node-labels: "ingress-ready=true" + extraPortMappings: + - containerPort: 80 + hostPort: 80 + protocol: TCP + - containerPort: 443 + hostPort: 443 + protocol: TCP diff --git a/.github/config/overlays/base.env b/.github/config/overlays/base.env new file mode 100644 index 0000000..e2ffc68 --- /dev/null +++ b/.github/config/overlays/base.env @@ -0,0 +1,11 @@ +# Components expected in the base (default) deployment. +# Used by verify-install.sh, verify-uninstall.sh, and debug.sh. +# +# Format: +# OPERATORS - "namespace:deployment" pairs (space-separated) +# CUSTOM_RESOURCES - "namespace:resource" pairs (space-separated) +# NAMESPACES - namespaces to inspect on failure (space-separated) + +OPERATORS="strimzi:strimzi-cluster-operator apicurio-registry:apicurio-registry-operator streamshub-console:streamshub-console-operator" +CUSTOM_RESOURCES="kafka:kafka/dev-cluster apicurio-registry:apicurioregistry3/apicurio-registry streamshub-console:console.console.streamshub.github.com/streamshub-console" +NAMESPACES="strimzi kafka apicurio-registry streamshub-console" diff --git a/.github/scripts/debug.sh b/.github/scripts/debug.sh new file mode 100755 index 0000000..58c65ec --- /dev/null +++ b/.github/scripts/debug.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# +# Dump diagnostic information for debugging failed smoke tests. +# Reads component definitions from an overlay config file. +# +# Environment variables: +# OVERLAY - overlay name (default: "base") +# + +set +e + +OVERLAY="${OVERLAY:-base}" +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +CONFIG_FILE="${SCRIPT_DIR}/../config/overlays/${OVERLAY}.env" + +if [ ! -f "${CONFIG_FILE}" ]; then + echo "ERROR: Overlay config not found: ${CONFIG_FILE}" + exit 1 +fi + +# shellcheck disable=SC1090 +source "${CONFIG_FILE}" + +echo "=== CR status ===" +for entry in ${CUSTOM_RESOURCES}; do + ns="${entry%%:*}" + resource="${entry#*:}" + kubectl get "${resource}" -n "${ns}" -o yaml 2>/dev/null || true +done +echo "" +echo "=== Events (all namespaces) ===" +kubectl get events --all-namespaces --sort-by='.lastTimestamp' | tail -50 +echo "" +echo "=== Pods (all namespaces) ===" +kubectl get pods --all-namespaces +echo "" +for ns in ${NAMESPACES}; do + echo "=== Pods in ${ns} ===" + kubectl get pods -n "${ns}" -o wide 2>/dev/null || true + echo "=== Pod logs in ${ns} ===" + for pod in $(kubectl get pods -n "${ns}" -o name 2>/dev/null); do + echo "--- ${pod} ---" + kubectl logs "${pod}" -n "${ns}" --tail=30 2>/dev/null || true + done +done diff --git a/.github/scripts/verify-install.sh b/.github/scripts/verify-install.sh new file mode 100755 index 0000000..2418ee2 --- /dev/null +++ b/.github/scripts/verify-install.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# +# Verify that all expected deployments and custom resources are ready. +# Reads component definitions from an overlay config file. +# +# Environment variables: +# OVERLAY - overlay name (default: "base") +# TIMEOUT - kubectl wait timeout (default: "600s") +# + +set -euo pipefail + +OVERLAY="${OVERLAY:-base}" +TIMEOUT="${TIMEOUT:-600s}" +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +CONFIG_FILE="${SCRIPT_DIR}/../config/overlays/${OVERLAY}.env" + +if [ ! -f "${CONFIG_FILE}" ]; then + echo "ERROR: Overlay config not found: ${CONFIG_FILE}" + exit 1 +fi + +# shellcheck disable=SC1090 +source "${CONFIG_FILE}" + +echo "=== Verifying install (overlay: ${OVERLAY}) ===" +echo "" + +for entry in ${OPERATORS}; do + ns="${entry%%:*}" + deploy="${entry#*:}" + echo "--- ${deploy} (${ns}) ---" + kubectl get deployment -n "${ns}" "${deploy}" +done + +echo "" + +for entry in ${CUSTOM_RESOURCES}; do + ns="${entry%%:*}" + resource="${entry#*:}" + echo "--- ${resource} (${ns}) ---" + kubectl wait "${resource}" --for=condition=Ready -n "${ns}" --timeout="${TIMEOUT}" +done diff --git a/.github/scripts/verify-uninstall.sh b/.github/scripts/verify-uninstall.sh new file mode 100755 index 0000000..232e922 --- /dev/null +++ b/.github/scripts/verify-uninstall.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# +# Verify that all quick-start resources have been removed after uninstall. +# + +set -euo pipefail + +QUICKSTART_LABEL="app.kubernetes.io/part-of=streamshub-developer-quickstart" + +echo "--- Checking for remaining quick-start resources ---" +remaining=$(kubectl get all -A -l "${QUICKSTART_LABEL}" --no-headers 2>/dev/null | wc -l | tr -d ' ') +if [ "$remaining" -gt 0 ]; then + echo "ERROR: Found $remaining remaining resources after uninstall:" + kubectl get all -A -l "${QUICKSTART_LABEL}" + exit 1 +fi +echo "All quick-start resources successfully removed" diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml new file mode 100644 index 0000000..b7eb86f --- /dev/null +++ b/.github/workflows/integration.yaml @@ -0,0 +1,48 @@ +name: Integration Test + +on: + push: + branches: + - main + pull_request: + +jobs: + smoke-minikube: + name: smoke-minikube + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Start Minikube + id: minikube + uses: medyagh/setup-minikube@e9e035a86bbc3caea26a450bd4dbf9d0c453682e # v0.0.21 + with: + minikube-version: 'latest' + addons: registry,ingress,ingress-dns + insecure-registry: 'localhost:5000,10.0.0.0/24' + start-args: '--extra-config=kubeadm.ignore-preflight-errors=SystemVerification --extra-config=apiserver.authorization-mode=RBAC,Node' + + - name: Smoke test + uses: ./.github/actions/smoke-test + + smoke-kind: + name: smoke-kind + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Create Kind cluster + uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0 + with: + config: .github/config/kind-config.yaml + + - name: Deploy ingress-nginx + run: | + kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.1/deploy/static/provider/kind/deploy.yaml + kubectl wait --namespace ingress-nginx \ + --for=condition=Ready pod \ + --selector=app.kubernetes.io/component=controller \ + --timeout=120s + + - name: Smoke test + uses: ./.github/actions/smoke-test diff --git a/.github/workflows/validate.yaml b/.github/workflows/validate.yaml index 42b3a61..b5ca400 100644 --- a/.github/workflows/validate.yaml +++ b/.github/workflows/validate.yaml @@ -2,7 +2,8 @@ name: Validate on: push: - branches: [main] + branches: + - main pull_request: jobs: @@ -10,10 +11,10 @@ jobs: name: Validate Kustomize configs runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up kubectl - uses: azure/setup-kubectl@v4 + uses: azure/setup-kubectl@776406bce94f63e41d621b960d78ee25c8b76ede # v4.0.1 - name: Build base layer run: kubectl kustomize base/ @@ -33,10 +34,10 @@ jobs: name: Lint shell scripts runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Run ShellCheck - uses: ludeeus/action-shellcheck@2.0.0 + uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # 2.0.0 with: version: v0.11.0 scandir: "." @@ -46,7 +47,7 @@ jobs: name: Lint YAML files runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install yamllint run: | diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c8dfaf --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +# VSCode +.vscode + +# IntelliJ IDEA specific +.idea/ +*.iml + +### Mac OS ### +**.DS_Store \ No newline at end of file diff --git a/README.md b/README.md index c41cfd0..10eec81 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,50 @@ kubectl port-forward -n streamshub-console svc/streamshub-console-console-servic Open [http://localhost:8080](http://localhost:8080) in your browser. +### Kind + +When using Kind, create the cluster with ingress-ready port mappings: + +```bash +cat <