From 2ccf81ddff74a2673676ccab55cd4f7d7ec52e08 Mon Sep 17 00:00:00 2001 From: "Ben Hearsum (he/him)" Date: Wed, 1 May 2024 12:35:13 -0400 Subject: [PATCH] Switch CI, image building, image pushing to Taskgraph (#161) * Switch CI, image building, image pushing to Taskgraph This lets us easily use Kaniko to build * Remove remnants of pre-taskgraph docker build/push * Update README with basic deployment instructions --- .taskcluster.yml | 402 ++++++++++++------ Dockerfile | 18 - README.rst | 5 + docker.d/build_image.sh | 7 - docker.d/generate_version_json.sh | 17 - docker.d/push_image.sh | 32 -- taskcluster/config.yml | 22 + taskcluster/docker/k8s_autoscale/Dockerfile | 44 ++ taskcluster/docker/skopeo/Dockerfile | 60 +++ taskcluster/docker/skopeo/policy.json | 14 + taskcluster/docker/skopeo/push_image.sh | 47 ++ taskcluster/docker/test/Dockerfile | 23 + .../transforms/by_tasks_for.py | 18 + taskcluster/kinds/docker-image/kind.yml | 18 + taskcluster/kinds/push-image/kind.yml | 60 +++ taskcluster/kinds/test/kind.yml | 18 + 16 files changed, 611 insertions(+), 194 deletions(-) delete mode 100644 Dockerfile delete mode 100755 docker.d/build_image.sh delete mode 100755 docker.d/generate_version_json.sh delete mode 100755 docker.d/push_image.sh create mode 100644 taskcluster/config.yml create mode 100644 taskcluster/docker/k8s_autoscale/Dockerfile create mode 100644 taskcluster/docker/skopeo/Dockerfile create mode 100644 taskcluster/docker/skopeo/policy.json create mode 100755 taskcluster/docker/skopeo/push_image.sh create mode 100644 taskcluster/docker/test/Dockerfile create mode 100644 taskcluster/k8s_autoscale_taskgraph/transforms/by_tasks_for.py create mode 100644 taskcluster/kinds/docker-image/kind.yml create mode 100644 taskcluster/kinds/push-image/kind.yml create mode 100644 taskcluster/kinds/test/kind.yml diff --git a/.taskcluster.yml b/.taskcluster.yml index 6f0426a..c1894de 100644 --- a/.taskcluster.yml +++ b/.taskcluster.yml @@ -1,130 +1,292 @@ +# yamllint disable rule:line-length +# This file is rendered via JSON-e by +# - github events - https://github.com/taskcluster/taskcluster/tree/main/services/github +# - cron tasks - https://hg.mozilla.org/ci/ci-admin/file/default/build-decision/ +# - action tasks - taskcluster/taskgraph/actions/registry.py +--- version: 1 +reporting: checks-v1 +autoCancelPreviousChecks: true policy: - pullRequests: public + pullRequests: public tasks: - $let: - head_rev: - $if: 'tasks_for == "github-pull-request"' - then: ${event.pull_request.head.sha} - else: - $if: 'tasks_for == "github-push"' - then: ${event.after} - else: ${event.release.tag_name} + - $let: + trustDomain: "releng" + level: "1" + ownerEmail: + $switch: + 'tasks_for == "github-push"': '${event.pusher.email}' + 'tasks_for == "github-release"': '${event.sender.login}@users.noreply.github.com' + 'tasks_for[:19] == "github-pull-request"': '${event.pull_request.user.login}@users.noreply.github.com' + 'tasks_for in ["cron", "action", "pr-action"]': '${tasks_for}@noreply.mozilla.org' + baseRepoUrl: + $switch: + 'tasks_for[:19] == "github-pull-request"': '${event.pull_request.base.repo.html_url}' + 'tasks_for in ["cron", "action"]': '${repository.url}' + 'tasks_for == "pr-action"': '${repository.base_url}' + $default: '${event.repository.html_url}' + repoUrl: + $switch: + 'tasks_for[:19] == "github-pull-request"': '${event.pull_request.head.repo.html_url}' + 'tasks_for in ["cron", "action", "pr-action"]': '${repository.url}' + $default: '${event.repository.html_url}' + project: + $switch: + 'tasks_for in ["github-push", "github-release"]': '${event.repository.name}' + 'tasks_for[:19] == "github-pull-request"': '${event.pull_request.head.repo.name}' + 'tasks_for in ["cron", "action", "pr-action"]': '${repository.project}' + head_branch: + $switch: + 'tasks_for[:19] == "github-pull-request"': ${event.pull_request.head.ref} + 'tasks_for == "github-push"': ${event.ref} + 'tasks_for == "github-release"': '${event.release.target_commitish}' + 'tasks_for in ["cron", "action", "pr-action"]': '${push.branch}' + base_ref: + $switch: + 'tasks_for[:19] == "github-pull-request"': ${event.pull_request.base.ref} + 'tasks_for == "github-push" && event.base_ref': ${event.base_ref} + 'tasks_for == "github-push"': ${event.ref} + 'tasks_for == "github-release"': '' + 'tasks_for in ["cron", "action"]': '${push.branch}' + 'tasks_for == "pr-action"': '${push.base_branch}' + head_ref: + $switch: + 'tasks_for[:19] == "github-pull-request"': ${event.pull_request.head.ref} + 'tasks_for == "github-push"': ${event.ref} + 'tasks_for == "github-release"': ${event.release.tag_name} + 'tasks_for in ["cron", "action", "pr-action"]': '${push.branch}' + base_sha: + $switch: + 'tasks_for == "github-push"': '${event.before}' + 'tasks_for == "github-release"': '${event.release.target_commitish}' + 'tasks_for[:19] == "github-pull-request"': '${event.pull_request.base.sha}' + 'tasks_for in ["cron", "action", "pr-action"]': '${push.revision}' + head_sha: + $switch: + 'tasks_for == "github-push"': '${event.after}' + 'tasks_for == "github-release"': '${event.release.tag_name}' + 'tasks_for[:19] == "github-pull-request"': '${event.pull_request.head.sha}' + 'tasks_for in ["cron", "action", "pr-action"]': '${push.revision}' + ownTaskId: + $switch: + '"github" in tasks_for': {$eval: as_slugid("decision_task")} + 'tasks_for in ["cron", "action", "pr-action"]': '${ownTaskId}' + pullRequestAction: + $switch: + 'tasks_for[:19] == "github-pull-request"': ${event.action} + $default: 'UNDEFINED' + releaseAction: + $if: 'tasks_for == "github-release"' + then: ${event.action} + else: 'UNDEFINED' + isPullRequest: + $eval: 'tasks_for[:19] == "github-pull-request"' + in: + $let: + short_base_ref: + $switch: + 'base_ref[:10] == "refs/tags/"': '${base_ref[10:]}' + 'base_ref[:11] == "refs/heads/"': '${$base_ref[11:]}' + $default: '${base_ref}' + short_head_ref: + $switch: + 'head_ref[:10] == "refs/tags/"': '${head_ref[10:]}' + 'head_ref[:11] == "refs/heads/"': '${head_ref[11:]}' + $default: '${head_ref}' + in: + $if: > + tasks_for in ["action", "pr-action", "cron"] + || (tasks_for == "github-push" && short_head_ref == "main") + || (isPullRequest && pullRequestAction in ["opened", "reopened", "synchronize"]) + then: + taskId: {$if: 'tasks_for != "action" && tasks_for != "pr-action"', then: '${ownTaskId}'} + taskGroupId: + $if: 'tasks_for in ["action", "pr-action"]' + then: + '${action.taskGroupId}' + else: + '${ownTaskId}' # same as taskId; this is how automation identifies a decision task + schedulerId: '${trustDomain}-level-${level}' + created: {$fromNow: ''} + deadline: {$fromNow: '1 day'} + expires: {$fromNow: '1 year 1 second'} # 1 second so artifacts expire first + metadata: + $merge: + - owner: "${ownerEmail}" + source: "${repoUrl}/raw/${head_sha}/.taskcluster.yml" + - $switch: + 'tasks_for == "github-push" || isPullRequest': + name: "Decision Task" + description: 'The task that creates all of the other tasks in the task graph' + 'tasks_for == "action"': + name: "Action: ${action.title}" + description: | + ${action.description} - repo_url: - $if: 'tasks_for == "github-pull-request"' - then: ${event.pull_request.head.repo.html_url} - else: ${event.repository.html_url} + Action triggered by clientID `${clientId}` + 'tasks_for == "pr-action"': + name: "PR action: ${action.title}" + description: | + ${action.description} - owner: ${event.sender.login}@users.noreply.github.com + PR action triggered by clientID `${clientId}` + $default: + name: "Decision Task for cron job ${cron.job_name}" + description: 'Created by a [cron task](https://firefox-ci-tc.services.mozilla.com/tasks/${cron.task_id})' - push_docker_image: - $if: 'tasks_for == "github-pull-request"' - then: '0' - else: - $if: 'tasks_for == "github-push" && event.ref in ["refs/heads/master", "refs/heads/production"]' - then: '1' - else: '0' + provisionerId: "${trustDomain}-${level}" + workerType: "decision-gcp" - docker_tag: - $if: 'tasks_for == "github-pull-request"' - then: pull-request - else: - $if: 'tasks_for == "github-release"' - then: ${event.release.tag_name} - else: # push - $if: 'event.ref == "refs/heads/production"' - then: production - else: - $if: 'event.ref == "refs/heads/master"' - # Use the `:dev` docker tag for master pushes for the "nonprod" K8S - # cluster. It matches the scriptworkers' docker image naming schema. - then: dev - else: unknown + tags: + $switch: + 'tasks_for == "github-push" || isPullRequest': + createdForUser: "${ownerEmail}" + kind: decision-task + 'tasks_for in ["action", "pr-action"]': + createdForUser: '${ownerEmail}' + kind: 'action-callback' + 'tasks_for == "cron"': + kind: cron-task - worker_level: - $if: 'tasks_for == "github-pull-request"' - then: 't' - else: - $if: 'tasks_for == "github-push" && event.ref in ["refs/heads/master", "refs/heads/production"]' - then: '3' - else: 't' + routes: + $flatten: + - checks + - $switch: + 'tasks_for == "github-push"': + - "index.${trustDomain}.v2.${project}.latest.taskgraph.decision" + - "index.${trustDomain}.v2.${project}.revision.${head_sha}.taskgraph.decision" + 'tasks_for == "action"': + - "index.${trustDomain}.v2.${project}.revision.${head_sha}.taskgraph.actions.${ownTaskId}" + 'tasks_for == "cron"': + - "index.${trustDomain}.v2.${project}.latest.taskgraph.decision-${cron.job_name}" + - "index.${trustDomain}.v2.${project}.revision.${head_sha}.taskgraph.decision-${cron.job_name}" + # list each cron task on this revision, so actions can find them + - 'index.${trustDomain}.v2.${project}.revision.${head_sha}.cron.${ownTaskId}' + $default: [] - in: - $if: > - (tasks_for == "github-pull-request" && event.action in ["opened", "reopened", "synchronize"]) - || tasks_for == "github-push" - then: - - taskId: '${as_slugid("py311")}' - provisionerId: releng-t - workerType: linux-gcp - created: {$fromNow: ''} - deadline: {$fromNow: '4 hours'} - payload: - maxRunTime: 3600 - image: python:3.11 - command: - - sh - - -lxce - - >- - git clone ${repo_url} /src && - cd /src && - git config advice.detachedHead false && - git checkout ${head_rev} && - pip install tox && - tox -e py311 - metadata: - name: tox py311 (${docker_tag}) - description: code linting & unit tests on py311 (${docker_tag}) - owner: ${owner} - source: ${repo_url}/raw/${head_rev}/.taskcluster.yml + scopes: + $switch: + 'tasks_for in ["github-push"]': + - 'assume:repo:${repoUrl[8:]}:branch:${short_head_ref}' + 'isPullRequest': + - 'assume:repo:github.com/${event.pull_request.base.repo.full_name}:${tasks_for[7:]}' + 'tasks_for == "action"': + - 'assume:repo:${repoUrl[8:]}:action:${action.action_perm}' + 'tasks_for == "pr-action"': + - 'assume:repo:${repoUrl[8:]}:pr-action:${action.action_perm}' + $default: + - 'assume:repo:${repoUrl[8:]}:cron:${cron.job_name}' - - taskId: {$eval: as_slugid("docker-build-and-push")} - dependencies: - - '${as_slugid("py311")}' - created: {$fromNow: ''} - deadline: {$fromNow: '24 hours'} - provisionerId: 'releng-${worker_level}' - workerType: linux-gcp - routes: [] - payload: - maxRunTime: 3600 - # we need to run really old docker version because taskcluster is using - # really old version in their setup - # image: docker:stable - image: 'docker:1.6.2' - env: - DOCKERHUB_EMAIL: 'release+dockerhub+services@mozilla.com' - DOCKERHUB_USER: 'mozillarelengservices' - DOCKER_REPO: 'mozilla/releng-k8s-autoscale' - DOCKER_TAG: '${docker_tag}' - GIT_HEAD_REV: '${head_rev}' - PUSH_DOCKER_IMAGE: '${push_docker_image}' - REPO_URL: '${repo_url}' - SECRET_URL: 'http://taskcluster/secrets/v1/secret/project/releng/k8s-autoscale/deploy' - command: - - sh - - -lxce - - >- - cd /tmp && - wget ${repo_url}/archive/${head_rev}.tar.gz && - tar zxf ${head_rev}.tar.gz && - find . && - mv k8s-autoscale-${head_rev} /src && - cd /src && - ./docker.d/generate_version_json.sh && - ./docker.d/build_image.sh && - ./docker.d/push_image.sh - features: - dind: true - taskclusterProxy: true - scopes: - $if: 'push_docker_image == "0"' - then: [] - else: - - secrets:get:project/releng/k8s-autoscale/deploy - metadata: - name: k8s-autoscale docker build (${docker_tag}) - description: k8s-autoscale docker build (${docker_tag}) - owner: ${owner} - source: ${repo_url} + dependencies: [] + requires: all-completed + + priority: + $switch: + 'tasks_for == "cron"': low + 'tasks_for == "github-push"|| isPullRequest': very-low + $default: lowest # tasks_for in ['action', 'pr-action'] + retries: 5 + + payload: + $let: + normProject: + $eval: 'join(split(project, "-"), "_")' + normProjectUpper: + $eval: 'uppercase(join(split(project, "-"), "_"))' + in: + env: + # run-task uses these to check out the source; the inputs to + # `taskgraph decision` are all on the command line. + $merge: + - ${normProjectUpper}_BASE_REPOSITORY: '${baseRepoUrl}' + ${normProjectUpper}_BASE_REF: '${short_base_ref}' + ${normProjectUpper}_BASE_REV: '${base_sha}' + ${normProjectUpper}_HEAD_REPOSITORY: '${repoUrl}' + ${normProjectUpper}_HEAD_REF: '${short_head_ref}' + ${normProjectUpper}_HEAD_REV: '${head_sha}' + ${normProjectUpper}_REPOSITORY_TYPE: git + REPOSITORIES: + $json: + ${normProject}: ${normProject} + - $if: 'isPullRequest' + then: + ${normProjectUpper}_PULL_REQUEST_NUMBER: '${event.pull_request.number}' + - $if: 'tasks_for in ["action", "pr-action"]' + then: + ACTION_TASK_GROUP_ID: '${action.taskGroupId}' # taskGroupId of the target task + ACTION_TASK_ID: {$json: {$eval: 'taskId'}} # taskId of the target task (JSON-encoded) + ACTION_INPUT: {$json: {$eval: 'input'}} + ACTION_CALLBACK: '${action.cb_name}' + + cache: + "${trustDomain}-project-${project}-level-${level}-checkouts-sparse-v2": /builds/worker/checkouts + + features: + taskclusterProxy: true + + image: mozillareleases/taskgraph:decision-v8.0.0@sha256:057ed9e52635d8211fd9afa66402ed9fd7c57249f791128126860648316a5bec + maxRunTime: 1800 + + command: + - run-task + - '--${normProject}-checkout=/builds/worker/checkouts/src' + - '--' + - bash + - -cx + - $let: + extraArgs: {$if: 'tasks_for == "cron"', then: '${cron.quoted_args}', else: ''} + in: + $if: 'tasks_for in ["action", "pr-action"]' + then: > + cd /builds/worker/checkouts/src && + ln -s /builds/worker/artifacts artifacts && + taskgraph action-callback + else: > + cd /builds/worker/checkouts/src && + ln -s /builds/worker/artifacts artifacts && + taskgraph decision + --pushlog-id='0' + --pushdate='0' + --project='${project}' + --owner='${ownerEmail}' + --level='${level}' + --repository-type=git + --tasks-for='${tasks_for}' + --base-repository='${baseRepoUrl}' + --base-ref='${base_ref}' + --base-rev='${base_sha}' + --head-repository='${repoUrl}' + --head-ref='${head_ref}' + --head-rev='${head_sha}' + ${extraArgs} + + artifacts: + 'public': + type: 'directory' + path: '/builds/worker/artifacts' + expires: {$fromNow: '1 year'} + 'public/docker-contexts': + type: 'directory' + path: '/builds/worker/checkouts/src/docker-contexts' + # This needs to be at least the deadline of the + # decision task + the docker-image task deadlines. + # It is set to a week to allow for some time for + # debugging, but they are not useful long-term. + expires: {$fromNow: '7 day'} + + extra: + $merge: + - $if: 'tasks_for in ["action", "pr-action"]' + then: + parent: '${action.taskGroupId}' + action: + name: '${action.name}' + context: + taskGroupId: '${action.taskGroupId}' + taskId: {$eval: 'taskId'} + input: {$eval: 'input'} + clientId: {$eval: 'clientId'} + - $if: 'tasks_for == "cron"' + then: + cron: {$json: {$eval: 'cron'}} + - tasks_for: '${tasks_for}' diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index f914958..0000000 --- a/Dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -FROM python:3.11.3 - -RUN groupadd --gid 10001 app && \ - useradd -g app --uid 10001 --shell /usr/sbin/nologin --create-home --home-dir /app app - -COPY . /app - -WORKDIR /app - -RUN python -m venv /app -RUN ./bin/pip install -r requirements/base.txt -RUN ./bin/pip install -e . - -COPY docker.d/healthcheck /bin/healthcheck -COPY docker.d/init.sh /app/bin/init.sh - -USER app -CMD ["/app/bin/init.sh"] diff --git a/README.rst b/README.rst index 9576ff7..03f65f7 100644 --- a/README.rst +++ b/README.rst @@ -7,3 +7,8 @@ Autoscale scriptworkers in Kubernetes * Free software: MPL2 * Documentation: https://scriptworker-scripts.readthedocs.io/en/latest/scriptworkers-autoscaling.html +========== +Deployment +========== + +Push to `dev` to deploy to dev, and `production` to deploy to production. diff --git a/docker.d/build_image.sh b/docker.d/build_image.sh deleted file mode 100755 index 64499b7..0000000 --- a/docker.d/build_image.sh +++ /dev/null @@ -1,7 +0,0 @@ -#/bin/sh -set -e - -test $DOCKER_REPO -test $DOCKER_TAG - -docker build -f Dockerfile -t $DOCKER_REPO:$DOCKER_TAG . diff --git a/docker.d/generate_version_json.sh b/docker.d/generate_version_json.sh deleted file mode 100755 index 1263706..0000000 --- a/docker.d/generate_version_json.sh +++ /dev/null @@ -1,17 +0,0 @@ -#/bin/bash - -test $GIT_HEAD_REV -test $TASK_ID -test $TASKCLUSTER_ROOT_URL -test $REPO_URL - -cat > version.json < /root/.dockercfg -chmod 600 /root/.dockercfg - -echo "=== Pushing to docker hub ===" -docker push $DOCKER_REPO:$DOCKER_TAG -docker push $DOCKER_REPO:$DOCKER_ARCHIVE_TAG - -echo "=== Clean up ===" -rm -f /root/.dockercfg diff --git a/taskcluster/config.yml b/taskcluster/config.yml new file mode 100644 index 0000000..54852d1 --- /dev/null +++ b/taskcluster/config.yml @@ -0,0 +1,22 @@ +--- +trust-domain: "releng" +task-priority: low + +taskgraph: + cached-task-prefix: "releng.v2.k8s-autoscale" + repositories: + k8s_autoscale: + name: "k8s-autoscale" + +workers: + aliases: + test: + provisioner: '{trust-domain}-t' + implementation: docker-worker + os: linux + worker-type: linux-gcp + images: + provisioner: '{trust-domain}-{level}' + implementation: docker-worker + os: linux + worker-type: 'linux-gcp' diff --git a/taskcluster/docker/k8s_autoscale/Dockerfile b/taskcluster/docker/k8s_autoscale/Dockerfile new file mode 100644 index 0000000..d44b190 --- /dev/null +++ b/taskcluster/docker/k8s_autoscale/Dockerfile @@ -0,0 +1,44 @@ +ARG PYTHON_VERSION +FROM python:$PYTHON_VERSION + +RUN groupadd --gid 10001 app && \ + useradd -g app --uid 10001 --shell /usr/sbin/nologin --create-home --home-dir /app app + +COPY . /app + +WORKDIR /app + +# %include version.txt +COPY topsrcdir/version.txt /app/version.txt + +# %include docker.d +COPY topsrcdir/docker.d/healthcheck /bin/healthcheck +COPY topsrcdir/docker.d/init.sh /app/bin/init.sh + +# %include configs +# %include requirements +# %include MANIFEST.in +# %include README.rst +# %include pyproject.toml +# %include setup.py +# %include src +COPY topsrcdir/configs/ /app/configs/ +COPY topsrcdir/requirements/ /app/requirements/ +COPY topsrcdir/MANIFEST.in /app/ +COPY topsrcdir/README.rst /app/ +COPY topsrcdir/pyproject.toml /app/ +COPY topsrcdir/setup.py /app/ +COPY topsrcdir/src/ /app/src/ +RUN python -m venv /app +RUN ./bin/pip install -r /app/requirements/base.txt +RUN ./bin/pip install -e . + +RUN chown -R app:app /app + +# %include-run-task + +VOLUME /builds/worker/checkouts +VOLUME /builds/worker/.cache + +USER app +CMD ["/app/bin/init.sh"] diff --git a/taskcluster/docker/skopeo/Dockerfile b/taskcluster/docker/skopeo/Dockerfile new file mode 100644 index 0000000..efcd950 --- /dev/null +++ b/taskcluster/docker/skopeo/Dockerfile @@ -0,0 +1,60 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +FROM golang:1.14 as skopeo + +WORKDIR /go/src/ +RUN ["/usr/bin/git", "clone", "--no-checkout", "--depth=1", "--branch=v1.1.0", "https://github.com/containers/skopeo", "."] +RUN ["/usr/bin/git", "checkout", "63085f5bef1131aa9ec0907a5c8d66b67de7c4b2"] +ENV GO111MODULE=on CGO_ENABLED=0 +RUN ["/usr/local/go/bin/go", "build", \ + "-mod=vendor", "-o", "out/skopeo", \ + "-tags", "exclude_graphdriver_devicemapper exclude_graphdriver_btrfs containers_image_openpgp", \ + "-ldflags", "-extldflags \"-static\" -w -s", \ + "./cmd/skopeo"] + + +FROM golang:1.14 as umoci + +WORKDIR /go/src/ +RUN ["/usr/bin/git", "clone", "--no-checkout", "--depth=1", "--branch=v0.4.6", "https://github.com/opencontainers/umoci", "."] +RUN ["/usr/bin/git", "checkout", "5efa06acfb3bb4e65d2711cf5255970948e047cf"] +ENV GO111MODULE=on CGO_ENABLED=0 +RUN ["/usr/local/go/bin/go", "build", \ + "-mod=vendor", "-o", "out/umoci", \ + "-ldflags", "-extldflags \"-static\" -w -s", \ + "./cmd/umoci"] + + +FROM debian:buster + +# %include-run-task + +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update -qq \ + && apt-get dist-upgrade -y \ + && apt-get install -y jq zstd python3-minimal curl \ + && apt-get clean + +COPY push_image.sh /usr/local/bin/ +COPY policy.json /etc/containers/policy.json +RUN chmod a+x /usr/local/bin/push_image.sh +COPY --from=skopeo /go/src/out/skopeo /usr/local/bin/ +COPY --from=umoci /go/src/out/umoci /usr/local/bin/ + +# Add worker user +RUN mkdir /builds && \ + groupadd -g 1000 -o worker && \ + useradd -d /builds/worker -s /bin/bash -m worker -g 1000 -o -u 1000 && \ + mkdir /builds/worker/artifacts && \ + chown worker:worker /builds/worker/artifacts + +USER worker +ENV SHELL=/bin/bash \ + HOME=/builds/worker \ + USER=worker + +WORKDIR /builds/worker +# Set a default command useful for debugging +CMD ["/bin/bash", "--login"] diff --git a/taskcluster/docker/skopeo/policy.json b/taskcluster/docker/skopeo/policy.json new file mode 100644 index 0000000..f003844 --- /dev/null +++ b/taskcluster/docker/skopeo/policy.json @@ -0,0 +1,14 @@ +{ + "default": [{"type": "reject"}], + "transports": { + "oci": { + "": [{"type": "insecureAcceptAnything"}] + }, + "docker-archive": { + "": [{"type": "insecureAcceptAnything"}] + }, + "dir": { + "": [{"type": "insecureAcceptAnything"}] + } + } +} diff --git a/taskcluster/docker/skopeo/push_image.sh b/taskcluster/docker/skopeo/push_image.sh new file mode 100755 index 0000000..1c72279 --- /dev/null +++ b/taskcluster/docker/skopeo/push_image.sh @@ -0,0 +1,47 @@ +#!/bin/sh +set -e + +export +test $DOCKER_REPO +test $MOZ_FETCHES_DIR +test $SECRET_URL +test $TASKCLUSTER_ROOT_URL +test $TASK_ID +test $VCS_HEAD_REPOSITORY +test $VCS_HEAD_REV +test $DRYRUN + +cd $MOZ_FETCHES_DIR +unzstd image.tar.zst + +echo "=== Inserting version.json into image ===" +# Create an OCI copy of image in order umoci can patch it +skopeo copy docker-archive:image.tar oci:k8s_autoscale:final + +cat > version.json < $HOME/.dockercfg + + echo "=== Pushing to docker hub ===" + DOCKER_TAG="${DOCKER_TAG}-$(cat ./version.txt)-$(date +%Y%m%d%H%M%S)-${GIT_HEAD_REV}" + skopeo copy oci:k8s_autoscale:final docker://$DOCKER_REPO:$DOCKER_TAG + skopeo inspect docker://$DOCKER_REPO:$DOCKER_TAG +fi + +echo "=== Clean up ===" +rm -rf $HOME/.docker diff --git a/taskcluster/docker/test/Dockerfile b/taskcluster/docker/test/Dockerfile new file mode 100644 index 0000000..6c4e0f4 --- /dev/null +++ b/taskcluster/docker/test/Dockerfile @@ -0,0 +1,23 @@ +ARG PYTHON_VERSION +FROM python:$PYTHON_VERSION + +# Add worker user +RUN mkdir /builds && \ + groupadd -g 1000 -o worker && \ + useradd -d /builds/worker -s /bin/bash -m worker -g 1000 -o -u 1000 && \ + mkdir /builds/worker/artifacts && \ + chown worker:worker /builds/worker/artifacts + +RUN pip install tox + +# %include-run-task + +ENV SHELL=/bin/bash \ + HOME=/builds/worker \ + PATH=/builds/worker/.local/bin:$PATH + +VOLUME /builds/worker/checkouts +VOLUME /builds/worker/.cache + +# Set a default command useful for debugging +CMD ["/bin/bash", "--login"] diff --git a/taskcluster/k8s_autoscale_taskgraph/transforms/by_tasks_for.py b/taskcluster/k8s_autoscale_taskgraph/transforms/by_tasks_for.py new file mode 100644 index 0000000..102ab52 --- /dev/null +++ b/taskcluster/k8s_autoscale_taskgraph/transforms/by_tasks_for.py @@ -0,0 +1,18 @@ +from taskgraph.transforms.base import TransformSequence +from taskgraph.util.schema import resolve_keyed_by + +transforms = TransformSequence() + + +@transforms.add +def evaluate_keyed_by(config, jobs): + for job in jobs: + for item in ("worker.env.DRYRUN", "worker.env.DOCKER_TAG", "scopes"): + resolve_keyed_by( + job, + item, + item_name=job["description"], + **{"tasks-for": config.params["tasks_for"]}, + ) + + yield job diff --git a/taskcluster/kinds/docker-image/kind.yml b/taskcluster/kinds/docker-image/kind.yml new file mode 100644 index 0000000..9092b90 --- /dev/null +++ b/taskcluster/kinds/docker-image/kind.yml @@ -0,0 +1,18 @@ +--- +loader: taskgraph.loader.transform:loader + +transforms: + - taskgraph.transforms.docker_image:transforms + - taskgraph.transforms.cached_tasks:transforms + - taskgraph.transforms.task:transforms + +task-defaults: + args: + PYTHON_VERSION: "3.11.3" + +tasks: + k8s_autoscale: {} + + skopeo: {} + + test: {} diff --git a/taskcluster/kinds/push-image/kind.yml b/taskcluster/kinds/push-image/kind.yml new file mode 100644 index 0000000..0e360da --- /dev/null +++ b/taskcluster/kinds/push-image/kind.yml @@ -0,0 +1,60 @@ +--- +loader: taskgraph.loader.transform:loader + +transforms: + - taskgraph.transforms.task_context + - k8s_autoscale_taskgraph.transforms.by_tasks_for + - taskgraph.transforms.run + - taskgraph.transforms.task + +kind-dependencies: + - docker-image + +tasks: + k8s_autoscale: + description: push k8s-autoscale image + + task-context: + from-parameters: + head_repo: head_repository + head_rev: head_rev + head_ref: head_ref + substitution-fields: + - worker.env + + worker-type: images + worker: + taskcluster-proxy: true + docker-image: {in-tree: skopeo} + max-run-time: 1800 + env: + DRYRUN: + by-tasks-for: + github-push: "0" + default: "1" + DOCKER_REPO: mozilla/releng-k8s-autoscale + DOCKER_TAG: "{head_ref}" + SECRET_URL: http://taskcluster/secrets/v1/secret/project/releng/k8s-autoscale/deploy + VCS_HEAD_REPOSITORY: "{head_repo}" + VCS_HEAD_REV: "{head_rev}" + + run: + using: run-task + checkout: false + cache-dotcache: false + command: + - /usr/local/bin/push_image.sh + + dependencies: + image: build-docker-image-k8s_autoscale + + fetches: + image: + - artifact: image.tar.zst + extract: false + + scopes: + by-tasks-for: + github-push: + - secrets:get:project/releng/k8s-autoscale/deploy + default: [] diff --git a/taskcluster/kinds/test/kind.yml b/taskcluster/kinds/test/kind.yml new file mode 100644 index 0000000..6134edf --- /dev/null +++ b/taskcluster/kinds/test/kind.yml @@ -0,0 +1,18 @@ +--- + +tasks: + python: + description: test k8s-autoscale + worker-type: test + worker: + docker-image: {"in-tree": "test"} + max-run-time: 1800 + run: + using: run-task + checkout: + k8s_autoscale: {} + cwd: '{checkout}' + command: + - tox + - -e + - py311