diff --git a/.github/workflows/gitlab-container-image.yml b/.github/workflows/gitlab-container-image.yml new file mode 100644 index 0000000..093eb16 --- /dev/null +++ b/.github/workflows/gitlab-container-image.yml @@ -0,0 +1,48 @@ +--- +name: Build & Push GitLab Container Image + +"on": + push: + branches: + - main + tags: + - v* + pull_request: {} + +jobs: + build: + runs-on: ubuntu-latest + env: + IMAGE: ${{ github.repository }}/gitlab + steps: + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Set image version latest + if: github.ref == 'refs/heads/main' + run: echo "VERSION=latest" >> ${GITHUB_ENV} + - name: Set image version for PRs to branch name + if: github.event_name == 'pull_request' + run: echo "VERSION=${GITHUB_REF_NAME//\//-}" >> ${GITHUB_ENV} + - name: Set image version from tag + if: startsWith(github.ref, 'refs/tags/v') + run: echo "VERSION=$(echo ${GITHUB_REF#refs/tags/})" >> ${GITHUB_ENV} + + - name: Login to ghcr.io + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push + id: docker_build + uses: docker/build-push-action@v6 + with: + context: '{{defaultContext}}:gitlab' + platforms: linux/amd64,linux/arm64 + push: true + tags: 'ghcr.io/${{ env.IMAGE }}:${{ env.VERSION }}' diff --git a/gitlab/Dockerfile b/gitlab/Dockerfile new file mode 100644 index 0000000..06caac4 --- /dev/null +++ b/gitlab/Dockerfile @@ -0,0 +1,5 @@ +FROM docker.io/library/alpine:latest + +RUN apk add --no-cache yamllint jsonnet jq curl +COPY ./bin/* /usr/local/bin/ +COPY ./commodore-compile.jsonnet /opt/commodore-compile.jsonnet diff --git a/gitlab/bin/step-render-pipeline b/gitlab/bin/step-render-pipeline new file mode 100755 index 0000000..763bb19 --- /dev/null +++ b/gitlab/bin/step-render-pipeline @@ -0,0 +1,19 @@ +#!/bin/sh +set -e -u -x + +cluster_catalog_urls="" +for c in ${CLUSTERS}; do + r=$(curl -sH"Authorization: Bearer ${COMMODORE_API_TOKEN}" "${COMMODORE_API_URL}/clusters/${c}" | jq -r .gitRepo.url) + cluster_catalog_urls="${cluster_catalog_urls}${c}=${r} " +done + +jsonnet \ + --ext-str clusters="${CLUSTERS}" \ + --ext-str memory_limits="${MEMORY_LIMITS:-}" \ + --ext-str cpu_limits="${CPU_LIMITS:-}" \ + --ext-str cpu_requests="${CPU_REQUESTS:-}" \ + --ext-str cluster_catalog_urls="${cluster_catalog_urls}" \ + --ext-str server_fqdn="${CI_SERVER_FQDN}" \ + --ext-str server_ssh_host="${CI_SERVER_SHELL_SSH_HOST}" \ + /opt/commodore-compile.jsonnet \ + > generated-commodore-compile.yml diff --git a/gitlab/bin/step-yamllint b/gitlab/bin/step-yamllint new file mode 100755 index 0000000..a0895ba --- /dev/null +++ b/gitlab/bin/step-yamllint @@ -0,0 +1,9 @@ +#!/bin/sh +set -e -u -x + +if [ "$(find . -name '.yamllint' -or -name '.yamllint.y*ml' | wc -l)" -ge "1" ]; then + # yamllint will autoload this file + exec yamllint . +else + exec yamllint -d "$YAMLLINT_DEFAULTS" . +fi diff --git a/gitlab/commodore-compile.jsonnet b/gitlab/commodore-compile.jsonnet new file mode 100644 index 0000000..df84f89 --- /dev/null +++ b/gitlab/commodore-compile.jsonnet @@ -0,0 +1,127 @@ +local commodore_version = 'v1.22.1'; +local commodore_image = 'docker.io/projectsyn/commodore:' + commodore_version; + +local to_array(param) = std.foldl( + function(obj, elem) + local parts = std.split(elem, '='); + obj { + [parts[0]]: parts[1], + }, + std.split(std.extVar(std.rstripChars(param, ' ')), ' '), + {}, +); + +local gitlab_fqdn = std.extVar('server_fqdn'); +local gitlab_ssh_host = std.extVar('server_ssh_host'); +local clusters = std.split(std.extVar('clusters'), ' '); +local cluster_catalog_urls = to_array('cluster_catalog_urls'); +local memory_limits = to_array('memory_limits'); +local cpu_limits = to_array('cpu_limits'); +local cpu_requests = to_array('cpu_requests'); + +local gitInsteadOf(cluster) = + local cluster_access_token = '${ACCESS_TOKEN_%s}' % std.strReplace(cluster, '-', '_'); + local cluster_repo = cluster_catalog_urls[cluster]; + local ssh_gitlab = 'ssh://git@%s/' % gitlab_ssh_host; + local catalog_path = if std.startsWith(cluster_repo, ssh_gitlab) then + // prefix ssh://git@ 0 == ssh, 1 == '', 2 == + std.join('/', std.split(cluster_repo, '/')[3:]); + + local catalogInsteadOf = + if catalog_path != null then + [ + 'git config --global url."https://gitlab-ci-token:%(access_token)s@%(gitlab_fqdn)s/%(catalog_path)s".insteadOf ssh://git@${CI_SERVER_SHELL_SSH_HOST}/%(catalog_path)s' % { + access_token: cluster_access_token, + catalog_path: catalog_path, + gitlab_fqdn: gitlab_fqdn, + }, + ] + else + []; + + [ + 'git config --global url."https://gitlab-ci-token:${CI_JOB_TOKEN}@%(gitlab_fqdn)s".insteadOf ssh://git@${CI_SERVER_SHELL_SSH_HOST}' % { + gitlab_fqdn: gitlab_fqdn, + }, + ] + catalogInsteadOf; + +local compile_job(cluster) = + { + stage: 'build', + image: + { + name: commodore_image, + }, + variables: + { + KUBERNETES_MEMORY_LIMIT: std.get(memory_limits, cluster, '2Gi'), + KUBERNETES_CPU_LIMIT: std.get(cpu_limits, cluster, '2'), + KUBERNETES_CPU_REQUEST: std.get(cpu_requests, cluster, '800m'), + }, + before_script: + [ + 'install --directory --mode=0700 ~/.ssh', + 'echo "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts', + 'echo "$SSH_CONFIG" >> ~/.ssh/config', + ], + script: + gitInsteadOf(cluster) + [ + '/usr/local/bin/entrypoint.sh commodore catalog compile --tenant-repo-revision-override $CI_COMMIT_SHA ' + cluster, + '(cd catalog/ && git --no-pager diff --staged --output ../diff.txt)', + ], + artifacts: + { + paths: + [ + 'diff.txt', + ], + expire_in: '1 week', + }, + rules: + [ + { 'if': '$CI_COMMIT_REF_NAME != $CI_DEFAULT_BRANCH' }, + ], + }; + +local deploy_job(cluster) = + { + stage: 'deploy', + variables: + { + KUBERNETES_MEMORY_LIMIT: std.get(memory_limits, cluster, default='2Gi'), + KUBERNETES_CPU_LIMIT: std.get(cpu_limits, cluster, default='2'), + KUBERNETES_CPU_REQUEST: std.get(cpu_requests, cluster, default='800m'), + }, + image: + { + name: commodore_image, + }, + before_script: + [ + 'install --directory --mode=0700 ~/.ssh', + 'echo "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts', + 'echo "$SSH_CONFIG" >> ~/.ssh/config', + ], + script: + gitInsteadOf(cluster) + [ + '/usr/local/bin/entrypoint.sh commodore catalog compile --push ' + cluster, + ], + rules: + [ + { 'if': '$CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH' }, + ], + }; + +local compile = + { + [x + '_compile']: compile_job(x) + for x in clusters + }; + +local deploy = + { + [x + '_deploy']: deploy_job(x) + for x in clusters + }; + +compile + deploy