|
49 | 49 | type: choice
|
50 | 50 | options:
|
51 | 51 | - scaleway
|
| 52 | + - linode |
52 | 53 | - digitalocean
|
53 | 54 | default: 'scaleway'
|
54 | 55 | kubernetes_versions:
|
@@ -200,6 +201,30 @@ jobs:
|
200 | 201 | echo $versions
|
201 | 202 | echo "versions=$versions" >> $GITHUB_OUTPUT
|
202 | 203 |
|
| 204 | + preprocess-linode-input: |
| 205 | + needs: preprocess-input |
| 206 | + if: ${{ inputs.cloud_provider == 'linode' }} |
| 207 | + name: Preprocess input variables for linode |
| 208 | + runs-on: ubuntu-latest |
| 209 | + outputs: |
| 210 | + kubernetes_versions: ${{ steps.k8s-versions.outputs.versions }} |
| 211 | + steps: |
| 212 | + - name: Install the Linode CLI |
| 213 | + uses: linode/action-linode-cli@v1 |
| 214 | + with: |
| 215 | + token: ${{ secrets.LINODE_TOKEN }} |
| 216 | + - id: k8s-versions |
| 217 | + name: Process k8s version input |
| 218 | + run: | |
| 219 | + if [ -z '${{ inputs.kubernetes_versions }}' ]; then |
| 220 | + echo "Kubernetes versions not specified, determine Linode supported versions" |
| 221 | + versions=`linode-cli lke versions-list --json | jq -ce '.[] | .id'` |
| 222 | + else |
| 223 | + versions='${{ inputs.kubernetes_versions }}' |
| 224 | + fi |
| 225 | + echo $versions |
| 226 | + echo "versions=$versions" >> $GITHUB_OUTPUT |
| 227 | +
|
203 | 228 | run-integration-test-scaleway:
|
204 | 229 | if: ${{ inputs.cloud_provider == 'scaleway' }}
|
205 | 230 | name: Run integration test on scaleway cluster
|
@@ -472,3 +497,164 @@ jobs:
|
472 | 497 | SLACK_ICON: https://github.com/redkubes.png?size=48
|
473 | 498 | SLACK_TITLE: Scheduled integration tests
|
474 | 499 | SLACK_USERNAME: RedKubesBot
|
| 500 | + |
| 501 | + run-integration-test-linode: |
| 502 | + if: ${{ inputs.cloud_provider == 'linode' }} |
| 503 | + name: Run integration test on linode cluster |
| 504 | + needs: preprocess-linode-input |
| 505 | + runs-on: ubuntu-latest |
| 506 | + strategy: |
| 507 | + fail-fast: false |
| 508 | + matrix: |
| 509 | + kubernetes_versions: ${{ fromJSON(needs.preprocess-linode-input.outputs.kubernetes_versions) }} |
| 510 | + max-parallel: 5 |
| 511 | + steps: |
| 512 | + - name: Install the Linode CLI |
| 513 | + uses: linode/action-linode-cli@v1 |
| 514 | + with: |
| 515 | + token: ${{ secrets.LINODE_TOKEN }} |
| 516 | + - name: Set k8s cluster name |
| 517 | + run: | |
| 518 | + echo "LINODE_CLUSTER_NAME=$(echo ${{ github.actor }} | tr '[:upper:]' '[:lower:]')-$(TZ='GMT-2' date +'%m-%d-%H-%M')" >> $GITHUB_ENV |
| 519 | + # Cluster name must be no longer than 63 characters |
| 520 | + - name: Determine exact k8s version |
| 521 | + run: | |
| 522 | + echo LINODE_K8S_VERSION=$(linode-cli lke versions-list --json | jq -ce --arg version "${{ matrix.kubernetes_versions }}" '.[] | select(.id | tostring | startswith($version)) | .id') >> $GITHUB_ENV |
| 523 | + - name: Create k8s cluster for testing |
| 524 | + run: | |
| 525 | + linode-cli lke cluster-create \ |
| 526 | + --label ${{ env.LINODE_CLUSTER_NAME }} \ |
| 527 | + --region nl-ams \ |
| 528 | + --k8s_version ${{ env.LINODE_K8S_VERSION }} \ |
| 529 | + --control_plane.high_availability true \ |
| 530 | + --node_pools.type g6-dedicated-8 --node_pools.count 3 \ |
| 531 | + --node_pools.autoscaler.enabled true \ |
| 532 | + --node_pools.autoscaler.max 3 \ |
| 533 | + --node_pools.autoscaler.min 3 \ |
| 534 | + --tags testing \ |
| 535 | + --no-defaults |
| 536 | + - name: Retrieve cluster id |
| 537 | + run: echo "LINODE_CLUSTER_ID=$(linode-cli lke clusters-list --json | jq -ce '.[] | select(.label | startswith("${{ env.LINODE_CLUSTER_NAME }}")) | .id')" >> $GITHUB_ENV |
| 538 | + - name: Wait for cluster to be ready |
| 539 | + run: | |
| 540 | + echo "Waiting for the cluster to be active..." |
| 541 | +
|
| 542 | + while :; do |
| 543 | + rawOutput=$(linode-cli lke pools-list ${{ env.LINODE_CLUSTER_ID }} --json) |
| 544 | +
|
| 545 | + allReady=$(echo "$rawOutput" | jq -r 'map(.nodes | .status == "ready") | all') |
| 546 | + echo "All nodes ready: $allReady" |
| 547 | + |
| 548 | + if [ "$allReady" == "true" ]; then |
| 549 | + echo "Cluster is ready" |
| 550 | + break |
| 551 | + fi |
| 552 | + |
| 553 | + sleep 30 |
| 554 | + done |
| 555 | + - name: Save kubectl config with auth token and Get kubectl environment and create docker secret |
| 556 | + run: | |
| 557 | + # Get the kubeconfig from linode-cli |
| 558 | + kubeconfig=$(linode-cli lke kubeconfig-view ${{ env.LINODE_CLUSTER_ID }} --text | sed 1d | base64 --decode) |
| 559 | +
|
| 560 | + # Save the kubeconfig to a file |
| 561 | + kubeconfigDir="$HOME/.kube" |
| 562 | + kubeconfigPath="$HOME/.kube/config" |
| 563 | + mkdir -p "$kubeconfigDir" # Create the directory if it doesn't exist |
| 564 | + echo "$kubeconfig" > "$kubeconfigPath" |
| 565 | + echo "Kubeconfig saved to $kubeconfigPath" |
| 566 | + |
| 567 | + # Set the kubectl context to use the new kubeconfig |
| 568 | + export KUBECONFIG="$kubeconfigPath" |
| 569 | + contextName=$(kubectl config get-contexts -o name | head -n 1) |
| 570 | + kubectl config use-context "$contextName" |
| 571 | + echo "Kubectl context set to linode" |
| 572 | + echo LINODE_CLUSTER_CONTEXT=`kubectl config current-context` >> $GITHUB_ENV |
| 573 | + - name: Create image pull secret on test cluster |
| 574 | + run: | |
| 575 | + kubectl create secret docker-registry reg-otomi-github \ |
| 576 | + --docker-server=${{ env.CACHE_REGISTRY }} \ |
| 577 | + --docker-username=${{ env.GIT_USER }} \ |
| 578 | + --docker-password='${{ secrets.NPM_TOKEN }}' |
| 579 | + - name: Checkout |
| 580 | + uses: actions/checkout@v4 |
| 581 | + - name: Prepare Otomi chart |
| 582 | + if: ${{ inputs.install_profile != 'no-otomi' }} |
| 583 | + run: | |
| 584 | + ref=${{ github.event.pull_request.head.ref || github.ref }} |
| 585 | + tag=${ref##*/} |
| 586 | + sed --in-place "s/APP_VERSION_PLACEHOLDER/$tag/g" chart/otomi/Chart.yaml |
| 587 | + sed --in-place "s/CONTEXT_PLACEHOLDER/${{ env.LINODE_CLUSTER_CONTEXT }}/g" tests/integration/${{ inputs.install_profile }}.yaml |
| 588 | + sed --in-place "s/OTOMI_VERSION_PLACEHOLDER/${GITHUB_REF##*/}/g" tests/integration/${{ inputs.install_profile }}.yaml |
| 589 | + touch values-container-registry.yaml |
| 590 | +
|
| 591 | + # If a pipeline installs Otomi from the semver tag then pull container image from DockerHub |
| 592 | + [[ ${GITHUB_REF##*/} =~ ^v[0-9].+$ ]] && exit 0 |
| 593 | +
|
| 594 | + # Pull image from cache registry |
| 595 | + cat << EOF > values-container-registry.yaml |
| 596 | + imageName: "${{ env.CACHE_REGISTRY }}/${{ env.CACHE_REPO }}" |
| 597 | + imagePullSecretNames: |
| 598 | + - reg-otomi-github |
| 599 | + EOF |
| 600 | + - name: Otomi install |
| 601 | + if: ${{ inputs.install_profile != 'no-otomi' }} |
| 602 | + env: |
| 603 | + AZ_DNS: ${{ secrets.AZ_DNS }} |
| 604 | + AZ_KMS: ${{ secrets.AZ_KMS }} |
| 605 | + AZ_OIDC: ${{ secrets.AZ_OIDC }} |
| 606 | + LETSENCRYPT_STAGING: ${{ secrets.LETSENCRYPT_STAGING }} |
| 607 | + LETSENCRYPT_PRODUCTION: ${{ secrets.LETSENCRYPT_PRODUCTION }} |
| 608 | + OTOMI_LICENSE: ${{ secrets.OTOMI_LICENSE }} |
| 609 | + run: | |
| 610 | + domainSuffix='' |
| 611 | + touch values.yaml |
| 612 | + [[ '${{ inputs.license }}' == 'yes' ]] && echo "$OTOMI_LICENSE" >> values.yaml |
| 613 | + [[ '${{ inputs.dns }}' == 'az_dns' ]] && echo "$AZ_DNS" >> values.yaml && domainSuffix='--set cluster.domainSuffix=tst-${{ github.run_id }}.aks.redkubes.net' |
| 614 | + [[ '${{ inputs.kms }}' == 'az_kms' ]] && echo "$AZ_KMS" >> values.yaml |
| 615 | + [[ '${{ inputs.oidc }}' == 'az_oidc' ]] && echo "$AZ_OIDC" >> values.yaml |
| 616 | + [[ '${{ inputs.certificate }}' == 'letsencrypt_staging' ]] && echo "$LETSENCRYPT_STAGING" >> values.yaml |
| 617 | + [[ '${{ inputs.certificate }}' == 'letsencrypt_production' ]] && echo "$LETSENCRYPT_PRODUCTION" >> values.yaml |
| 618 | +
|
| 619 | + install_args="--wait --wait-for-jobs --timeout 90m0s otomi chart/otomi \ |
| 620 | + --values tests/integration/${{ inputs.install_profile }}.yaml \ |
| 621 | + --values values-container-registry.yaml |
| 622 | + --values values.yaml \ |
| 623 | + --set cluster.provider=${{ inputs.cloud_provider }} |
| 624 | + $domainSuffix" |
| 625 | +
|
| 626 | + [[ '${{ inputs.generate_password }}' == 'no' ]] && install_args="$install_args --set otomi.adminPassword=welcomeotomi" |
| 627 | +
|
| 628 | + helm install $install_args |
| 629 | +
|
| 630 | + - name: Gather k8s events on failure |
| 631 | + if: failure() |
| 632 | + run: | |
| 633 | + kubectl get events --sort-by='.lastTimestamp' -A |
| 634 | + - name: Gather k8s pods on failure |
| 635 | + if: failure() |
| 636 | + run: | |
| 637 | + kubectl get pods -A -o wide |
| 638 | + - name: Gather otomi logs on failure |
| 639 | + if: failure() |
| 640 | + run: | |
| 641 | + kubectl logs jobs/otomi --tail 150 |
| 642 | + - name: Gather otomi-e2e logs on failure |
| 643 | + if: failure() |
| 644 | + run: | |
| 645 | + kubectl logs -n maintenance -l app.kubernetes.io/instance=job-e2e --tail 15000 |
| 646 | + - name: Remove the test cluster |
| 647 | + if: always() |
| 648 | + run: | |
| 649 | + [[ "${{ inputs.cluster_persistence }}" == "preserve" ]] && echo "The cluster ${{ env.LINODE_CLUSTER_NAME }} will NOT be destroyed!!" && exit 0 |
| 650 | + linode-cli lke cluster-delete ${{ env.LINODE_CLUSTER_ID }} |
| 651 | + - name: Slack Notification |
| 652 | + if: always() |
| 653 | + uses: rtCamp/action-slack-notify@v2 |
| 654 | + env: |
| 655 | + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} |
| 656 | + SLACK_CHANNEL: github-ci |
| 657 | + SLACK_COLOR: ${{ job.status }} |
| 658 | + SLACK_ICON: https://github.com/redkubes.png?size=48 |
| 659 | + SLACK_TITLE: Scheduled integration tests |
| 660 | + SLACK_USERNAME: RedKubesBot |
0 commit comments