|
| 1 | +name: OpenWhisk Regression on kind |
| 2 | + |
| 3 | +on: |
| 4 | + workflow_dispatch: |
| 5 | + push: |
| 6 | + branches: |
| 7 | + - master |
| 8 | + - 'feature/**' |
| 9 | + |
| 10 | +jobs: |
| 11 | + regression: |
| 12 | + strategy: |
| 13 | + matrix: |
| 14 | + include: |
| 15 | + - language: python |
| 16 | + version: "3.11" |
| 17 | + architecture: "x64" |
| 18 | + - language: nodejs |
| 19 | + version: "20" |
| 20 | + architecture: "x64" |
| 21 | + - language: java |
| 22 | + version: "8" |
| 23 | + architecture: "x64" |
| 24 | + fail-fast: false |
| 25 | + |
| 26 | + name: ${{ matrix.language }} ${{ matrix.version }} ${{ matrix.architecture }} |
| 27 | + runs-on: ubuntu-latest |
| 28 | + timeout-minutes: 90 |
| 29 | + |
| 30 | + env: |
| 31 | + KIND_VERSION: v0.27.0 |
| 32 | + KIND_NODE_IMAGE: kindest/node:v1.31.4 |
| 33 | + REGISTRY_NAME: kind-registry |
| 34 | + REGISTRY_PORT: "5000" |
| 35 | + OW_NAMESPACE: openwhisk |
| 36 | + OW_API_PORT: "31001" |
| 37 | + WSK_AUTH: 23bc46b1-71f6-4ed5-8c54-816aa4f8c502:123zO3xZCLrMN6v2BKK1dXYFpXlPkccOFqm12CdAsMgRU4VrNZ9lyGVCGuMDGIwP |
| 38 | + OW_ACTION_MEMORY_MAX: "3072" |
| 39 | + RESOURCE_PREFIX: ci |
| 40 | + LANGUAGE: ${{ matrix.language }} |
| 41 | + LANGUAGE_VERSION: ${{ matrix.version }} |
| 42 | + ARCHITECTURE: ${{ matrix.architecture }} |
| 43 | + |
| 44 | + steps: |
| 45 | + - name: Checkout code |
| 46 | + uses: actions/checkout@v4 |
| 47 | + with: |
| 48 | + submodules: recursive |
| 49 | + |
| 50 | + #- name: Reclaim disk |
| 51 | + # run: | |
| 52 | + # sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \ |
| 53 | + # /opt/hostedtoolcache/CodeQL |
| 54 | + # docker image prune -af |
| 55 | + # df -h |
| 56 | + |
| 57 | + - name: Install kind |
| 58 | + run: | |
| 59 | + curl -fsSLo kind https://kind.sigs.k8s.io/dl/${KIND_VERSION}/kind-linux-amd64 |
| 60 | + sudo install -m 0755 kind /usr/local/bin/kind |
| 61 | + kind version |
| 62 | +
|
| 63 | + - name: Install kubectl |
| 64 | + run: | |
| 65 | + KCTL=$(curl -fsSL https://dl.k8s.io/release/stable.txt) |
| 66 | + curl -fsSLo kubectl https://dl.k8s.io/release/${KCTL}/bin/linux/amd64/kubectl |
| 67 | + sudo install -m 0755 kubectl /usr/local/bin/kubectl |
| 68 | + kubectl version --client |
| 69 | +
|
| 70 | + - name: Install helm |
| 71 | + uses: azure/setup-helm@v4 |
| 72 | + with: |
| 73 | + version: latest |
| 74 | + |
| 75 | + - name: Install wsk CLI |
| 76 | + run: | |
| 77 | + curl -fsSLo wsk.tgz \ |
| 78 | + https://github.com/apache/openwhisk-cli/releases/download/1.2.0/OpenWhisk_CLI-1.2.0-linux-amd64.tgz |
| 79 | + tar -xzf wsk.tgz wsk |
| 80 | + sudo install -m 0755 wsk /usr/local/bin/wsk |
| 81 | +
|
| 82 | + - name: Install uv |
| 83 | + uses: astral-sh/setup-uv@v4 |
| 84 | + |
| 85 | + - name: Create virtual environment and install SeBS |
| 86 | + run: | |
| 87 | + uv venv |
| 88 | + uv pip install . |
| 89 | +
|
| 90 | + - name: Start local registry |
| 91 | + run: | |
| 92 | + docker run -d --restart=always \ |
| 93 | + -p 127.0.0.1:${REGISTRY_PORT}:5000 \ |
| 94 | + --name ${REGISTRY_NAME} \ |
| 95 | + registry:2 |
| 96 | +
|
| 97 | + - name: Create kind cluster |
| 98 | + run: | |
| 99 | + cat > kind-config.yaml <<EOF |
| 100 | + kind: Cluster |
| 101 | + apiVersion: kind.x-k8s.io/v1alpha4 |
| 102 | + containerdConfigPatches: |
| 103 | + - |- |
| 104 | + [plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:${REGISTRY_PORT}"] |
| 105 | + endpoint = ["http://${REGISTRY_NAME}:5000"] |
| 106 | + nodes: |
| 107 | + - role: control-plane |
| 108 | + - role: worker |
| 109 | + labels: |
| 110 | + openwhisk-role: core |
| 111 | + extraPortMappings: |
| 112 | + - containerPort: ${OW_API_PORT} |
| 113 | + hostPort: ${OW_API_PORT} |
| 114 | + protocol: TCP |
| 115 | + - role: worker |
| 116 | + labels: |
| 117 | + openwhisk-role: invoker |
| 118 | + EOF |
| 119 | + kind create cluster --image ${KIND_NODE_IMAGE} --config kind-config.yaml --wait 5m |
| 120 | +
|
| 121 | + - name: Attach registry to kind network |
| 122 | + run: | |
| 123 | + if [ "$(docker inspect -f '{{json .NetworkSettings.Networks.kind}}' ${REGISTRY_NAME})" = "null" ]; then |
| 124 | + docker network connect kind ${REGISTRY_NAME} |
| 125 | + fi |
| 126 | +
|
| 127 | + - name: Start Minio and ScyllaDB |
| 128 | + run: | |
| 129 | + set -o pipefail |
| 130 | + uv run sebs storage start all configs/storage.json --output-json storage.json |
| 131 | +
|
| 132 | + - name: Configure OpenWhisk |
| 133 | + run: | |
| 134 | + WORKER_IP=$(kubectl get node kind-worker -o jsonpath='{.status.addresses[0].address}') |
| 135 | + HOST_IP=$(hostname -I | awk '{print $1}') |
| 136 | + echo "WORKER_IP=${WORKER_IP}" >> $GITHUB_ENV |
| 137 | + echo "HOST_IP=${HOST_IP}" >> $GITHUB_ENV |
| 138 | +
|
| 139 | + git clone --depth 1 https://github.com/apache/openwhisk-deploy-kube.git /tmp/ow |
| 140 | +
|
| 141 | + sed -i '/^ memory:$/,/^ concurrency:$/ s/^\( max:\) ".*"/\1 "'"${OW_ACTION_MEMORY_MAX}"' MB"/' \ |
| 142 | + /tmp/ow/helm/openwhisk/values.yaml |
| 143 | +
|
| 144 | + helm install owdev /tmp/ow/helm/openwhisk \ |
| 145 | + -n ${OW_NAMESPACE} --create-namespace \ |
| 146 | + -f /tmp/ow/deploy/kind/mycluster.yaml |
| 147 | +
|
| 148 | + for i in $(seq 1 60); do |
| 149 | + kubectl get job owdev-install-packages -n ${OW_NAMESPACE} >/dev/null 2>&1 && break |
| 150 | + sleep 2 |
| 151 | + done |
| 152 | + kubectl wait --for=condition=complete --timeout=20m \ |
| 153 | + job/owdev-install-packages -n ${OW_NAMESPACE} |
| 154 | + kubectl get pods -n ${OW_NAMESPACE} |
| 155 | +
|
| 156 | + wsk property set \ |
| 157 | + --apihost https://${WORKER_IP}:${OW_API_PORT} \ |
| 158 | + --auth ${WSK_AUTH} |
| 159 | +
|
| 160 | + - name: Create OpenWhisk regression config |
| 161 | + run: | |
| 162 | + jq \ |
| 163 | + --arg host_ip "${HOST_IP}" \ |
| 164 | + ' |
| 165 | + .object.minio.address = ($host_ip + ":" + (.object.minio.mapped_port | tostring)) |
| 166 | + | .nosql.scylladb.address = ($host_ip + ":" + (.nosql.scylladb.mapped_port | tostring)) |
| 167 | + ' storage.json > storage-openwhisk.json |
| 168 | +
|
| 169 | + jq \ |
| 170 | + --arg language "${LANGUAGE}" \ |
| 171 | + --arg version "${LANGUAGE_VERSION}" \ |
| 172 | + --arg architecture "${ARCHITECTURE}" \ |
| 173 | + --arg registry "localhost:${REGISTRY_PORT}" \ |
| 174 | + --slurpfile storage storage-openwhisk.json \ |
| 175 | + ' |
| 176 | + .experiments.architecture = $architecture |
| 177 | + | .experiments.runtime.language = $language |
| 178 | + | .experiments.runtime.version = $version |
| 179 | + | .deployment.openwhisk.docker_registry.registry = $registry |
| 180 | + | .deployment.openwhisk.storage = $storage[0] |
| 181 | + ' configs/openwhisk.json > openwhisk-regression.json |
| 182 | +
|
| 183 | + - name: Run OpenWhisk regression |
| 184 | + id: regression |
| 185 | + continue-on-error: true |
| 186 | + timeout-minutes: 45 |
| 187 | + run: | |
| 188 | + set -o pipefail |
| 189 | + uv run sebs benchmark regression test \ |
| 190 | + --config openwhisk-regression.json \ |
| 191 | + --deployment openwhisk \ |
| 192 | + --language ${LANGUAGE} \ |
| 193 | + --language-version ${LANGUAGE_VERSION} \ |
| 194 | + --architecture ${ARCHITECTURE} \ |
| 195 | + --selected-architecture \ |
| 196 | + --resource-prefix ${RESOURCE_PREFIX} \ |
| 197 | + --filter-output |
| 198 | +
|
| 199 | + - name: Collect OpenWhisk action logs |
| 200 | + if: steps.regression.outcome == 'failure' |
| 201 | + run: | |
| 202 | + mkdir -p diagnostics |
| 203 | + wsk -i action list > diagnostics/action-list.txt 2>&1 || true |
| 204 | + awk 'NF > 0 && $1 != "actions" && $1 != "ok:" {print $1}' diagnostics/action-list.txt \ |
| 205 | + > diagnostics/actions.txt |
| 206 | +
|
| 207 | + if [ ! -s diagnostics/actions.txt ]; then |
| 208 | + echo "No OpenWhisk actions returned by 'wsk action list'." \ |
| 209 | + > diagnostics/no-actions.txt |
| 210 | + fi |
| 211 | +
|
| 212 | + while IFS= read -r action; do |
| 213 | + [ -n "${action}" ] || continue |
| 214 | + safe_name=$(echo "${action}" | tr '/.' '__') |
| 215 | + { |
| 216 | + echo "=== action ${action} ===" |
| 217 | + wsk -i action get "${action}" || true |
| 218 | + echo |
| 219 | + echo "=== activations for ${action} ===" |
| 220 | + wsk -i activation list "${action}" || true |
| 221 | + echo |
| 222 | + } | tee "diagnostics/${safe_name}.txt" |
| 223 | +
|
| 224 | + activation_ids=$( |
| 225 | + wsk -i activation list "${action}" 2>/dev/null \ |
| 226 | + | awk '$3 ~ /^[0-9a-f]{32}$/ {print $3}' |
| 227 | + ) |
| 228 | + for activation_id in ${activation_ids}; do |
| 229 | + { |
| 230 | + echo "=== activation ${activation_id} logs for ${action} ===" |
| 231 | + wsk -i activation logs "${activation_id}" || true |
| 232 | + echo |
| 233 | + echo "=== activation ${activation_id} record for ${action} ===" |
| 234 | + wsk -i activation get "${activation_id}" || true |
| 235 | + echo |
| 236 | + } >> "diagnostics/${safe_name}.txt" |
| 237 | + done |
| 238 | + done < diagnostics/actions.txt |
| 239 | +
|
| 240 | + - name: Diagnostics on failure |
| 241 | + if: failure() |
| 242 | + run: | |
| 243 | + mkdir -p diagnostics |
| 244 | + { |
| 245 | + echo "=== pods ===" |
| 246 | + kubectl get pods -A |
| 247 | + echo |
| 248 | + echo "=== invoker logs ===" |
| 249 | + kubectl logs -n ${OW_NAMESPACE} -l name=owdev-invoker --tail=200 || true |
| 250 | + echo |
| 251 | + echo "=== controller logs ===" |
| 252 | + kubectl logs -n ${OW_NAMESPACE} -l name=owdev-controller --tail=200 || true |
| 253 | + echo |
| 254 | + echo "=== registry contents ===" |
| 255 | + curl -s http://localhost:${REGISTRY_PORT}/v2/_catalog || true |
| 256 | + echo |
| 257 | + echo "=== registry container logs ===" |
| 258 | + docker logs ${REGISTRY_NAME} --tail=100 || true |
| 259 | + } | tee diagnostics/cluster-diagnostics.txt |
| 260 | +
|
| 261 | + - name: Upload regression artifacts |
| 262 | + if: always() |
| 263 | + uses: actions/upload-artifact@v4 |
| 264 | + with: |
| 265 | + name: openwhisk-regression-artifacts-${{ matrix.language }}-${{ matrix.version }}-${{ matrix.architecture }} |
| 266 | + path: | |
| 267 | + diagnostics/ |
| 268 | + regression-cache/ |
| 269 | + storage.json |
| 270 | + storage-openwhisk.json |
| 271 | + openwhisk-regression.json |
| 272 | + regression_*.json |
| 273 | + if-no-files-found: ignore |
| 274 | + |
| 275 | + - name: Fail job when regression failed |
| 276 | + if: steps.regression.outcome == 'failure' |
| 277 | + run: exit 1 |
| 278 | + |
| 279 | + - name: Cleanup |
| 280 | + if: always() |
| 281 | + run: | |
| 282 | + uv run sebs storage stop all storage.json || true |
| 283 | + kind delete cluster || true |
| 284 | + docker rm -f ${REGISTRY_NAME} || true |
0 commit comments