feat: add devops-controlled dev ci flow

This commit is contained in:
Codex
2026-05-18 06:59:51 +00:00
parent 348c644fde
commit b265274750
29 changed files with 2504 additions and 366 deletions
@@ -40,7 +40,8 @@ services:
K3SCTL_NATIVE_SERVICE_URL_CODE_QUEUE: "${K3SCTL_NATIVE_SERVICE_URL_CODE_QUEUE:-}"
K3SCTL_NATIVE_SERVICE_URL_MDTODO: "${K3SCTL_NATIVE_SERVICE_URL_MDTODO:-}"
K3SCTL_NATIVE_SERVICE_URL_DECISION_CENTER: "${K3SCTL_NATIVE_SERVICE_URL_DECISION_CENTER:-}"
K3SCTL_MANIFEST_PATHS: "${K3SCTL_MANIFEST_PATHS:-k3s/code-queue.k3s.json,k3s/mdtodo.k3s.json,k3s/claudeqq.k3s.json,k3s/decision-center.k3s.json}"
K3SCTL_NATIVE_SERVICE_URL_DEVOPS: "${K3SCTL_NATIVE_SERVICE_URL_DEVOPS:-}"
K3SCTL_MANIFEST_PATHS: "${K3SCTL_MANIFEST_PATHS:-k3s/code-queue.k3s.json,k3s/mdtodo.k3s.json,k3s/claudeqq.k3s.json,k3s/decision-center.k3s.json,k3s/devops.k3s.json}"
K3SCTL_SERVICES_JSON: "${K3SCTL_SERVICES_JSON:-[]}"
UNIDESK_LOG_RETENTION_BYTES: "${UNIDESK_LOG_RETENTION_BYTES:-512MiB}"
volumes:
@@ -77,6 +77,40 @@ roleRef:
name: unidesk-ci-trigger-reader
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: unidesk-ci-dev-e2e-manager
labels:
app.kubernetes.io/name: unidesk-ci
app.kubernetes.io/part-of: unidesk
rules:
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "list", "watch", "create", "delete", "patch"]
- apiGroups: [""]
resources: ["configmaps", "services", "pods", "pods/log"]
verbs: ["get", "list", "watch", "create", "delete", "patch"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "delete", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: unidesk-ci-dev-e2e-manager
labels:
app.kubernetes.io/name: unidesk-ci
app.kubernetes.io/part-of: unidesk
subjects:
- kind: ServiceAccount
name: unidesk-ci-runner
namespace: unidesk-ci
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: unidesk-ci-dev-e2e-manager
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: unidesk-ci-cross-namespace
@@ -146,7 +180,7 @@ spec:
type: string
- name: image
type: string
default: unidesk-code-queue:d601
default: unidesk-code-queue:dev
workspaces:
- name: source
volumes:
@@ -185,6 +219,7 @@ spec:
git rev-parse HEAD | tee "$(workspaces.source.path)/commit.txt"
- name: install-and-check
image: "$(params.image)"
imagePullPolicy: Never
env:
- name: DOCKER_HOST
value: unix:///var/run/docker.sock
@@ -235,12 +270,13 @@ spec:
type: string
- name: app-image
type: string
default: unidesk-code-queue:d601
default: unidesk-code-queue:dev
workspaces:
- name: source
steps:
- name: start-read-service
image: "$(params.app-image)"
imagePullPolicy: Never
env:
- name: HTTP_PROXY
value: ""
@@ -499,6 +535,7 @@ spec:
exit 1
- name: measure
image: "$(params.app-image)"
imagePullPolicy: Never
workingDir: "$(workspaces.source.path)/repo"
env:
- name: CI_CODE_QUEUE_URL
@@ -550,6 +587,7 @@ spec:
bun scripts/ci-code-queue-read-perf.ts
- name: cleanup
image: "$(params.app-image)"
imagePullPolicy: Never
env:
- name: HTTP_PROXY
value: ""
@@ -588,6 +626,408 @@ spec:
delete_resource "api/v1/namespaces/$kube_namespace/services/code-queue-ci-read"
---
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: unidesk-dev-namespace-e2e
namespace: unidesk-ci
labels:
app.kubernetes.io/name: unidesk-ci
app.kubernetes.io/component: dev-namespace-e2e
spec:
params:
- name: repo-url
type: string
default: https://github.com/pikasTech/unidesk
- name: desired-ref
type: string
default: master
- name: deploy-commit
type: string
- name: environment
type: string
default: dev
- name: run-id
type: string
- name: keep-namespace
type: string
default: "false"
- name: app-image
type: string
default: unidesk-code-queue:dev
workspaces:
- name: source
steps:
- name: clone-deploy-manifest
image: alpine/git:2.45.2
env:
- name: HTTP_PROXY
value: "http://d601-provider-egress-proxy.unidesk.svc.cluster.local:18789"
- name: HTTPS_PROXY
value: "http://d601-provider-egress-proxy.unidesk.svc.cluster.local:18789"
- name: ALL_PROXY
value: "http://d601-provider-egress-proxy.unidesk.svc.cluster.local:18789"
- name: NO_PROXY
value: "localhost,127.0.0.1,::1,d601-provider-egress-proxy,d601-provider-egress-proxy.unidesk,d601-provider-egress-proxy.unidesk.svc,d601-provider-egress-proxy.unidesk.svc.cluster.local"
- name: http_proxy
value: "http://d601-provider-egress-proxy.unidesk.svc.cluster.local:18789"
- name: https_proxy
value: "http://d601-provider-egress-proxy.unidesk.svc.cluster.local:18789"
- name: all_proxy
value: "http://d601-provider-egress-proxy.unidesk.svc.cluster.local:18789"
- name: no_proxy
value: "localhost,127.0.0.1,::1,d601-provider-egress-proxy,d601-provider-egress-proxy.unidesk,d601-provider-egress-proxy.unidesk.svc,d601-provider-egress-proxy.unidesk.svc.cluster.local"
script: |
#!/bin/sh
set -eu
run_dir="$(workspaces.source.path)/dev-e2e-$(params.run-id)"
rm -rf "$run_dir"
mkdir -p "$run_dir"
git clone --filter=blob:none --no-checkout "$(params.repo-url)" "$run_dir/repo"
cd "$run_dir/repo"
git fetch --depth=1 origin "$(params.desired-ref)"
actual="$(git rev-parse FETCH_HEAD)"
expected="$(params.deploy-commit)"
if [ "$actual" != "$expected" ]; then
echo "desired ref commit mismatch actual=$actual expected=$expected" >&2
exit 1
fi
git show FETCH_HEAD:deploy.json >"$run_dir/deploy.json"
printf '%s\n' "$actual" >"$run_dir/deploy-commit.txt"
- name: namespace-smoke-e2e
image: "$(params.app-image)"
imagePullPolicy: Never
env:
- name: HTTP_PROXY
value: ""
- name: HTTPS_PROXY
value: ""
- name: ALL_PROXY
value: ""
- name: NO_PROXY
value: "localhost,127.0.0.1,::1,kubernetes,kubernetes.default,kubernetes.default.svc,kubernetes.default.svc.cluster.local"
- name: http_proxy
value: ""
- name: https_proxy
value: ""
- name: all_proxy
value: ""
- name: no_proxy
value: "localhost,127.0.0.1,::1,kubernetes,kubernetes.default,kubernetes.default.svc,kubernetes.default.svc.cluster.local"
script: |
#!/usr/bin/env bash
set -euo pipefail
ns="unidesk-ci-e2e-$(params.run-id)"
keep="$(params.keep-namespace)"
run_dir="$(workspaces.source.path)/dev-e2e-$(params.run-id)"
deploy_json="$run_dir/deploy.json"
result_json="$run_dir/dev-e2e-result.json"
kube_api="https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT_HTTPS}"
kube_token="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"
kube_ca="/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
kube() {
local method="$1"
shift
curl -fsS --cacert "$kube_ca" -H "Authorization: Bearer $kube_token" -X "$method" "$@"
}
delete_path() {
local path="$1"
local code
code="$(curl -sS -o /tmp/unidesk-dev-e2e-delete-response -w "%{http_code}" --cacert "$kube_ca" -H "Authorization: Bearer $kube_token" -X DELETE "$kube_api/$path")"
if [ "$code" = "200" ] || [ "$code" = "202" ] || [ "$code" = "404" ]; then
return 0
fi
cat /tmp/unidesk-dev-e2e-delete-response >&2
return 1
}
cleanup() {
if [ "$keep" = "true" ]; then
echo "dev_e2e_namespace_retained=$ns"
return 0
fi
delete_path "api/v1/namespaces/$ns" || true
echo "dev_e2e_namespace_deleted=$ns"
}
trap cleanup EXIT
bun - "$deploy_json" "$run_dir/dev-e2e-service-commits.env" "$(params.environment)" <<'BUN'
const [deployPath, outPath, environment] = process.argv.slice(2);
const manifest = await Bun.file(deployPath).json();
if (!manifest || manifest.schemaVersion !== 2 || !manifest.environments?.[environment]) {
throw new Error(`deploy.json must contain schemaVersion=2 environments.${environment}`);
}
const services = manifest.environments[environment].services;
if (!Array.isArray(services) || services.length === 0) {
throw new Error(`deploy.json environments.${environment}.services must contain services`);
}
const lines = [];
for (const service of services) {
if (!service?.id || !service?.commitId || !service?.repo) {
throw new Error(`each deploy.json environments.${environment} service must contain id, repo and commitId`);
}
const key = String(service.id).toUpperCase().replace(/[^A-Z0-9]/g, "_");
lines.push(`${key}_COMMIT=${service.commitId}`);
}
await Bun.write(outPath, lines.join("\n") + "\n");
console.log(JSON.stringify({ ok: true, environment, services: services.map((service) => ({ id: service.id, commitId: service.commitId })) }));
BUN
# shellcheck disable=SC1091
source "$run_dir/dev-e2e-service-commits.env"
backend_commit="${BACKEND_CORE_COMMIT:-unknown}"
frontend_commit="${FRONTEND_COMMIT:-unknown}"
code_queue_commit="${CODE_QUEUE_COMMIT:-unknown}"
delete_path "api/v1/namespaces/$ns"
cat >/tmp/dev-e2e-namespace.yaml <<YAML
apiVersion: v1
kind: Namespace
metadata:
name: $ns
labels:
app.kubernetes.io/part-of: unidesk
unidesk.ai/purpose: ci-dev-e2e
unidesk.ai/deploy-ref: master-deploy-json-dev
YAML
kube PATCH \
-H "Content-Type: application/apply-patch+yaml" \
--data-binary @/tmp/dev-e2e-namespace.yaml \
"$kube_api/api/v1/namespaces/$ns?fieldManager=unidesk-ci&force=true" >/dev/null
deploy_json_b64="$(base64 -w0 "$deploy_json")"
cat >/tmp/dev-e2e-configmap.yaml <<YAML
apiVersion: v1
kind: ConfigMap
metadata:
name: desired-manifest
namespace: $ns
labels:
app.kubernetes.io/name: unidesk-dev-namespace-e2e
app.kubernetes.io/part-of: unidesk
data:
deployCommit: "$(params.deploy-commit)"
environment: "$(params.environment)"
backendCoreCommit: "$backend_commit"
frontendCommit: "$frontend_commit"
codeQueueCommit: "$code_queue_commit"
deploy.json.b64: "$deploy_json_b64"
YAML
kube PATCH \
-H "Content-Type: application/apply-patch+yaml" \
--data-binary @/tmp/dev-e2e-configmap.yaml \
"$kube_api/api/v1/namespaces/$ns/configmaps/desired-manifest?fieldManager=unidesk-ci&force=true" >/dev/null
cat >/tmp/dev-e2e-target.yaml <<YAML
apiVersion: apps/v1
kind: Deployment
metadata:
name: dev-e2e-target
namespace: $ns
labels:
app.kubernetes.io/name: unidesk-dev-namespace-e2e
app.kubernetes.io/component: smoke-target
app.kubernetes.io/part-of: unidesk
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: unidesk-dev-namespace-e2e
app.kubernetes.io/component: smoke-target
template:
metadata:
labels:
app.kubernetes.io/name: unidesk-dev-namespace-e2e
app.kubernetes.io/component: smoke-target
app.kubernetes.io/part-of: unidesk
spec:
nodeSelector:
unidesk.ai/node-id: D601
terminationGracePeriodSeconds: 5
containers:
- name: smoke-target
image: "$(params.app-image)"
imagePullPolicy: Never
command:
- bun
- -e
- |
const port = Number(process.env.PORT || 8080);
const payload = {
ok: true,
environment: "dev",
namespace: process.env.CI_E2E_NAMESPACE,
deployCommit: process.env.CI_E2E_DEPLOY_COMMIT,
backendCoreCommit: process.env.BACKEND_CORE_COMMIT,
frontendCommit: process.env.FRONTEND_COMMIT,
codeQueueCommit: process.env.CODE_QUEUE_COMMIT
};
Bun.serve({
hostname: "0.0.0.0",
port,
fetch(req) {
const url = new URL(req.url);
if (url.pathname === "/health" || url.pathname === "/") {
return Response.json(payload);
}
return new Response("not found", { status: 404 });
}
});
console.log(JSON.stringify({ listening: port, ...payload }));
await new Promise(() => {});
ports:
- name: http
containerPort: 8080
env:
- name: PORT
value: "8080"
- name: CI_E2E_NAMESPACE
value: "$ns"
- name: CI_E2E_DEPLOY_COMMIT
value: "$(params.deploy-commit)"
- name: BACKEND_CORE_COMMIT
value: "$backend_commit"
- name: FRONTEND_COMMIT
value: "$frontend_commit"
- name: CODE_QUEUE_COMMIT
value: "$code_queue_commit"
readinessProbe:
httpGet:
path: /health
port: http
periodSeconds: 3
timeoutSeconds: 2
failureThreshold: 20
resources:
requests:
cpu: 20m
memory: 64Mi
limits:
memory: 256Mi
---
apiVersion: v1
kind: Service
metadata:
name: dev-e2e-target
namespace: $ns
labels:
app.kubernetes.io/name: unidesk-dev-namespace-e2e
app.kubernetes.io/component: smoke-target
app.kubernetes.io/part-of: unidesk
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: unidesk-dev-namespace-e2e
app.kubernetes.io/component: smoke-target
ports:
- name: http
port: 8080
targetPort: http
YAML
csplit -s -f /tmp/dev-e2e-target- /tmp/dev-e2e-target.yaml '/^---$/' '{*}'
kube PATCH \
-H "Content-Type: application/apply-patch+yaml" \
--data-binary @/tmp/dev-e2e-target-00 \
"$kube_api/apis/apps/v1/namespaces/$ns/deployments/dev-e2e-target?fieldManager=unidesk-ci&force=true" >/dev/null
kube PATCH \
-H "Content-Type: application/apply-patch+yaml" \
--data-binary @/tmp/dev-e2e-target-01 \
"$kube_api/api/v1/namespaces/$ns/services/dev-e2e-target?fieldManager=unidesk-ci&force=true" >/dev/null
deadline=$((SECONDS + 180))
while [ "$SECONDS" -lt "$deadline" ]; do
status="$(kube GET "$kube_api/apis/apps/v1/namespaces/$ns/deployments/dev-e2e-target")"
available="$(printf '%s' "$status" | jq -r '.status.availableReplicas // 0')"
observed="$(printf '%s' "$status" | jq -r '.status.observedGeneration // 0')"
generation="$(printf '%s' "$status" | jq -r '.metadata.generation // 0')"
if [ "$available" -ge 1 ] && [ "$observed" -ge "$generation" ]; then
echo "dev_e2e_target_rollout=available namespace=$ns"
break
fi
sleep 2
done
if [ "$SECONDS" -ge "$deadline" ]; then
echo "dev_e2e_target_rollout=timeout namespace=$ns" >&2
kube GET "$kube_api/apis/apps/v1/namespaces/$ns/deployments/dev-e2e-target" >&2
exit 1
fi
bun - "$ns" "$(params.deploy-commit)" "$backend_commit" "$frontend_commit" "$code_queue_commit" "$result_json" <<'BUN'
const [ns, deployCommit, backendCommit, frontendCommit, codeQueueCommit, resultPath] = process.argv.slice(2);
const url = `http://dev-e2e-target.${ns}.svc.cluster.local:8080/health`;
const started = performance.now();
const response = await fetch(url);
const elapsedMs = Math.round(performance.now() - started);
const body = await response.json();
const checks = [
response.ok,
body.ok === true,
body.environment === "dev",
body.namespace === ns,
body.deployCommit === deployCommit,
body.backendCoreCommit === backendCommit,
body.frontendCommit === frontendCommit,
body.codeQueueCommit === codeQueueCommit
];
const result = { ok: checks.every(Boolean), elapsedMs, url, body };
await Bun.write(resultPath, JSON.stringify(result, null, 2) + "\n");
console.log(JSON.stringify(result));
if (!result.ok) process.exit(1);
BUN
---
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
name: unidesk-dev-namespace-e2e
namespace: unidesk-ci
labels:
app.kubernetes.io/name: unidesk-ci
app.kubernetes.io/component: dev-namespace-e2e
app.kubernetes.io/part-of: unidesk
spec:
params:
- name: repo-url
type: string
default: https://github.com/pikasTech/unidesk
- name: desired-ref
type: string
default: master
- name: deploy-commit
type: string
- name: environment
type: string
default: dev
- name: run-id
type: string
- name: keep-namespace
type: string
default: "false"
- name: app-image
type: string
default: unidesk-code-queue:dev
workspaces:
- name: shared-workspace
tasks:
- name: dev-namespace-e2e
taskRef:
name: unidesk-dev-namespace-e2e
params:
- name: repo-url
value: "$(params.repo-url)"
- name: desired-ref
value: "$(params.desired-ref)"
- name: deploy-commit
value: "$(params.deploy-commit)"
- name: environment
value: "$(params.environment)"
- name: run-id
value: "$(params.run-id)"
- name: keep-namespace
value: "$(params.keep-namespace)"
- name: app-image
value: "$(params.app-image)"
workspaces:
- name: source
workspace: shared-workspace
---
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
name: unidesk-ci
@@ -604,10 +1044,10 @@ spec:
type: string
- name: check-image
type: string
default: unidesk-code-queue:d601
default: unidesk-code-queue:dev
- name: code-queue-image
type: string
default: unidesk-code-queue:d601
default: unidesk-code-queue:dev
workspaces:
- name: shared-workspace
tasks:
@@ -155,8 +155,8 @@ metadata:
unidesk.ai/deployment-mode: k3sctl-managed
unidesk.ai/deploy-service-id: code-queue
annotations:
unidesk.ai/deploy-ref: origin/deploy/dev
unidesk.ai/image-source: deploy-dev-commit
unidesk.ai/deploy-ref: origin/master:deploy.json#environments.dev
unidesk.ai/image-source: deploy-env-commit
spec:
replicas: 1
strategy:
@@ -205,9 +205,9 @@ spec:
- name: UNIDESK_DEPLOY_REPO
value: https://github.com/pikasTech/unidesk
- name: UNIDESK_DEPLOY_COMMIT
value: replace-with-deploy-dev-commit
value: replace-with-deploy-env-commit
- name: UNIDESK_DEPLOY_REQUESTED_COMMIT
value: replace-with-deploy-dev-commit
value: replace-with-deploy-env-commit
volumeMounts:
- name: script
mountPath: /etc/unidesk-provider-egress
@@ -250,8 +250,8 @@ metadata:
unidesk.ai/deployment-mode: k3sctl-managed
unidesk.ai/deploy-service-id: code-queue
annotations:
unidesk.ai/deploy-ref: origin/deploy/dev
unidesk.ai/image-source: deploy-dev-commit
unidesk.ai/deploy-ref: origin/master:deploy.json#environments.dev
unidesk.ai/image-source: deploy-env-commit
spec:
replicas: 1
strategy:
@@ -306,13 +306,13 @@ spec:
- name: UNIDESK_DEPLOY_REPO
value: https://github.com/pikasTech/unidesk
- name: UNIDESK_DEPLOY_COMMIT
value: replace-with-deploy-dev-commit
value: replace-with-deploy-env-commit
- name: UNIDESK_DEPLOY_REQUESTED_COMMIT
value: replace-with-deploy-dev-commit
value: replace-with-deploy-env-commit
- name: CODE_QUEUE_DEPLOY_COMMIT
value: replace-with-deploy-dev-commit
value: replace-with-deploy-env-commit
- name: CODE_QUEUE_DEPLOY_REQUESTED_COMMIT
value: replace-with-deploy-dev-commit
value: replace-with-deploy-env-commit
- name: CODE_QUEUE_INSTANCE_ID
value: D601-dev
- name: CODE_QUEUE_SERVICE_ROLE
@@ -460,8 +460,8 @@ metadata:
unidesk.ai/deployment-mode: k3sctl-managed
unidesk.ai/deploy-service-id: code-queue
annotations:
unidesk.ai/deploy-ref: origin/deploy/dev
unidesk.ai/image-source: deploy-dev-commit
unidesk.ai/deploy-ref: origin/master:deploy.json#environments.dev
unidesk.ai/image-source: deploy-env-commit
spec:
replicas: 1
selector:
@@ -514,13 +514,13 @@ spec:
- name: UNIDESK_DEPLOY_REPO
value: https://github.com/pikasTech/unidesk
- name: UNIDESK_DEPLOY_COMMIT
value: replace-with-deploy-dev-commit
value: replace-with-deploy-env-commit
- name: UNIDESK_DEPLOY_REQUESTED_COMMIT
value: replace-with-deploy-dev-commit
value: replace-with-deploy-env-commit
- name: CODE_QUEUE_DEPLOY_COMMIT
value: replace-with-deploy-dev-commit
value: replace-with-deploy-env-commit
- name: CODE_QUEUE_DEPLOY_REQUESTED_COMMIT
value: replace-with-deploy-dev-commit
value: replace-with-deploy-env-commit
- name: CODE_QUEUE_INSTANCE_ID
value: D601-dev-read
- name: CODE_QUEUE_SERVICE_ROLE
@@ -603,8 +603,8 @@ metadata:
unidesk.ai/deployment-mode: k3sctl-managed
unidesk.ai/deploy-service-id: code-queue
annotations:
unidesk.ai/deploy-ref: origin/deploy/dev
unidesk.ai/image-source: deploy-dev-commit
unidesk.ai/deploy-ref: origin/master:deploy.json#environments.dev
unidesk.ai/image-source: deploy-env-commit
spec:
replicas: 1
selector:
@@ -657,13 +657,13 @@ spec:
- name: UNIDESK_DEPLOY_REPO
value: https://github.com/pikasTech/unidesk
- name: UNIDESK_DEPLOY_COMMIT
value: replace-with-deploy-dev-commit
value: replace-with-deploy-env-commit
- name: UNIDESK_DEPLOY_REQUESTED_COMMIT
value: replace-with-deploy-dev-commit
value: replace-with-deploy-env-commit
- name: CODE_QUEUE_DEPLOY_COMMIT
value: replace-with-deploy-dev-commit
value: replace-with-deploy-env-commit
- name: CODE_QUEUE_DEPLOY_REQUESTED_COMMIT
value: replace-with-deploy-dev-commit
value: replace-with-deploy-env-commit
- name: CODE_QUEUE_INSTANCE_ID
value: D601-dev-write
- name: CODE_QUEUE_SERVICE_ROLE
@@ -32,8 +32,8 @@ metadata:
app.kubernetes.io/part-of: unidesk
unidesk.ai/environment: dev
annotations:
unidesk.ai/deploy-ref: origin/deploy/dev
unidesk.ai/image-source: deploy-dev-commit
unidesk.ai/deploy-ref: origin/master:deploy.json#environments.dev
unidesk.ai/image-source: deploy-env-commit
unidesk.ai/deploy-service-id: backend-core
spec:
replicas: 1
@@ -105,9 +105,9 @@ spec:
- name: UNIDESK_DEPLOY_REPO
value: https://github.com/pikasTech/unidesk
- name: UNIDESK_DEPLOY_COMMIT
value: replace-with-deploy-dev-commit
value: replace-with-deploy-env-commit
- name: UNIDESK_DEPLOY_REQUESTED_COMMIT
value: replace-with-deploy-dev-commit
value: replace-with-deploy-env-commit
- name: LOG_FILE
value: /var/log/unidesk-dev/backend-core-dev.jsonl
volumeMounts:
@@ -175,8 +175,8 @@ metadata:
app.kubernetes.io/part-of: unidesk
unidesk.ai/environment: dev
annotations:
unidesk.ai/deploy-ref: origin/deploy/dev
unidesk.ai/image-source: deploy-dev-commit
unidesk.ai/deploy-ref: origin/master:deploy.json#environments.dev
unidesk.ai/image-source: deploy-env-commit
unidesk.ai/deploy-service-id: frontend
spec:
replicas: 1
@@ -250,9 +250,9 @@ spec:
- name: UNIDESK_DEPLOY_REPO
value: https://github.com/pikasTech/unidesk
- name: UNIDESK_DEPLOY_COMMIT
value: replace-with-deploy-dev-commit
value: replace-with-deploy-env-commit
- name: UNIDESK_DEPLOY_REQUESTED_COMMIT
value: replace-with-deploy-dev-commit
value: replace-with-deploy-env-commit
- name: LOG_FILE
value: /var/log/unidesk-dev/frontend-dev.jsonl
volumeMounts:
@@ -82,7 +82,7 @@ metadata:
data:
UNIDESK_ENV: dev
UNIDESK_NAMESPACE: unidesk-dev
UNIDESK_DEPLOY_REF: origin/deploy/dev
UNIDESK_DEPLOY_REF: origin/master:deploy.json#environments.dev
UNIDESK_PROVIDER_ID: D601-dev
UNIDESK_NODE_ID: D601
UNIDESK_DEV_DATABASE_NAME: unidesk_dev
@@ -177,7 +177,7 @@ data:
('namespace', 'unidesk-dev', now()),
('database', 'unidesk_dev', now()),
('provider_id', 'D601-dev', now()),
('deploy_ref', 'origin/deploy/dev', now())
('deploy_ref', 'origin/master:deploy.json#environments.dev', now())
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = now();
CREATE TABLE IF NOT EXISTS unidesk_nodes (
@@ -0,0 +1,37 @@
{
"apiVersion": "unidesk.ai/k3s/v1",
"kind": "ManagedKubernetesService",
"metadata": {
"name": "devops",
"namespace": "unidesk-ci"
},
"spec": {
"adapterServiceId": "k3sctl-adapter",
"controlPlane": {
"type": "kubernetes",
"cluster": "unidesk-k3s",
"context": "unidesk-k3s"
},
"route": {
"kind": "kubernetes-service",
"serviceName": "devops",
"servicePort": 4286
},
"activeInstanceId": "D601",
"singleWriter": true,
"expectedNodeIds": [
"D601"
],
"instances": [
{
"id": "D601",
"nodeId": "D601",
"role": "primary",
"baseUrl": "kubernetes://unidesk-ci/services/devops:4286",
"healthPath": "/health",
"healthMode": "service-proxy"
}
],
"requireAllInstancesHealthy": true
}
}
@@ -0,0 +1,171 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: devops
namespace: unidesk-ci
labels:
app.kubernetes.io/name: devops
app.kubernetes.io/part-of: unidesk
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: devops
namespace: unidesk-ci
labels:
app.kubernetes.io/name: devops
app.kubernetes.io/part-of: unidesk
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get", "list"]
- apiGroups: ["tekton.dev"]
resources: ["pipelines", "tasks", "taskruns"]
verbs: ["get", "list", "watch"]
- apiGroups: ["tekton.dev"]
resources: ["pipelineruns"]
verbs: ["get", "list", "watch", "create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: devops
namespace: unidesk-ci
labels:
app.kubernetes.io/name: devops
app.kubernetes.io/part-of: unidesk
subjects:
- kind: ServiceAccount
name: devops
namespace: unidesk-ci
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: devops
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: devops
namespace: unidesk-ci
labels:
app.kubernetes.io/name: devops
app.kubernetes.io/part-of: unidesk
unidesk.ai/deployment-mode: k3sctl-managed
unidesk.ai/instance-id: D601
unidesk.ai/deploy-service-id: devops
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: devops
unidesk.ai/instance-id: D601
template:
metadata:
labels:
app.kubernetes.io/name: devops
app.kubernetes.io/part-of: unidesk
unidesk.ai/deployment-mode: k3sctl-managed
unidesk.ai/instance-id: D601
unidesk.ai/node-id: D601
unidesk.ai/deploy-service-id: devops
annotations:
unidesk.ai/deploy-service-id: devops
unidesk.ai/deploy-repo: https://github.com/pikasTech/unidesk
unidesk.ai/deploy-commit: replace-with-deploy-env-commit
unidesk.ai/deploy-requested-commit: replace-with-deploy-env-commit
spec:
serviceAccountName: devops
nodeSelector:
unidesk.ai/node-id: D601
terminationGracePeriodSeconds: 10
containers:
- name: devops
image: unidesk-devops:dev-placeholder
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 4286
env:
- name: HOST
value: "0.0.0.0"
- name: PORT
value: "4286"
- name: DEVOPS_NAMESPACE
value: "unidesk-ci"
- name: DEVOPS_REPO_URL
value: "https://github.com/pikasTech/unidesk"
- name: DEVOPS_DESIRED_REF
value: "master"
- name: DEVOPS_ENVIRONMENT
value: "dev"
- name: UNIDESK_DEPLOY_SERVICE_ID
value: "devops"
- name: UNIDESK_DEPLOY_REPO
value: "https://github.com/pikasTech/unidesk"
- name: UNIDESK_DEPLOY_COMMIT
value: replace-with-deploy-env-commit
- name: UNIDESK_DEPLOY_REQUESTED_COMMIT
value: replace-with-deploy-env-commit
- name: DEVOPS_GIT_PROXY_URL
value: "http://d601-provider-egress-proxy.unidesk.svc.cluster.local:18789"
- name: DEVOPS_DEV_E2E_PIPELINE
value: "unidesk-dev-namespace-e2e"
- name: DEVOPS_PIPELINE_SERVICE_ACCOUNT
value: "unidesk-ci-runner"
- name: DEVOPS_PIPELINE_WORKSPACE_CLAIM
value: "unidesk-ci-cache"
- name: DEVOPS_DEV_E2E_APP_IMAGE
value: "unidesk-code-queue:dev"
- name: LOG_FILE
value: "/var/log/unidesk/devops.jsonl"
volumeMounts:
- name: logs
mountPath: /var/log/unidesk
readinessProbe:
httpGet:
path: /health
port: http
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 12
livenessProbe:
httpGet:
path: /live
port: http
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 6
resources:
requests:
cpu: 20m
memory: 48Mi
limits:
memory: 160Mi
volumes:
- name: logs
hostPath:
path: /home/ubuntu/.unidesk/devops-deploy/logs
type: DirectoryOrCreate
---
apiVersion: v1
kind: Service
metadata:
name: devops
namespace: unidesk-ci
labels:
app.kubernetes.io/name: devops
app.kubernetes.io/part-of: unidesk
unidesk.ai/deployment-mode: k3sctl-managed
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: devops
unidesk.ai/instance-id: D601
ports:
- name: http
port: 4286
targetPort: http
@@ -274,7 +274,7 @@ function mergeServices(services: ManagedService[]): ManagedService[] {
}
function readConfig(): RuntimeConfig {
const paths = manifestPaths(envString("K3SCTL_MANIFEST_PATHS", "k3s/code-queue.k3s.json,k3s/mdtodo.k3s.json,k3s/claudeqq.k3s.json,k3s/decision-center.k3s.json"));
const paths = manifestPaths(envString("K3SCTL_MANIFEST_PATHS", "k3s/code-queue.k3s.json,k3s/mdtodo.k3s.json,k3s/claudeqq.k3s.json,k3s/decision-center.k3s.json,k3s/devops.k3s.json"));
const inlineServices = parseServices(envString("K3SCTL_SERVICES_JSON", "[]"));
const manifestServices = readManifestServices(paths);
return {