feat: add D601 direct artifact consumer
This commit is contained in:
@@ -71,14 +71,27 @@ const defaultOptions: ArtifactRegistryOptions = {
|
||||
sourceRepoExplicit: false,
|
||||
deployRef: null,
|
||||
};
|
||||
const supportedArtifactConsumerServices = ["backend-core", "baidu-netdisk", "code-queue-mgr", "decision-center", "frontend", "oa-event-flow", "project-manager", "todo-note"] as const;
|
||||
const supportedArtifactConsumerServices = [
|
||||
"backend-core",
|
||||
"baidu-netdisk",
|
||||
"code-queue-mgr",
|
||||
"decision-center",
|
||||
"findjob",
|
||||
"frontend",
|
||||
"k3sctl-adapter",
|
||||
"met-nonlinear",
|
||||
"oa-event-flow",
|
||||
"pipeline",
|
||||
"project-manager",
|
||||
"todo-note",
|
||||
] as const;
|
||||
type SupportedArtifactConsumerService = typeof supportedArtifactConsumerServices[number];
|
||||
const legacyDeployBackendCoreDisabled = true;
|
||||
|
||||
interface ArtifactConsumerSpec {
|
||||
serviceId: SupportedArtifactConsumerService;
|
||||
environment?: ArtifactDeployEnvironment;
|
||||
kind: "compose" | "d601-k3s";
|
||||
kind: "compose" | "d601-compose" | "d601-k3s";
|
||||
registryRepository: string;
|
||||
sourceRepo?: string;
|
||||
dockerfile: string;
|
||||
@@ -99,6 +112,9 @@ interface ArtifactConsumerTarget {
|
||||
deployEnvPrefix: string;
|
||||
healthProbeCommand: string;
|
||||
requireHealthCommit: boolean;
|
||||
workDir?: string;
|
||||
composeFile?: string;
|
||||
projectHint?: string;
|
||||
};
|
||||
k3s?: {
|
||||
namespace: string;
|
||||
@@ -270,6 +286,117 @@ const artifactConsumerSpecs: Record<string, ArtifactConsumerSpec> = {
|
||||
},
|
||||
},
|
||||
},
|
||||
"findjob": {
|
||||
serviceId: "findjob",
|
||||
environment: "prod",
|
||||
kind: "d601-compose",
|
||||
sourceRepo: "https://gitee.com/Lyon1998/findjob",
|
||||
registryRepository: "unidesk/findjob",
|
||||
dockerfile: "Dockerfile",
|
||||
prodLiveApply: "enabled",
|
||||
targets: {
|
||||
dev: {
|
||||
targetImage: "findjob-server",
|
||||
targetCommitImage: (commit: string) => `findjob-server:${commit}`,
|
||||
deployRef: "deploy.json#environments.dev.services.findjob",
|
||||
compose: {
|
||||
serviceName: "server",
|
||||
containerName: "findjob-server",
|
||||
deployEnvPrefix: "UNIDESK_FINDJOB_DEPLOY",
|
||||
workDir: "/home/ubuntu/findjob",
|
||||
composeFile: "docker-compose.yml",
|
||||
projectHint: "findjob",
|
||||
healthProbeCommand: "curl -fsS --max-time 12 http://127.0.0.1:3254/api/health",
|
||||
requireHealthCommit: false,
|
||||
},
|
||||
},
|
||||
prod: {
|
||||
targetImage: "findjob-server",
|
||||
targetCommitImage: (commit: string) => `findjob-server:${commit}`,
|
||||
deployRef: "deploy.json#environments.prod.services.findjob",
|
||||
compose: {
|
||||
serviceName: "server",
|
||||
containerName: "findjob-server",
|
||||
deployEnvPrefix: "UNIDESK_FINDJOB_DEPLOY",
|
||||
workDir: "/home/ubuntu/findjob",
|
||||
composeFile: "docker-compose.yml",
|
||||
projectHint: "findjob",
|
||||
healthProbeCommand: "curl -fsS --max-time 12 http://127.0.0.1:3254/api/health",
|
||||
requireHealthCommit: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"k3sctl-adapter": {
|
||||
serviceId: "k3sctl-adapter",
|
||||
environment: "prod",
|
||||
kind: "d601-compose",
|
||||
registryRepository: "unidesk/k3sctl-adapter",
|
||||
dockerfile: "src/components/microservices/k3sctl-adapter/Dockerfile",
|
||||
prodLiveApply: "supervisor-only",
|
||||
prodLiveBlockReason: "k3sctl-adapter is an infrastructure control bridge; this executor exposes artifact consumer plan/dry-run only. Real production deployment requires supervisor confirmation outside this task.",
|
||||
targets: {
|
||||
prod: {
|
||||
targetImage: "unidesk-k3sctl-adapter:d601",
|
||||
targetCommitImage: (commit: string) => `unidesk-k3sctl-adapter:${commit}`,
|
||||
deployRef: "deploy.json#environments.prod.services.k3sctl-adapter",
|
||||
compose: {
|
||||
serviceName: "k3sctl-adapter",
|
||||
containerName: "k3sctl-adapter",
|
||||
deployEnvPrefix: "UNIDESK_K3SCTL_ADAPTER_DEPLOY",
|
||||
workDir: "/home/ubuntu/cq-deploy",
|
||||
composeFile: "src/components/microservices/k3sctl-adapter/docker-compose.d601.yml",
|
||||
projectHint: "k3sctl-adapter",
|
||||
healthProbeCommand: "curl -fsS --max-time 10 http://127.0.0.1:4266/health",
|
||||
requireHealthCommit: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"met-nonlinear": {
|
||||
serviceId: "met-nonlinear",
|
||||
environment: "prod",
|
||||
kind: "d601-compose",
|
||||
sourceRepo: "https://github.com/pikasTech/met_nonlinear",
|
||||
registryRepository: "unidesk/met-nonlinear",
|
||||
dockerfile: "docker/unidesk/Dockerfile.ml",
|
||||
prodLiveApply: "unsupported",
|
||||
prodLiveBlockReason: "met-nonlinear is blocked for live artifact deploy because config.json points at docker/unidesk/Dockerfile.ml while the compose service is met-nonlinear-ts. The current compose contract does not let CD prove that the recreated long-running container image label equals the requested commit.",
|
||||
runtimeVerification: "blocked",
|
||||
runtimeVerificationBlockReason: "D601 direct artifact consumer is implemented, but this service's registered Dockerfile is the ML image contract while the long-running Compose service is met-nonlinear-ts. Publish a labeled artifact that matches the running service image contract before live deploy, or update the service contract to a server Dockerfile.",
|
||||
targets: {
|
||||
dev: {
|
||||
targetImage: "met-nonlinear-ml:tf26",
|
||||
targetCommitImage: (commit: string) => `met-nonlinear-ml:${commit}`,
|
||||
deployRef: "deploy.json#environments.dev.services.met-nonlinear",
|
||||
compose: {
|
||||
serviceName: "met-nonlinear-ts",
|
||||
containerName: "met-nonlinear-ts",
|
||||
deployEnvPrefix: "UNIDESK_MET_NONLINEAR_DEPLOY",
|
||||
workDir: "/home/ubuntu/met_nonlinear",
|
||||
composeFile: "docker-compose.unidesk.yml",
|
||||
projectHint: "met-nonlinear",
|
||||
healthProbeCommand: "curl -fsS --max-time 20 http://127.0.0.1:3288/health",
|
||||
requireHealthCommit: false,
|
||||
},
|
||||
},
|
||||
prod: {
|
||||
targetImage: "met-nonlinear-ml:tf26",
|
||||
targetCommitImage: (commit: string) => `met-nonlinear-ml:${commit}`,
|
||||
deployRef: "deploy.json#environments.prod.services.met-nonlinear",
|
||||
compose: {
|
||||
serviceName: "met-nonlinear-ts",
|
||||
containerName: "met-nonlinear-ts",
|
||||
deployEnvPrefix: "UNIDESK_MET_NONLINEAR_DEPLOY",
|
||||
workDir: "/home/ubuntu/met_nonlinear",
|
||||
composeFile: "docker-compose.unidesk.yml",
|
||||
projectHint: "met-nonlinear",
|
||||
healthProbeCommand: "curl -fsS --max-time 20 http://127.0.0.1:3288/health",
|
||||
requireHealthCommit: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"oa-event-flow": {
|
||||
serviceId: "oa-event-flow",
|
||||
environment: "prod",
|
||||
@@ -338,6 +465,47 @@ const artifactConsumerSpecs: Record<string, ArtifactConsumerSpec> = {
|
||||
},
|
||||
},
|
||||
},
|
||||
"pipeline": {
|
||||
serviceId: "pipeline",
|
||||
environment: "prod",
|
||||
kind: "d601-compose",
|
||||
sourceRepo: "https://github.com/pikasTech/pipeline",
|
||||
registryRepository: "unidesk/pipeline",
|
||||
dockerfile: "Dockerfile",
|
||||
prodLiveApply: "enabled",
|
||||
targets: {
|
||||
dev: {
|
||||
targetImage: "pipeline-v2-control",
|
||||
targetCommitImage: (commit: string) => `pipeline-v2-control:${commit}`,
|
||||
deployRef: "deploy.json#environments.dev.services.pipeline",
|
||||
compose: {
|
||||
serviceName: "pipeline-control",
|
||||
containerName: "pipeline-v2-control",
|
||||
deployEnvPrefix: "UNIDESK_PIPELINE_DEPLOY",
|
||||
workDir: "/home/ubuntu/pipeline",
|
||||
composeFile: "docker-compose.yml",
|
||||
projectHint: "pipeline",
|
||||
healthProbeCommand: "curl -fsS --max-time 20 http://127.0.0.1:18082/health",
|
||||
requireHealthCommit: false,
|
||||
},
|
||||
},
|
||||
prod: {
|
||||
targetImage: "pipeline-v2-control",
|
||||
targetCommitImage: (commit: string) => `pipeline-v2-control:${commit}`,
|
||||
deployRef: "deploy.json#environments.prod.services.pipeline",
|
||||
compose: {
|
||||
serviceName: "pipeline-control",
|
||||
containerName: "pipeline-v2-control",
|
||||
deployEnvPrefix: "UNIDESK_PIPELINE_DEPLOY",
|
||||
workDir: "/home/ubuntu/pipeline",
|
||||
composeFile: "docker-compose.yml",
|
||||
projectHint: "pipeline",
|
||||
healthProbeCommand: "curl -fsS --max-time 20 http://127.0.0.1:18082/health",
|
||||
requireHealthCommit: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"todo-note": {
|
||||
serviceId: "todo-note",
|
||||
environment: "prod",
|
||||
@@ -1318,6 +1486,167 @@ async function deployBackendCoreNow(options: ArtifactRegistryOptions): Promise<R
|
||||
return deployComposeArtifactNow(options, spec, target);
|
||||
}
|
||||
|
||||
function d601ComposeArtifactDeployScript(options: ArtifactRegistryOptions, spec: ArtifactConsumerSpec, target: ArtifactConsumerTarget, commit: string): string {
|
||||
if (target.compose === undefined) throw new Error(`${spec.serviceId} missing compose artifact consumer config`);
|
||||
const compose = target.compose;
|
||||
const sourceImage = artifactImageRef(options, spec, commit);
|
||||
const sourceRepo = sourceRepoFor(options, spec);
|
||||
const commitImage = target.targetCommitImage(commit);
|
||||
const envValues = composeArtifactEnvValues(spec, target, options, commit);
|
||||
const labels = {
|
||||
"unidesk.ai/deploy-service-id": spec.serviceId,
|
||||
"unidesk.ai/deploy-ref": deployRefFor(options, spec),
|
||||
"unidesk.ai/deploy-repo": sourceRepo,
|
||||
"unidesk.ai/deploy-commit": commit,
|
||||
"unidesk.ai/deploy-requested-commit": commit,
|
||||
"unidesk.ai/image-source": sourceImage,
|
||||
"unidesk.ai/deploy-environment": options.environment ?? "prod",
|
||||
};
|
||||
const override = {
|
||||
services: {
|
||||
[compose.serviceName]: {
|
||||
image: "${UNIDESK_ARTIFACT_STABLE_IMAGE}",
|
||||
labels,
|
||||
environment: {
|
||||
UNIDESK_DEPLOY_SERVICE_ID: spec.serviceId,
|
||||
UNIDESK_DEPLOY_REF: deployRefFor(options, spec),
|
||||
UNIDESK_DEPLOY_REPO: sourceRepo,
|
||||
UNIDESK_DEPLOY_COMMIT: commit,
|
||||
UNIDESK_DEPLOY_REQUESTED_COMMIT: commit,
|
||||
...envValues,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
return [
|
||||
"set -euo pipefail",
|
||||
`registry_image=${shellQuote(sourceImage)}`,
|
||||
`stable_image=${shellQuote(target.targetImage)}`,
|
||||
`commit_image=${shellQuote(commitImage)}`,
|
||||
`service_id=${shellQuote(spec.serviceId)}`,
|
||||
`source_repo=${shellQuote(sourceRepo)}`,
|
||||
`deploy_ref=${shellQuote(deployRefFor(options, spec))}`,
|
||||
`commit=${shellQuote(commit)}`,
|
||||
`dockerfile=${shellQuote(spec.dockerfile)}`,
|
||||
`work_dir=${shellQuote(compose.workDir ?? "/home/ubuntu")}`,
|
||||
`compose_file=${shellQuote(compose.composeFile ?? "docker-compose.yml")}`,
|
||||
`compose_service=${shellQuote(compose.serviceName)}`,
|
||||
`container=${shellQuote(compose.containerName)}`,
|
||||
`project_hint=${shellQuote(compose.projectHint ?? "")}`,
|
||||
`health_probe_b64=${shellQuote(base64(compose.healthProbeCommand))}`,
|
||||
`override_b64=${shellQuote(base64(JSON.stringify(override, null, 2)))}`,
|
||||
"command -v docker >/dev/null",
|
||||
"docker compose version >/dev/null",
|
||||
`curl -fsSI -H 'Accept: application/vnd.docker.distribution.manifest.v2+json' ${shellQuote(`http://127.0.0.1:${options.port}/v2/${spec.registryRepository}/manifests/${commit}`)} >/dev/null`,
|
||||
"docker pull -q \"$registry_image\" >/dev/null",
|
||||
"label_commit=$(docker image inspect \"$registry_image\" --format '{{ index .Config.Labels \"unidesk.ai/source-commit\" }}')",
|
||||
"label_service=$(docker image inspect \"$registry_image\" --format '{{ index .Config.Labels \"unidesk.ai/service-id\" }}')",
|
||||
"label_dockerfile=$(docker image inspect \"$registry_image\" --format '{{ index .Config.Labels \"unidesk.ai/dockerfile\" }}')",
|
||||
"test \"$label_commit\" = \"$commit\"",
|
||||
"test \"$label_service\" = \"$service_id\"",
|
||||
"test \"$label_dockerfile\" = \"$dockerfile\"",
|
||||
"test -d \"$work_dir\"",
|
||||
"test -f \"$work_dir/$compose_file\"",
|
||||
"docker tag \"$registry_image\" \"$stable_image\"",
|
||||
"docker tag \"$registry_image\" \"$commit_image\"",
|
||||
"override=\"$work_dir/.unidesk-artifact-consumer.override.yml\"",
|
||||
"printf '%s' \"$override_b64\" | base64 -d > \"$override\"",
|
||||
"export UNIDESK_ARTIFACT_STABLE_IMAGE=\"$stable_image\"",
|
||||
"project=$(docker inspect \"$container\" --format '{{ index .Config.Labels \"com.docker.compose.project\" }}' 2>/dev/null || true)",
|
||||
"if [ -z \"$project\" ]; then project=\"$project_hint\"; fi",
|
||||
"if [ -z \"$project\" ]; then project=$(basename \"$work_dir\"); fi",
|
||||
"cd \"$work_dir\"",
|
||||
"docker compose -p \"$project\" -f \"$compose_file\" -f \"$override\" up -d --no-build --no-deps --force-recreate \"$compose_service\"",
|
||||
"ready=0",
|
||||
"for attempt in $(seq 1 90); do",
|
||||
" cid=$(docker ps -q --filter label=com.docker.compose.project=\"$project\" --filter label=com.docker.compose.service=\"$compose_service\" --filter label=com.docker.compose.oneoff=False | head -1 || true)",
|
||||
" if [ -n \"$cid\" ]; then",
|
||||
" health=$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' \"$cid\" 2>/dev/null || true)",
|
||||
" echo \"artifact_cd_container_probe attempt=$attempt cid=$cid health=$health\"",
|
||||
" if [ \"$health\" = \"healthy\" ] || [ \"$health\" = \"running\" ]; then ready=1; break; fi",
|
||||
" else",
|
||||
" echo \"artifact_cd_container_probe attempt=$attempt cid=missing\"",
|
||||
" fi",
|
||||
" sleep 2",
|
||||
"done",
|
||||
"test \"$ready\" = \"1\"",
|
||||
"cid=$(docker ps -q --filter label=com.docker.compose.project=\"$project\" --filter label=com.docker.compose.service=\"$compose_service\" --filter label=com.docker.compose.oneoff=False | head -1)",
|
||||
"image_id=$(docker inspect -f '{{.Image}}' \"$cid\")",
|
||||
"actual_commit=$(docker image inspect -f '{{ index .Config.Labels \"unidesk.ai/source-commit\" }}' \"$image_id\")",
|
||||
"actual_service=$(docker image inspect -f '{{ index .Config.Labels \"unidesk.ai/service-id\" }}' \"$image_id\")",
|
||||
"container_commit=$(docker inspect -f '{{ index .Config.Labels \"unidesk.ai/deploy-commit\" }}' \"$cid\")",
|
||||
"test \"$actual_commit\" = \"$commit\"",
|
||||
"test \"$actual_service\" = \"$service_id\"",
|
||||
"test \"$container_commit\" = \"$commit\"",
|
||||
"health_probe=$(printf '%s' \"$health_probe_b64\" | base64 -d)",
|
||||
"docker exec \"$cid\" sh -lc \"$health_probe\" >/tmp/unidesk-artifact-health.out",
|
||||
"cat /tmp/unidesk-artifact-health.out",
|
||||
"printf 'artifact_cd_service=%s\\nartifact_cd_source_repo=%s\\nartifact_cd_deploy_ref=%s\\nartifact_cd_source_image=%s\\nartifact_cd_stable_image=%s\\nartifact_cd_runtime_image=%s\\nartifact_cd_commit=%s\\nartifact_cd_container=%s\\nartifact_cd_container_id=%s\\nartifact_cd_image_label_commit=%s\\nartifact_cd_container_label_commit=%s\\n' \"$service_id\" \"$source_repo\" \"$deploy_ref\" \"$registry_image\" \"$stable_image\" \"$commit_image\" \"$commit\" \"$container\" \"$cid\" \"$actual_commit\" \"$container_commit\"",
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
async function deployD601ComposeArtifactNow(options: ArtifactRegistryOptions, spec: ArtifactConsumerSpec, target: ArtifactConsumerTarget): Promise<Record<string, unknown>> {
|
||||
const environment = options.environment ?? "prod";
|
||||
const commit = options.commit;
|
||||
if (commit === null) throw new Error("artifact-registry deploy-service requires --commit <full-sha>");
|
||||
if (target.compose === undefined) throw new Error(`${spec.serviceId} missing compose artifact consumer config`);
|
||||
const health = runReadonlyStatus(options, true);
|
||||
if (health.ok !== true) return { ok: false, serviceId: spec.serviceId, error: "D601 artifact registry is not healthy", health };
|
||||
const sourceImage = artifactImageRef(options, spec, commit);
|
||||
const registryProbe = runRemoteScript(options, registryArtifactProbeScript(options, spec, commit), Math.max(options.timeoutMs, 120_000));
|
||||
if (registryProbe.exitCode !== 0 || registryProbe.timedOut) {
|
||||
return {
|
||||
ok: false,
|
||||
supported: true,
|
||||
serviceId: spec.serviceId,
|
||||
step: "registry-artifact-check",
|
||||
error: registryArtifactMissingMessage(spec),
|
||||
sourceImage,
|
||||
registryProbe: commandTail(registryProbe),
|
||||
};
|
||||
}
|
||||
const deploy = runRemoteScript(options, d601ComposeArtifactDeployScript(options, spec, target, commit), Math.max(options.timeoutMs, 420_000));
|
||||
if (deploy.exitCode !== 0 || deploy.timedOut) {
|
||||
return {
|
||||
ok: false,
|
||||
supported: true,
|
||||
serviceId: spec.serviceId,
|
||||
step: "d601-compose-artifact-deploy",
|
||||
sourceImage,
|
||||
registryProbe: commandTail(registryProbe),
|
||||
deploy: commandTail(deploy),
|
||||
rollback: rollbackInfo(spec, target, environment, commit),
|
||||
};
|
||||
}
|
||||
return {
|
||||
ok: true,
|
||||
supported: true,
|
||||
serviceId: spec.serviceId,
|
||||
environment,
|
||||
commit,
|
||||
providerId: options.providerId,
|
||||
sourceRepo: sourceRepoFor(options, spec),
|
||||
deployRef: deployRefFor(options, spec),
|
||||
sourceImage,
|
||||
targetImage: target.targetImage,
|
||||
targetCommitImage: target.targetCommitImage(commit),
|
||||
composeService: target.compose.serviceName,
|
||||
containerName: target.compose.containerName,
|
||||
registryProbe: commandTail(registryProbe),
|
||||
deploy: commandTail(deploy),
|
||||
validation: {
|
||||
liveCommit: commit,
|
||||
liveRequestedCommit: commit,
|
||||
imageLabelCommit: commit,
|
||||
containerDeployLabelCommit: commit,
|
||||
serviceHealthCommit: target.compose.requireHealthCommit ? commit : "not-required",
|
||||
serviceHealthRequestedCommit: target.compose.requireHealthCommit ? commit : "not-required",
|
||||
healthyOldVersionAccepted: false,
|
||||
},
|
||||
rollback: rollbackInfo(spec, target, environment, commit),
|
||||
};
|
||||
}
|
||||
|
||||
function deployBackendCoreJob(args: string[], options: ArtifactRegistryOptions): Record<string, unknown> {
|
||||
if (options.commit === null) throw new Error("artifact-registry deploy-backend-core requires --commit <full-sha>");
|
||||
const spec = artifactConsumerSpecs["backend-core"];
|
||||
@@ -1383,12 +1712,15 @@ function dryRunArtifactConsumerPlan(options: ArtifactRegistryOptions, spec: Arti
|
||||
reason: spec.runtimeVerificationBlockReason ?? spec.prodLiveBlockReason ?? null,
|
||||
},
|
||||
};
|
||||
if (spec.kind === "compose") {
|
||||
if (spec.kind === "compose" || spec.kind === "d601-compose") {
|
||||
if (target.compose === undefined) throw new Error(`${spec.serviceId} missing compose artifact consumer config`);
|
||||
return {
|
||||
...common,
|
||||
target: {
|
||||
kind: "compose",
|
||||
kind: spec.kind,
|
||||
runtimeHost: spec.kind === "d601-compose" ? "D601" : "main-server",
|
||||
workDir: target.compose.workDir,
|
||||
composeFile: target.compose.composeFile,
|
||||
composeService: target.compose.serviceName,
|
||||
containerName: target.compose.containerName,
|
||||
targetImage: options.targetImage ?? target.targetImage,
|
||||
@@ -1398,8 +1730,13 @@ function dryRunArtifactConsumerPlan(options: ArtifactRegistryOptions, spec: Arti
|
||||
},
|
||||
validation: [
|
||||
"D601 registry /v2 manifest exists for the commit tag",
|
||||
"loaded image labels match service id, source commit, and Dockerfile",
|
||||
"running Compose container image label matches the requested commit",
|
||||
spec.kind === "d601-compose"
|
||||
? "D601-pulled image labels match service id, source commit, and Dockerfile"
|
||||
: "loaded image labels match service id, source commit, and Dockerfile",
|
||||
spec.kind === "d601-compose"
|
||||
? "running D601 Compose container is recreated with a no-build override that points the service image at the artifact"
|
||||
: "running Compose container image label matches the requested commit",
|
||||
...(spec.kind === "d601-compose" ? ["running Compose container image label matches the requested commit"] : []),
|
||||
verificationBlocked
|
||||
? `blocked: ${spec.runtimeVerificationBlockReason}`
|
||||
: target.compose.requireHealthCommit
|
||||
@@ -1434,11 +1771,14 @@ function dryRunArtifactConsumerPlan(options: ArtifactRegistryOptions, spec: Arti
|
||||
}
|
||||
|
||||
function rollbackInfo(spec: ArtifactConsumerSpec, target: ArtifactConsumerTarget, environment: ArtifactDeployEnvironment, commit: string): Record<string, unknown> {
|
||||
if (spec.kind === "compose") {
|
||||
if (spec.kind === "compose" || spec.kind === "d601-compose") {
|
||||
const compose = target.compose;
|
||||
return {
|
||||
type: "compose-retag-recreate",
|
||||
type: spec.kind === "d601-compose" ? "d601-compose-retag-recreate" : "compose-retag-recreate",
|
||||
composeService: compose?.serviceName,
|
||||
containerName: compose?.containerName,
|
||||
workDir: compose?.workDir,
|
||||
composeFile: compose?.composeFile,
|
||||
previousImageHint: `Use docker image ls / docker inspect to find the previous labeled ${spec.serviceId} image id; Compose volumes are unchanged.`,
|
||||
commandShape: `bun scripts/cli.ts deploy apply --env ${environment} --service ${spec.serviceId}${environment === "prod" ? " --commit <previous-full-sha>" : ""}`,
|
||||
};
|
||||
@@ -1670,6 +2010,7 @@ async function deployServiceNow(options: ArtifactRegistryOptions): Promise<Recor
|
||||
const liveBlock = artifactConsumerLiveBlock(spec, options);
|
||||
if (liveBlock !== null) return liveBlock;
|
||||
if (spec.kind === "compose") return deployComposeArtifactNow(options, spec, target);
|
||||
if (spec.kind === "d601-compose") return deployD601ComposeArtifactNow(options, spec, target);
|
||||
return deployD601K3sArtifactNow(options, spec, target);
|
||||
}
|
||||
|
||||
@@ -1724,6 +2065,10 @@ function localHelp(): Record<string, unknown> {
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service code-queue-mgr --commit <full-sha> --dry-run [--provider-id D601]",
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service todo-note --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service todo-note --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service findjob --commit <full-sha> --dry-run [--provider-id D601]",
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service pipeline --commit <full-sha> --dry-run [--provider-id D601]",
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service met-nonlinear --commit <full-sha> --dry-run [--provider-id D601]",
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service k3sctl-adapter --commit <full-sha> --dry-run [--provider-id D601]",
|
||||
],
|
||||
firstStage: "install now writes the rendered systemd/Compose/config files and starts the registry",
|
||||
artifactConsumers: {
|
||||
@@ -1739,6 +2084,10 @@ function localHelp(): Record<string, unknown> {
|
||||
"bun scripts/cli.ts deploy apply --env prod --service oa-event-flow",
|
||||
"bun scripts/cli.ts deploy apply --env prod --service code-queue-mgr --dry-run",
|
||||
"bun scripts/cli.ts deploy apply --env prod --service todo-note",
|
||||
"bun scripts/cli.ts deploy apply --env prod --service findjob --dry-run",
|
||||
"bun scripts/cli.ts deploy apply --env prod --service pipeline --dry-run",
|
||||
"bun scripts/cli.ts deploy apply --env prod --service met-nonlinear --dry-run",
|
||||
"bun scripts/cli.ts deploy apply --env prod --service k3sctl-adapter --dry-run",
|
||||
],
|
||||
devCommands: [
|
||||
"bun scripts/cli.ts deploy apply --env dev --service frontend",
|
||||
@@ -1747,6 +2096,9 @@ function localHelp(): Record<string, unknown> {
|
||||
"bun scripts/cli.ts deploy apply --env dev --service oa-event-flow --dry-run",
|
||||
"bun scripts/cli.ts deploy apply --env dev --service code-queue-mgr --dry-run",
|
||||
"bun scripts/cli.ts deploy apply --env dev --service todo-note",
|
||||
"bun scripts/cli.ts deploy apply --env dev --service findjob --dry-run",
|
||||
"bun scripts/cli.ts deploy apply --env dev --service pipeline --dry-run",
|
||||
"bun scripts/cli.ts deploy apply --env dev --service met-nonlinear --dry-run",
|
||||
],
|
||||
rollbackShape: "rerun the same artifact consumer with a previous commit-pinned image",
|
||||
},
|
||||
|
||||
+13
-9
@@ -136,12 +136,14 @@ const nativeK3sCtrAddress = "/run/k3s/containerd/containerd.sock";
|
||||
const unideskRepoUrl = "https://github.com/pikasTech/unidesk";
|
||||
const d601MaintenanceDeployAllowedServiceIds = new Set<string>(["backend-core", "k3sctl-adapter", "code-queue"]);
|
||||
const devApplySupportedServiceIds = new Set<string>(["backend-core"]);
|
||||
const devArtifactConsumerServiceIds = new Set<string>(["baidu-netdisk", "code-queue-mgr", "decision-center", "frontend", "oa-event-flow", "project-manager", "todo-note"]);
|
||||
const devArtifactConsumerServiceIds = new Set<string>(["baidu-netdisk", "code-queue-mgr", "decision-center", "findjob", "frontend", "met-nonlinear", "oa-event-flow", "pipeline", "project-manager", "todo-note"]);
|
||||
const devArtifactConsumerProdDesiredFallbackServiceIds = new Set<string>(["code-queue-mgr", "oa-event-flow", "project-manager", "todo-note"]);
|
||||
const prodArtifactConsumerServiceIds = new Set<string>(["backend-core", "baidu-netdisk", "code-queue-mgr", "decision-center", "frontend", "oa-event-flow", "project-manager", "todo-note"]);
|
||||
const prodForbiddenTargetSideBuildServiceIds = new Set<string>(["backend-core", "baidu-netdisk", "decision-center", "frontend"]);
|
||||
const prodArtifactConsumerServiceIds = new Set<string>(["backend-core", "baidu-netdisk", "code-queue-mgr", "decision-center", "findjob", "frontend", "k3sctl-adapter", "met-nonlinear", "oa-event-flow", "pipeline", "project-manager", "todo-note"]);
|
||||
const prodForbiddenTargetSideBuildServiceIds = new Set<string>(["backend-core", "baidu-netdisk", "decision-center", "findjob", "frontend", "k3sctl-adapter", "met-nonlinear", "pipeline"]);
|
||||
const prodArtifactLiveApplyBlockedServiceIds = new Map<string, string>([
|
||||
["code-queue-mgr", "code-queue-mgr is the main-server Code Queue control-plane sidecar; live production apply requires explicit supervisor confirmation."],
|
||||
["met-nonlinear", "met-nonlinear is blocked for live artifact deploy because config.json points at docker/unidesk/Dockerfile.ml while the compose service is met-nonlinear-ts."],
|
||||
["k3sctl-adapter", "k3sctl-adapter is an infrastructure control bridge; this executor exposes artifact consumer plan/dry-run only. Real production deployment requires supervisor confirmation outside this task."],
|
||||
]);
|
||||
const deployEnvironmentTargets: Record<DeployEnvironment, DeployEnvironmentTarget> = {
|
||||
dev: {
|
||||
@@ -205,7 +207,7 @@ export function deployHelp(action: string | undefined = undefined): Record<strin
|
||||
},
|
||||
options: [
|
||||
{ name: "--file <path>", default: defaultDeployFile, description: "Desired-state manifest path relative to the repo root. JSON and ESM JS manifests are supported, for example deploy.json or develop.js. Local manifest apply allows k3sctl-adapter and explicit production code-queue controlled rollout on D601." },
|
||||
{ name: "--env <dev|prod>", description: "Read the named environment from origin/master:deploy.json. Dev apply supports backend-core target-side rollout plus reviewed artifact consumers for frontend, baidu-netdisk, decision-center, project-manager, oa-event-flow, code-queue-mgr, and todo-note. Prod apply uses the D601 registry artifact consumer for reviewed services; code-queue-mgr live apply is supervisor-gated." },
|
||||
{ name: "--env <dev|prod>", description: "Read the named environment from origin/master:deploy.json. Dev apply supports backend-core target-side rollout plus reviewed artifact consumers for frontend, baidu-netdisk, decision-center, project-manager, oa-event-flow, code-queue-mgr, todo-note, findjob, pipeline, and met-nonlinear. Prod apply uses the D601 registry artifact consumer for reviewed services; code-queue-mgr and D601 direct infrastructure/incomplete contracts are dry-run or supervisor-gated." },
|
||||
{ name: "--service <id>", description: "Limit reconcile to one service from the manifest." },
|
||||
{ name: "--commit <full-sha>", description: "Prod artifact rollback/apply override for a selected service; the image must already exist in D601 registry." },
|
||||
{ name: "--dry-run", description: "Prepare and validate without mutating the target service." },
|
||||
@@ -767,7 +769,7 @@ function isDevK3sDeployService(service: UniDeskMicroserviceConfig): boolean {
|
||||
}
|
||||
|
||||
function isDevArtifactConsumerService(service: UniDeskMicroserviceConfig): boolean {
|
||||
return service.deployment.mode === "k3sctl-managed"
|
||||
return (service.deployment.mode === "k3sctl-managed" || isDirectComposeDeployMode(service))
|
||||
&& devArtifactConsumerServiceIds.has(service.id);
|
||||
}
|
||||
|
||||
@@ -791,10 +793,12 @@ function selectServices(config: UniDeskConfig, manifest: DeployManifest, service
|
||||
return selected.map((desired) => {
|
||||
if (manifest.environment === "dev") {
|
||||
const service = devK3sDeployService(desired.id);
|
||||
if (service === undefined) {
|
||||
throw new Error(`deploy --env dev service ${desired.id} is not enabled for direct rollout in the current CI-only phase`);
|
||||
if (service !== undefined) return { desired, config: service };
|
||||
const directService = configById.get(desired.id);
|
||||
if (directService !== undefined && isDirectComposeDeployMode(directService) && devArtifactConsumerServiceIds.has(directService.id)) {
|
||||
return { desired, config: directService };
|
||||
}
|
||||
return { desired, config: service };
|
||||
throw new Error(`deploy --env dev service ${desired.id} is not enabled for direct rollout in the current CI-only phase`);
|
||||
}
|
||||
const service = configById.get(desired.id) ?? coreDeployService(config, desired.id, manifest.environment);
|
||||
if (service === undefined) throw new Error(`deploy manifest service ${desired.id} is not present in config.json microservices or supported core deploy services`);
|
||||
@@ -2885,7 +2889,7 @@ export async function runDeployCommand(config: UniDeskConfig | null, args: strin
|
||||
}
|
||||
const unsupported = unsupportedDevApplyServices(manifest, options.serviceId);
|
||||
if (unsupported.length > 0) {
|
||||
throw new Error(`deploy apply --env dev currently supports backend-core target-side rollout plus frontend/baidu-netdisk/decision-center/project-manager/oa-event-flow/code-queue-mgr/todo-note artifact consumers; unsupported selected services: ${unsupported.join(", ")}. Use ci run-dev-e2e for smoke verification.`);
|
||||
throw new Error(`deploy apply --env dev currently supports backend-core target-side rollout plus frontend/baidu-netdisk/decision-center/project-manager/oa-event-flow/code-queue-mgr/todo-note/findjob/pipeline/met-nonlinear artifact consumers; unsupported selected services: ${unsupported.join(", ")}. Use ci run-dev-e2e for smoke verification.`);
|
||||
}
|
||||
const devArtifactServices = selectedDevArtifactServicesWithProdFallback(manifest, options.serviceId);
|
||||
const devTargetServices = selectedDevTargetServices(manifest, options.serviceId);
|
||||
|
||||
Reference in New Issue
Block a user