438 lines
20 KiB
YAML
438 lines
20 KiB
YAML
apiVersion: tekton.dev/v1
|
|
kind: Pipeline
|
|
metadata:
|
|
name: agentrun-v01-ci-image-publish
|
|
namespace: agentrun-ci
|
|
labels:
|
|
app.kubernetes.io/part-of: agentrun
|
|
agentrun.pikastech.local/lane: v0.1
|
|
spec:
|
|
params:
|
|
- name: git-url
|
|
type: string
|
|
default: git@github.com:pikasTech/agentrun.git
|
|
- name: git-read-url
|
|
type: string
|
|
default: http://git-mirror-http.devops-infra.svc.cluster.local/pikasTech/agentrun.git
|
|
- name: git-write-url
|
|
type: string
|
|
default: http://git-mirror-write.devops-infra.svc.cluster.local/pikasTech/agentrun.git
|
|
- name: source-branch
|
|
type: string
|
|
default: v0.1
|
|
- name: gitops-branch
|
|
type: string
|
|
default: v0.1-gitops
|
|
- name: revision
|
|
type: string
|
|
- name: registry-prefix
|
|
type: string
|
|
default: 127.0.0.1:5000/agentrun
|
|
- name: tools-image
|
|
type: string
|
|
default: oven/bun:1.2.15-alpine
|
|
workspaces:
|
|
- name: source
|
|
- name: git-ssh
|
|
tasks:
|
|
- name: prepare-source
|
|
workspaces:
|
|
- name: source
|
|
workspace: source
|
|
taskSpec:
|
|
params:
|
|
- name: git-read-url
|
|
- name: revision
|
|
- name: tools-image
|
|
workspaces:
|
|
- name: source
|
|
steps:
|
|
- name: clone-and-check
|
|
image: $(params.tools-image)
|
|
env:
|
|
- name: HTTP_PROXY
|
|
value: http://127.0.0.1:10808
|
|
- name: HTTPS_PROXY
|
|
value: http://127.0.0.1:10808
|
|
- name: NO_PROXY
|
|
value: hyueapi.com,.hyueapi.com,127.0.0.1,localhost,::1,10.42.0.0/16,10.43.0.0/16,.svc,.cluster.local
|
|
- name: http_proxy
|
|
value: http://127.0.0.1:10808
|
|
- name: https_proxy
|
|
value: http://127.0.0.1:10808
|
|
- name: no_proxy
|
|
value: hyueapi.com,.hyueapi.com,127.0.0.1,localhost,::1,10.42.0.0/16,10.43.0.0/16,.svc,.cluster.local
|
|
- name: GIT_TERMINAL_PROMPT
|
|
value: "0"
|
|
script: |
|
|
#!/bin/sh
|
|
set -eu
|
|
apk add --no-cache git curl
|
|
rm -rf /workspace/source/repo
|
|
mkdir -p /workspace/source/repo
|
|
git init /workspace/source/repo
|
|
cd /workspace/source/repo
|
|
git remote add origin "$(params.git-read-url)"
|
|
git fetch --depth=1 origin "$(params.revision)"
|
|
git checkout --detach FETCH_HEAD
|
|
test "$(git rev-parse HEAD)" = "$(params.revision)"
|
|
bun install --frozen-lockfile
|
|
bun run check
|
|
bun scripts/agentrun-gitops-render.ts --out /tmp/agentrun-gitops-render-check --source-commit "$(params.revision)" --check
|
|
AGENTRUN_SELFTEST_CODEX_COMMAND="$(command -v bun)" \
|
|
AGENTRUN_SELFTEST_CODEX_ARGS="[\"$PWD/src/selftest/fake-codex-app-server.ts\"]" \
|
|
bun run self-test
|
|
params:
|
|
- name: git-read-url
|
|
value: $(params.git-read-url)
|
|
- name: revision
|
|
value: $(params.revision)
|
|
- name: tools-image
|
|
value: $(params.tools-image)
|
|
- name: plan-artifacts
|
|
runAfter: [prepare-source]
|
|
workspaces:
|
|
- name: source
|
|
workspace: source
|
|
taskSpec:
|
|
params:
|
|
- name: git-read-url
|
|
- name: gitops-branch
|
|
- name: revision
|
|
- name: registry-prefix
|
|
results:
|
|
- name: env-identity
|
|
- name: build-count
|
|
- name: reuse-count
|
|
- name: summary
|
|
workspaces:
|
|
- name: source
|
|
steps:
|
|
- name: plan
|
|
image: oven/bun:1.2.15-alpine
|
|
env:
|
|
- name: GIT_TERMINAL_PROMPT
|
|
value: "0"
|
|
script: |
|
|
#!/bin/sh
|
|
set -eu
|
|
apk add --no-cache git nodejs
|
|
cd /workspace/source/repo
|
|
node <<'NODE' > /workspace/source/env-identity
|
|
const { createHash } = require("node:crypto");
|
|
const { readFileSync } = require("node:fs");
|
|
const inputs = [
|
|
["baseImage", "oven/bun:1.2.15-alpine"],
|
|
["systemPackages", "ca-certificates git kubectl nodejs openssh-client"],
|
|
["containerfile", readFileSync("deploy/container/Containerfile", "utf8")],
|
|
["bootScript", readFileSync("deploy/runtime/boot/agentrun-boot.sh", "utf8")],
|
|
["bootMgr", readFileSync("deploy/runtime/boot/agentrun-mgr.sh", "utf8")],
|
|
["bootRunner", readFileSync("deploy/runtime/boot/agentrun-runner.sh", "utf8")],
|
|
["packageJson", readFileSync("package.json", "utf8")],
|
|
["bunLock", readFileSync("bun.lock", "utf8")],
|
|
["tsconfig", readFileSync("tsconfig.json", "utf8")],
|
|
];
|
|
process.stdout.write(createHash("sha256").update(JSON.stringify(inputs)).digest("hex").slice(0, 20));
|
|
NODE
|
|
env_identity="$(cat /workspace/source/env-identity)"
|
|
rm -rf /workspace/source/gitops-prev
|
|
if git clone --depth=1 --branch "$(params.gitops-branch)" "$(params.git-read-url)" /workspace/source/gitops-prev >/tmp/agentrun-prev-gitops.log 2>&1; then
|
|
prev_catalog=/workspace/source/gitops-prev/deploy/artifact-catalog.v01.json
|
|
else
|
|
prev_catalog=/dev/null
|
|
fi
|
|
AGENTRUN_ENV_IDENTITY="$env_identity" \
|
|
AGENTRUN_PREV_CATALOG="$prev_catalog" \
|
|
AGENTRUN_REVISION="$(params.revision)" \
|
|
AGENTRUN_GITOPS_BRANCH="$(params.gitops-branch)" \
|
|
AGENTRUN_REGISTRY_PREFIX="$(params.registry-prefix)" \
|
|
node <<'NODE'
|
|
const { readFileSync, writeFileSync } = require("node:fs");
|
|
const envIdentity = process.env.AGENTRUN_ENV_IDENTITY;
|
|
const revision = process.env.AGENTRUN_REVISION;
|
|
const gitopsBranch = process.env.AGENTRUN_GITOPS_BRANCH;
|
|
let previousService = null;
|
|
try {
|
|
const catalog = JSON.parse(readFileSync(process.env.AGENTRUN_PREV_CATALOG, "utf8"));
|
|
previousService = (catalog.services || []).find((item) => item.serviceId === "agentrun-mgr" && item.envIdentity === envIdentity && /^sha256:[a-f0-9]{64}$/.test(item.envDigest || item.digest || "")) || null;
|
|
} catch {}
|
|
const reused = previousService !== null;
|
|
const plan = {
|
|
lane: "v0.1",
|
|
sourceBranch: "v0.1",
|
|
gitopsBranch,
|
|
sourceCommitId: revision,
|
|
envIdentity,
|
|
toolchainInputs: ["oven/bun:1.2.15-alpine", "deploy/container/Containerfile", "deploy/runtime/boot/*.sh", "package.json", "bun.lock", "tsconfig.json", "apk:ca-certificates git kubectl nodejs openssh-client"],
|
|
buildServices: reused ? [] : ["agentrun-mgr"],
|
|
reusedServices: reused ? ["agentrun-mgr"] : [],
|
|
unsafeReuseServices: [],
|
|
previousService,
|
|
summary: `build=${reused ? 0 : 1} reuse=${reused ? 1 : 0} unsafeReuse=0`,
|
|
};
|
|
writeFileSync("/workspace/source/ci-plan.json", `${JSON.stringify(plan, null, 2)}\n`);
|
|
writeFileSync("/tekton/results/env-identity", envIdentity);
|
|
writeFileSync("/tekton/results/build-count", String(plan.buildServices.length));
|
|
writeFileSync("/tekton/results/reuse-count", String(plan.reusedServices.length));
|
|
writeFileSync("/tekton/results/summary", plan.summary);
|
|
console.log(JSON.stringify({ event: "agentrun-ci-plan", status: "succeeded", sourceCommitId: revision, envIdentity, buildServices: plan.buildServices, reusedServices: plan.reusedServices, unsafeReuseServices: [], summary: plan.summary }));
|
|
NODE
|
|
params:
|
|
- name: git-read-url
|
|
value: $(params.git-read-url)
|
|
- name: gitops-branch
|
|
value: $(params.gitops-branch)
|
|
- name: revision
|
|
value: $(params.revision)
|
|
- name: registry-prefix
|
|
value: $(params.registry-prefix)
|
|
- name: image-publish
|
|
runAfter: [plan-artifacts]
|
|
workspaces:
|
|
- name: source
|
|
workspace: source
|
|
taskSpec:
|
|
params:
|
|
- name: revision
|
|
- name: registry-prefix
|
|
results:
|
|
- name: image
|
|
- name: digest
|
|
- name: repository-digest
|
|
- name: env-identity
|
|
- name: status
|
|
sidecars:
|
|
- name: buildkitd
|
|
image: moby/buildkit:rootless
|
|
args:
|
|
- --addr
|
|
- unix:///workspace/buildkit-run/buildkitd.sock
|
|
- --oci-worker-no-process-sandbox
|
|
env:
|
|
- name: HTTP_PROXY
|
|
value: http://127.0.0.1:10808
|
|
- name: HTTPS_PROXY
|
|
value: http://127.0.0.1:10808
|
|
- name: NO_PROXY
|
|
value: hyueapi.com,.hyueapi.com,127.0.0.1,localhost,::1,10.42.0.0/16,10.43.0.0/16,.svc,.cluster.local
|
|
- name: http_proxy
|
|
value: http://127.0.0.1:10808
|
|
- name: https_proxy
|
|
value: http://127.0.0.1:10808
|
|
- name: no_proxy
|
|
value: hyueapi.com,.hyueapi.com,127.0.0.1,localhost,::1,10.42.0.0/16,10.43.0.0/16,.svc,.cluster.local
|
|
securityContext:
|
|
allowPrivilegeEscalation: true
|
|
appArmorProfile:
|
|
type: Unconfined
|
|
seccompProfile:
|
|
type: Unconfined
|
|
runAsUser: 1000
|
|
runAsGroup: 1000
|
|
volumeMounts:
|
|
- name: buildkit-run
|
|
mountPath: /workspace/buildkit-run
|
|
steps:
|
|
- name: prepare-buildctl
|
|
image: moby/buildkit:rootless
|
|
script: |
|
|
#!/bin/sh
|
|
set -eu
|
|
mkdir -p /workspace/buildkit-bin
|
|
cp /usr/bin/buildctl /workspace/buildkit-bin/buildctl
|
|
chmod +x /workspace/buildkit-bin/buildctl
|
|
volumeMounts:
|
|
- name: buildkit-bin
|
|
mountPath: /workspace/buildkit-bin
|
|
- name: build-or-reuse
|
|
image: oven/bun:1.2.15-alpine
|
|
env:
|
|
- name: HTTP_PROXY
|
|
value: http://127.0.0.1:10808
|
|
- name: HTTPS_PROXY
|
|
value: http://127.0.0.1:10808
|
|
- name: NO_PROXY
|
|
value: hyueapi.com,.hyueapi.com,127.0.0.1,localhost,::1,10.42.0.0/16,10.43.0.0/16,.svc,.cluster.local
|
|
script: |
|
|
#!/bin/sh
|
|
set -eu
|
|
apk add --no-cache curl nodejs
|
|
cd /workspace/source/repo
|
|
env_identity="$(cat /workspace/source/env-identity)"
|
|
if node -e 'const p=require("/workspace/source/ci-plan.json"); process.exit((p.buildServices||[]).length===0 ? 0 : 1)'; then
|
|
node <<'NODE'
|
|
const { readFileSync, writeFileSync } = require("node:fs");
|
|
const plan = JSON.parse(readFileSync("/workspace/source/ci-plan.json", "utf8"));
|
|
const service = plan.previousService;
|
|
if (!service) throw new Error("reuse plan missing previousService");
|
|
const image = service.envImage || service.image;
|
|
const digest = service.envDigest || service.digest;
|
|
const repositoryDigest = service.envRepositoryDigest || service.repositoryDigest;
|
|
writeFileSync("/tekton/results/image", image);
|
|
writeFileSync("/tekton/results/digest", digest);
|
|
writeFileSync("/tekton/results/repository-digest", repositoryDigest);
|
|
writeFileSync("/tekton/results/env-identity", plan.envIdentity);
|
|
writeFileSync("/tekton/results/status", "reused");
|
|
console.log(JSON.stringify({ event: "agentrun-env-image", status: "reused", serviceId: "agentrun-mgr", envIdentity: plan.envIdentity, image, digest, summary: plan.summary }));
|
|
NODE
|
|
exit 0
|
|
fi
|
|
image="$(params.registry-prefix)/agentrun-mgr-env:${env_identity}"
|
|
buildctl=/workspace/buildkit-bin/buildctl
|
|
for attempt in $(seq 1 60); do
|
|
if "$buildctl" --addr unix:///workspace/buildkit-run/buildkitd.sock debug workers >/dev/null 2>&1; then break; fi
|
|
sleep 1
|
|
done
|
|
"$buildctl" --addr unix:///workspace/buildkit-run/buildkitd.sock build \
|
|
--frontend dockerfile.v0 \
|
|
--local context=. \
|
|
--local dockerfile=deploy/container \
|
|
--opt filename=Containerfile \
|
|
--opt build-arg:HTTP_PROXY=http://127.0.0.1:10808 \
|
|
--opt build-arg:HTTPS_PROXY=http://127.0.0.1:10808 \
|
|
--opt build-arg:NO_PROXY=hyueapi.com,.hyueapi.com,127.0.0.1,localhost,::1,10.42.0.0/16,10.43.0.0/16,.svc,.cluster.local \
|
|
--output type=image,name="$image",push=true,registry.insecure=true
|
|
digest="$(curl -fsSI -H "Accept: application/vnd.docker.distribution.manifest.v2+json" "http://127.0.0.1:5000/v2/agentrun/agentrun-mgr-env/manifests/$env_identity" | awk -F': ' 'tolower($1)=="docker-content-digest" {gsub(/\r/,"",$2); print $2; exit}')"
|
|
test -n "$digest"
|
|
curl -fsSI -H "Accept: application/vnd.docker.distribution.manifest.v2+json" "http://127.0.0.1:5000/v2/agentrun/agentrun-mgr-env/manifests/$digest" >/dev/null
|
|
printf '%s' "$image" > /tekton/results/image
|
|
printf '%s' "$digest" > /tekton/results/digest
|
|
printf '%s' "$(params.registry-prefix)/agentrun-mgr-env@$digest" > /tekton/results/repository-digest
|
|
printf '%s' "$env_identity" > /tekton/results/env-identity
|
|
printf '%s' built > /tekton/results/status
|
|
printf '{"event":"agentrun-env-image","status":"built","serviceId":"agentrun-mgr","envIdentity":"%s","image":"%s","digest":"%s"}\n' "$env_identity" "$image" "$digest"
|
|
volumeMounts:
|
|
- name: buildkit-bin
|
|
mountPath: /workspace/buildkit-bin
|
|
- name: buildkit-run
|
|
mountPath: /workspace/buildkit-run
|
|
volumes:
|
|
- name: buildkit-bin
|
|
emptyDir: {}
|
|
- name: buildkit-run
|
|
emptyDir: {}
|
|
params:
|
|
- name: revision
|
|
value: $(params.revision)
|
|
- name: registry-prefix
|
|
value: $(params.registry-prefix)
|
|
- name: gitops-promote
|
|
runAfter: [image-publish]
|
|
workspaces:
|
|
- name: source
|
|
workspace: source
|
|
taskSpec:
|
|
params:
|
|
- name: git-write-url
|
|
- name: gitops-branch
|
|
- name: revision
|
|
- name: registry-prefix
|
|
- name: image
|
|
- name: digest
|
|
- name: repository-digest
|
|
- name: env-identity
|
|
- name: image-status
|
|
workspaces:
|
|
- name: source
|
|
steps:
|
|
- name: promote
|
|
image: oven/bun:1.2.15-alpine
|
|
env:
|
|
- name: GIT_TERMINAL_PROMPT
|
|
value: "0"
|
|
- name: AGENTRUN_IMAGE
|
|
value: $(params.image)
|
|
- name: AGENTRUN_DIGEST
|
|
value: $(params.digest)
|
|
- name: AGENTRUN_REPOSITORY_DIGEST
|
|
value: $(params.repository-digest)
|
|
- name: AGENTRUN_ENV_IDENTITY
|
|
value: $(params.env-identity)
|
|
- name: AGENTRUN_IMAGE_STATUS
|
|
value: $(params.image-status)
|
|
- name: AGENTRUN_REVISION
|
|
value: $(params.revision)
|
|
- name: AGENTRUN_GITOPS_BRANCH
|
|
value: $(params.gitops-branch)
|
|
script: |
|
|
#!/bin/sh
|
|
set -eu
|
|
apk add --no-cache git openssh-client nodejs
|
|
cd /workspace/source/repo
|
|
node <<'NODE' > /workspace/source/artifact-catalog.v01.json
|
|
const { readFileSync } = require("node:fs");
|
|
const plan = JSON.parse(readFileSync("/workspace/source/ci-plan.json", "utf8"));
|
|
const service = {
|
|
serviceId: "agentrun-mgr",
|
|
artifactKind: "env-reuse",
|
|
status: process.env.AGENTRUN_IMAGE_STATUS,
|
|
image: process.env.AGENTRUN_IMAGE,
|
|
digest: process.env.AGENTRUN_DIGEST,
|
|
repositoryDigest: process.env.AGENTRUN_REPOSITORY_DIGEST,
|
|
imageTag: process.env.AGENTRUN_ENV_IDENTITY,
|
|
envIdentity: process.env.AGENTRUN_ENV_IDENTITY,
|
|
envImage: process.env.AGENTRUN_IMAGE,
|
|
envDigest: process.env.AGENTRUN_DIGEST,
|
|
envRepositoryDigest: process.env.AGENTRUN_REPOSITORY_DIGEST,
|
|
bootCommit: process.env.AGENTRUN_REVISION,
|
|
bootScript: "deploy/runtime/boot/agentrun-boot.sh",
|
|
provenance: {
|
|
sourceCommitId: process.env.AGENTRUN_REVISION,
|
|
toolchainInputs: plan.toolchainInputs,
|
|
buildServices: plan.buildServices,
|
|
reusedServices: plan.reusedServices,
|
|
unsafeReuseServices: plan.unsafeReuseServices,
|
|
previousSourceCommitId: plan.previousService?.bootCommit || null,
|
|
},
|
|
};
|
|
const catalog = {
|
|
lane: "v0.1",
|
|
sourceBranch: "v0.1",
|
|
gitopsBranch: process.env.AGENTRUN_GITOPS_BRANCH,
|
|
sourceCommitId: process.env.AGENTRUN_REVISION,
|
|
summary: plan.summary,
|
|
services: [service],
|
|
};
|
|
console.log(JSON.stringify(catalog, null, 2));
|
|
NODE
|
|
rm -rf /workspace/source/rendered
|
|
bun scripts/agentrun-gitops-render.ts --out /workspace/source/rendered --source-commit "$(params.revision)" --registry-prefix "$(params.registry-prefix)" --catalog /workspace/source/artifact-catalog.v01.json --require-catalog
|
|
rm -rf /workspace/source/gitops
|
|
git clone --branch "$(params.gitops-branch)" "$(params.git-write-url)" /workspace/source/gitops || {
|
|
git clone "$(params.git-write-url)" /workspace/source/gitops
|
|
cd /workspace/source/gitops
|
|
git checkout --orphan "$(params.gitops-branch)"
|
|
git rm -rf . >/dev/null 2>&1 || true
|
|
}
|
|
cd /workspace/source/gitops
|
|
git config user.email agentrun-ci@g14.local
|
|
git config user.name agentrun-ci
|
|
mkdir -p deploy/gitops/g14 deploy
|
|
rm -rf deploy/gitops/g14/runtime-v01 deploy/gitops/g14/argocd
|
|
cp -a /workspace/source/rendered/runtime-v01 deploy/gitops/g14/runtime-v01
|
|
cp -a /workspace/source/rendered/argocd deploy/gitops/g14/argocd
|
|
cp /workspace/source/rendered/artifact-catalog.v01.json deploy/artifact-catalog.v01.json
|
|
git add deploy
|
|
git commit -m "gitops: promote agentrun v0.1 $(params.revision)" || true
|
|
git push origin "$(params.gitops-branch)"
|
|
printf '{"event":"agentrun-gitops-promote","status":"succeeded","sourceCommitId":"%s","envIdentity":"%s","imageStatus":"%s","summary":%s}\n' "$(params.revision)" "$(params.env-identity)" "$(params.image-status)" "$(node -e 'const p=require("/workspace/source/ci-plan.json"); console.log(JSON.stringify(p.summary))')"
|
|
params:
|
|
- name: git-write-url
|
|
value: $(params.git-write-url)
|
|
- name: gitops-branch
|
|
value: $(params.gitops-branch)
|
|
- name: revision
|
|
value: $(params.revision)
|
|
- name: registry-prefix
|
|
value: $(params.registry-prefix)
|
|
- name: image
|
|
value: $(tasks.image-publish.results.image)
|
|
- name: digest
|
|
value: $(tasks.image-publish.results.digest)
|
|
- name: repository-digest
|
|
value: $(tasks.image-publish.results.repository-digest)
|
|
- name: env-identity
|
|
value: $(tasks.image-publish.results.env-identity)
|
|
- name: image-status
|
|
value: $(tasks.image-publish.results.status)
|