diff --git a/.github/inject-sensitive-values.sh b/.github/inject-sensitive-values.sh new file mode 100755 index 0000000..37e4405 --- /dev/null +++ b/.github/inject-sensitive-values.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# Directory containing values files +VALUES_DIR=$1 + +# Image repository and tag +REPO=$2 +TAG=$3 +PRIVATE_KEY=$4 + +# Loop through each values file in the directory +for VALUES_FILE in "$VALUES_DIR"/*.yaml; do + # Use sed to update the repository and tag + sed -i "s|repository:.*|repository: $REPO|g" "$VALUES_FILE" + sed -i "s|tag:.*|tag: \"$TAG\"|g" "$VALUES_FILE" + sed -i "s|PrivateKey = \".*\"|PrivateKey = \"$PRIVATE_KEY\"|g" "$VALUES_FILE" +done \ No newline at end of file diff --git a/.github/kubeval.sh b/.github/kubeval.sh new file mode 100755 index 0000000..9a9d8ff --- /dev/null +++ b/.github/kubeval.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +mkdir -p ./.bin +export PATH="./.bin:$PATH" + +set -euxo pipefail + +KUBEVAL_VERSION=v0.16.1 + +SEMVER_VERSION=v1.0.5 + +CHART_DIRS="$(git diff --find-renames --name-only "$(git rev-parse --abbrev-ref HEAD)" remotes/origin/main -- charts | cut -d '/' -f 2 | uniq)" +SCHEMA_LOCATION="https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/" + +# install kubeval +curl --silent --show-error --fail --location --output /tmp/kubeval.tar.gz https://github.com/instrumenta/kubeval/releases/download/"${KUBEVAL_VERSION}"/kubeval-linux-amd64.tar.gz +tar -C .bin/ -xf /tmp/kubeval.tar.gz kubeval + +# install semver compare +curl -sSfLo .bin/semver2 https://raw.githubusercontent.com/Ariel-Rodriguez/sh-semversion-2/${SEMVER_VERSION}/semver2.sh +chmod +x .bin/semver2 + +# Compute required kubernetes api versions +apis=() + +# validate charts +for CHART_DIR in ${CHART_DIRS}; do + (cd "charts/${CHART_DIR}"; helm dependency build) + for VALUES_FILE in charts/"${CHART_DIR}"/ci/*.yaml; do + helm template \ + "${apis[@]}" \ + --values "${VALUES_FILE}" \ + charts/"${CHART_DIR}" | kubeval \ + --strict \ + --ignore-missing-schemas \ + --kubernetes-version "${KUBERNETES_VERSION#v}" \ + --schema-location "${SCHEMA_LOCATION}" + done +done \ No newline at end of file diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8de3289..0925b04 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -7,6 +7,9 @@ on: pull_request: merge_group: +permissions: + id-token: write + contents: read jobs: lint-chart: @@ -42,11 +45,124 @@ jobs: - name: Run helm-docs run: .github/helm-docs.sh + kubeval-chart: + runs-on: ubuntu-latest + needs: + - lint-chart + - lint-docs + strategy: + matrix: + k8s: + # from https://github.com/yannh/kubernetes-json-schema + - v1.26.12 + - v1.27.9 + - v1.28.5 + - v1.29.0 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Run kubeval + env: + KUBERNETES_VERSION: ${{ matrix.k8s }} + run: .github/kubeval.sh + + install-chart: + name: install-chart + runs-on: ubuntu-latest + if: ${{ github.event_name != 'pull_request' || github.repository_owner != github.event.pull_request.head.repo.owner.login || !startsWith(github.event.pull_request.head.ref, 'renovate/') }} + needs: + - lint-chart + - lint-docs + - kubeval-chart + strategy: + matrix: + k8s: + # from https://hub.docker.com/r/kindest/node/tags + - v1.26.13 + - v1.27.10 + - v1.28.6 + - v1.29.1 + env: + ECR_REPO: "${{ secrets.ECR_REPO }}" + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: assume base role + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.IAM_ROLE }} + role-session-name: ${{ github.actor }} + mask-aws-account-id: true + aws-region: us-east-1 + role-duration-seconds: 900 + + - name: assume ecr role + run: | + aws sts assume-role --role-arn ${{ secrets.ECR_ROLE }} --role-session-name ${{ github.actor }} --region us-east-1 --tags "Key=repo,Value=builder-vault-helm" > assume-role-output.json + AWS_ACCESS_KEY_ID=$(jq -r '.Credentials.AccessKeyId' assume-role-output.json) + AWS_SECRET_ACCESS_KEY=$(jq -r '.Credentials.SecretAccessKey' assume-role-output.json) + AWS_SESSION_TOKEN=$(jq -r '.Credentials.SessionToken' assume-role-output.json) + echo "AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID" >> $GITHUB_ENV + echo "AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY" >> $GITHUB_ENV + echo "AWS_SESSION_TOKEN=$AWS_SESSION_TOKEN" >> $GITHUB_ENV + echo "::add-mask::$AWS_ACCESS_KEY_ID" + echo "::add-mask::$AWS_SECRET_ACCESS_KEY" + echo "::add-mask::$AWS_SESSION_TOKEN" + + - name: Get appVersion from Chart.yaml + id: chart_version + run: | + APP_VERSION=$(grep 'appVersion:' charts/tsm-node/Chart.yaml | awk '{print $2}') + echo "IMAGE_TAG=$APP_VERSION" >> $GITHUB_ENV + + - name: Pull image from ECR + run: | + aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin $ECR_REPO + IMAGE_TAG=$(echo ${{ env.IMAGE_TAG }} | tr -d '\r') + docker pull $ECR_REPO:$IMAGE_TAG + + - name: Create kind ${{ matrix.k8s }} cluster + uses: helm/kind-action@v1.9.0 + with: + node_image: kindest/node:${{ matrix.k8s }} + version: v0.21.0 + + - name: Load image into kind cluster + run: | + IMAGE_TAG=$(echo ${{ env.IMAGE_TAG }} | tr -d '\r') + kind load docker-image $ECR_REPO:$IMAGE_TAG -n chart-testing + + - name: Inject ECR Repo and Image Tag into Values Files + run: | + IMAGE_TAG=$(echo ${{ env.IMAGE_TAG }} | tr -d '\r') + ./.github/inject-sensitive-values.sh charts/tsm-node/ci $ECR_REPO $IMAGE_TAG ${{ secrets.PRIVATE_KEY }} + + - name: Install chart-testing + uses: helm/chart-testing-action@v2.6.0 + + - name: Run chart install + run: ct install --config .github/ct.yaml + + - name: Cleanup AWS Credentials + if: always() + run: | + echo "AWS_ACCESS_KEY_ID=" >> $GITHUB_ENV + echo "AWS_SECRET_ACCESS_KEY=" >> $GITHUB_ENV + echo "AWS_SESSION_TOKEN=" >> $GITHUB_ENV + # Catch-all required check for test matrix test-success: needs: - lint-chart - lint-docs + - kubeval-chart + - install-chart runs-on: ubuntu-latest timeout-minutes: 1 if: always() @@ -61,3 +177,13 @@ jobs: needs.lint-docs.result == 'failure' || needs.lint-docs.result == 'cancelled' run: exit 1 + - name: Fail for failed or cancelled kubeval-chart + if: | + needs.kubeval-chart.result == 'failure' || + needs.kubeval-chart.result == 'cancelled' + run: exit 1 + - name: Fail for failed or cancelled install-chart + if: | + needs.install-chart.result == 'failure' || + needs.install-chart.result == 'cancelled' + run: exit 1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f9b91e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.bin \ No newline at end of file diff --git a/charts/tsm-node/Chart.yaml b/charts/tsm-node/Chart.yaml index e0e75e2..6610a6f 100644 --- a/charts/tsm-node/Chart.yaml +++ b/charts/tsm-node/Chart.yaml @@ -5,5 +5,5 @@ maintainers: - name: Blockdaemon email: sre@blockdaemon.com type: application -version: 0.1.0 +version: 0.1.1 appVersion: "61.0.2" diff --git a/charts/tsm-node/README.md b/charts/tsm-node/README.md index 4c285e9..4fdda05 100644 --- a/charts/tsm-node/README.md +++ b/charts/tsm-node/README.md @@ -1,6 +1,6 @@ # tsm-node -![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 61.0.2](https://img.shields.io/badge/AppVersion-61.0.2-informational?style=flat-square) +![Version: 0.1.1](https://img.shields.io/badge/Version-0.1.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 61.0.2](https://img.shields.io/badge/AppVersion-61.0.2-informational?style=flat-square) A Helm chart to deploy a Blockdaemon TSM node to kubernetes diff --git a/charts/tsm-node/ci/configFile-values.yaml b/charts/tsm-node/ci/configFile-values.yaml new file mode 100644 index 0000000..5b4e32e --- /dev/null +++ b/charts/tsm-node/ci/configFile-values.yaml @@ -0,0 +1,35 @@ +replicaCount: 1 +index: 0 + +config: + configFile: | + [Player] + Index = 0 + PrivateKey = "replace me" + + [Database] + DriverName = "sqlite3" + DataSourceName = "/tmp/tsmdb" + EncryptorMasterPassword = "ENCRYPTION_KEY" + + [SDKServer] + Port = 8080 +image: + repository: + pullPolicy: IfNotPresent + tag: "61.0.2" +sdkService: + type: NodePort + ports: + - port: 8080 + name: sdk + targetPort: 8080 + - port: 9000 + name: mpc + targetPort: 9000 + +mpcService: + enabled: false + +ingress: + enabled: false diff --git a/charts/tsm-node/ci/ingress.yaml b/charts/tsm-node/ci/ingress.yaml new file mode 100644 index 0000000..aeb8a76 --- /dev/null +++ b/charts/tsm-node/ci/ingress.yaml @@ -0,0 +1,46 @@ +replicaCount: 1 +index: 0 + +config: + configFile: | + [Player] + Index = 0 + PrivateKey = "replace me" + + [Database] + DriverName = "sqlite3" + DataSourceName = "/tmp/tsmdb" + EncryptorMasterPassword = "ENCRYPTION_KEY" + + [SDKServer] + Port = 8080 +image: + repository: + pullPolicy: IfNotPresent + tag: "61.0.2" +sdkService: + type: NodePort + ports: + - port: 8080 + name: sdk + targetPort: 8080 + - port: 9000 + name: mpc + targetPort: 9000 + +mpcService: + enabled: false + +ingress: + enabled: true + className: "alb" + annotations: + alb.ingress.kubernetes.io/scheme: internet-facing + alb.ingress.kubernetes.io/certificate-arn: + alb.ingress.kubernetes.io/healthcheck-path: /ping + hosts: + - host: "tsm0-sdk.exmaple.com" + paths: + - path: / + pathType: Prefix + port: 8080 diff --git a/charts/tsm-node/templates/deployment.yaml b/charts/tsm-node/templates/deployment.yaml index 0556084..3d538bc 100644 --- a/charts/tsm-node/templates/deployment.yaml +++ b/charts/tsm-node/templates/deployment.yaml @@ -48,7 +48,7 @@ spec: name: {{ .name }} protocol: TCP {{- end }} - livenessProbe: #TODO + livenessProbe: httpGet: path: /ping port: sdk