feat: add v02 device-pod env reuse boot path

This commit is contained in:
Codex
2026-05-29 22:49:08 +08:00
parent 56b720efa8
commit d1ffc007e4
14 changed files with 901 additions and 74 deletions
+155 -20
View File
@@ -76,6 +76,7 @@ const codexApiProfileBaseUrl = process.env.HWLAB_G14_CODEX_API_PROFILE_BASE_URL
const codexApiForwarderPort = process.env.HWLAB_G14_CODEX_API_FORWARDER_PORT || "49280";
const codexApiForwarderUpstreamBaseUrl = process.env.HWLAB_G14_CODEX_API_UPSTREAM_BASE_URL || "https://hyueapi.com";
const sourceCommitPattern = /^[a-f0-9]{7,40}$/u;
const v02EnvReuseRuntimeMode = "env-reuse-git-mirror-checkout";
const primitiveValidationTasks = Object.freeze([
{
name: "repo-reports-guard",
@@ -407,8 +408,47 @@ function catalogServiceById(catalog, serviceId) {
return (catalog?.services ?? []).find((service) => service?.serviceId === serviceId) ?? null;
}
function v02EnvReuseEnabled(catalog, serviceId) {
const service = catalogServiceById(catalog, serviceId);
return service?.runtimeMode === v02EnvReuseRuntimeMode || service?.envReuse === true;
}
function bootShForService(deployService, serviceId) {
const value = deployService?.bootSh || deployService?.bootScript || `deploy/runtime/boot/${serviceId}.sh`;
const text = String(value).replaceAll("\\", "/").replace(/^\.\//u, "");
assert.ok(text && !text.startsWith("/") && !text.split("/").includes(".."), `${serviceId} boot script must be repo-relative`);
return text;
}
function bootMetadataForService({ args, catalog, deployService, serviceId, source }) {
const catalogService = catalogServiceById(catalog, serviceId);
const environmentImage = catalogService?.environmentImage ?? imageFor(args.registryPrefix, `${serviceId}-env`, `env-${String(catalogService?.environmentInputHash ?? source.full).slice(0, 12)}`);
const environmentDigest = catalogService?.environmentDigest ?? catalogService?.digest ?? null;
return {
runtimeMode: v02EnvReuseRuntimeMode,
environmentImage,
environmentDigest,
environmentInputHash: catalogService?.environmentInputHash ?? null,
codeInputHash: catalogService?.codeInputHash ?? null,
bootRepo: catalogService?.bootRepo ?? args.sourceRepo,
bootCommit: catalogService?.bootCommit ?? source.full,
bootSh: catalogService?.bootSh ?? bootShForService(deployService, serviceId)
};
}
function runtimeArtifactForService({ catalog, serviceId, source, registryPrefix, useDeployImages = false, digestPin = false }) {
const catalogService = catalogServiceById(catalog, serviceId);
if (catalogService?.runtimeMode === v02EnvReuseRuntimeMode || catalogService?.envReuse === true) {
const environmentImage = catalogService.environmentImage ?? imageFor(registryPrefix, `${serviceId}-env`, `env-${String(catalogService.environmentInputHash ?? source.full).slice(0, 12)}`);
const runtimeImage = digestPin && useDeployImages ? digestPinnedImage(environmentImage, catalogService.environmentDigest ?? catalogService.digest) : environmentImage;
return {
image: runtimeImage,
imageTag: imageTagFromReference(environmentImage) ?? source.imageTag ?? source.short,
commit: catalogService.bootCommit ?? source.full,
runtimeMode: v02EnvReuseRuntimeMode,
environmentDigest: catalogService.environmentDigest ?? catalogService.digest ?? null
};
}
const fallbackImageTag = source.imageTag ?? source.short;
const image = useDeployImages && catalogService?.image
? catalogService.image
@@ -480,17 +520,44 @@ function artifactCatalogSkeleton({ args, source }) {
},
allowedProfiles: [environment],
forbiddenProfiles: args.lane === "v02" ? ["dev", "prod"] : ["prod"],
services: serviceIdsForLane(args.lane).map((serviceId) => ({
serviceId,
profile: environment,
namespace,
commitId: tag,
sourceCommitId: source.full,
image: imageFor(args.registryPrefix, serviceId, tag),
imageTag: tag,
digest: null,
buildBackend: "contract-skeleton"
}))
services: serviceIdsForLane(args.lane).map((serviceId) => artifactCatalogSkeletonService({ args, source, serviceId, environment, namespace, tag }))
};
}
function artifactCatalogSkeletonService({ args, source, serviceId, environment, namespace, tag }) {
const base = {
serviceId,
profile: environment,
namespace,
commitId: tag,
sourceCommitId: source.full,
image: imageFor(args.registryPrefix, serviceId, tag),
imageTag: tag,
digest: null,
buildBackend: "contract-skeleton"
};
if (args.lane !== "v02" || serviceId !== "hwlab-device-pod") return base;
const environmentImage = imageFor(args.registryPrefix, `${serviceId}-env`, `env-${String(source.full).slice(0, 12)}`);
return {
...base,
image: environmentImage,
imageTag: imageTagFromReference(environmentImage),
runtimeMode: v02EnvReuseRuntimeMode,
envReuse: true,
environmentImage,
environmentDigest: null,
environmentInputHash: null,
bootRepo: args.sourceRepo,
bootCommit: source.full,
bootSh: `deploy/runtime/boot/${serviceId}.sh`,
codeInputHash: null,
bootEnvEvidence: {
env: {
HWLAB_BOOT_REPO: args.sourceRepo,
HWLAB_BOOT_COMMIT: source.full,
HWLAB_BOOT_SH: `deploy/runtime/boot/${serviceId}.sh`
}
}
};
}
@@ -718,6 +785,8 @@ function transformWorkloads({ workloads, deploy, catalog, source, registryPrefix
const deployService = deployServices.get(serviceId);
if (!deployService) continue;
const artifact = runtimeArtifactForService({ catalog, serviceId, source, registryPrefix, useDeployImages, digestPin });
const envReuse = profile === "v02" && v02EnvReuseEnabled(catalog, serviceId);
const bootMetadata = envReuse ? bootMetadataForService({ args: { sourceRepo: deploy?.lanes?.v02?.sourceRepo || defaultSourceRepo, registryPrefix }, catalog, deployService, serviceId, source }) : null;
const image = artifact.image;
const runtimeCommit = artifact.commit;
const runtimeImageTag = artifact.imageTag;
@@ -739,6 +808,31 @@ function transformWorkloads({ workloads, deploy, catalog, source, registryPrefix
upsertEnv(container.env, "HWLAB_GITOPS_TARGET", gitopsTarget);
upsertEnv(container.env, "HWLAB_GITOPS_PROFILE", profileLabel);
upsertEnv(container.env, "HWLAB_GITOPS_SOURCE_COMMIT", source.full);
if (bootMetadata) {
upsertEnv(container.env, "HWLAB_RUNTIME_MODE", bootMetadata.runtimeMode);
upsertEnv(container.env, "HWLAB_BOOT_REPO", bootMetadata.bootRepo);
upsertEnv(container.env, "HWLAB_BOOT_COMMIT", bootMetadata.bootCommit);
upsertEnv(container.env, "HWLAB_BOOT_SH", bootMetadata.bootSh);
upsertEnv(container.env, "HWLAB_BOOT_READ_URL", defaultV02GitReadUrl);
upsertEnv(container.env, "HWLAB_ENVIRONMENT_IMAGE", bootMetadata.environmentImage ?? "");
upsertEnv(container.env, "HWLAB_ENVIRONMENT_DIGEST", bootMetadata.environmentDigest ?? "");
upsertEnv(container.env, "HWLAB_ENVIRONMENT_INPUT_HASH", bootMetadata.environmentInputHash ?? "");
upsertEnv(container.env, "HWLAB_CODE_INPUT_HASH", bootMetadata.codeInputHash ?? "");
upsertEnv(container.env, "HWLAB_IMAGE_DIGEST", bootMetadata.environmentDigest ?? "unknown");
annotate(podTemplate.metadata, {
"hwlab.pikastech.local/runtime-mode": bootMetadata.runtimeMode,
"hwlab.pikastech.local/boot-repo": bootMetadata.bootRepo,
"hwlab.pikastech.local/boot-commit": bootMetadata.bootCommit,
"hwlab.pikastech.local/boot-sh": bootMetadata.bootSh,
"hwlab.pikastech.local/environment-digest": bootMetadata.environmentDigest ?? "not_published",
"hwlab.pikastech.local/environment-input-hash": bootMetadata.environmentInputHash ?? "unknown",
"hwlab.pikastech.local/code-input-hash": bootMetadata.codeInputHash ?? "unknown"
});
label(podTemplate.metadata, {
"hwlab.pikastech.local/runtime-mode": bootMetadata.runtimeMode,
"hwlab.pikastech.local/boot-commit": bootMetadata.bootCommit
});
}
if (serviceId === "hwlab-cloud-api" || serviceId === "hwlab-edge-proxy") {
upsertEnv(container.env, "HWLAB_PUBLIC_ENDPOINT", runtimeEndpoint);
}
@@ -1033,6 +1127,7 @@ function prepareSourceScript() {
"git remote set-url origin \"$git_read_url\"",
"git checkout \"$(params.revision)\"",
"test \"$(git rev-parse HEAD)\" = \"$(params.revision)\"",
"git merge-base --is-ancestor \"$(params.revision)\" \"origin/$(params.source-branch)\" || { echo '{\"event\":\"source-ancestry\",\"status\":\"failed\",\"revision\":\"'\"$(params.revision)\"'\",\"sourceBranch\":\"'\"$(params.source-branch)\"'\"}'; exit 32; }",
"ci_timing_emit source-clone succeeded \"$source_clone_started_ms\"",
"catalog_path=\"$(params.catalog-path)\"",
"mkdir -p \"$(dirname \"$catalog_path\")\"",
@@ -1064,7 +1159,14 @@ function prepareSourceScript() {
"const namespace = 'hwlab-v02';",
"const selected = (selectedServices || '').split(',').filter(Boolean);",
"const serviceIds = selected.length ? selected : (deploy.services || []).map((service) => service.serviceId);",
"const services = serviceIds.map((serviceId) => ({ serviceId, profile: 'v02', namespace, commitId: tag, sourceCommitId: revision, image: `${registryPrefix}/${serviceId}:${tag}`, imageTag: tag, digest: null, buildBackend: 'contract-skeleton' }));",
"const services = serviceIds.map((serviceId) => {",
" const service = { serviceId, profile: 'v02', namespace, commitId: tag, sourceCommitId: revision, image: `${registryPrefix}/${serviceId}:${tag}`, imageTag: tag, digest: null, buildBackend: 'contract-skeleton' };",
" if (serviceId === 'hwlab-device-pod') {",
" const environmentImage = `${registryPrefix}/${serviceId}-env:env-${revision.slice(0, 12)}`;",
" Object.assign(service, { image: environmentImage, imageTag: environmentImage.slice(environmentImage.lastIndexOf(':') + 1), runtimeMode: 'env-reuse-git-mirror-checkout', envReuse: true, environmentImage, environmentDigest: null, environmentInputHash: null, codeInputHash: null, bootRepo: 'git@github.com:pikasTech/HWLAB.git', bootCommit: revision, bootSh: 'deploy/runtime/boot/hwlab-device-pod.sh', bootEnvEvidence: { env: { HWLAB_BOOT_REPO: 'git@github.com:pikasTech/HWLAB.git', HWLAB_BOOT_COMMIT: revision, HWLAB_BOOT_SH: 'deploy/runtime/boot/hwlab-device-pod.sh', HWLAB_ENVIRONMENT_IMAGE: environmentImage, HWLAB_ENVIRONMENT_DIGEST: '' } } });",
" }",
" return service;",
"});",
"fs.mkdirSync(path.dirname(catalogPath), { recursive: true });",
"fs.writeFileSync(catalogPath, JSON.stringify({ catalogVersion: 'v1', kind: 'hwlab-artifact-catalog', environment: 'v02', profile: 'v02', namespace, endpoint: 'http://74.48.78.17:19667', commitId: tag, artifactState: 'contract-skeleton', publish: { registryPrefix, sourceCommitId: revision, imageTag: tag, publishedAt: null }, allowedProfiles: ['v02'], forbiddenProfiles: ['dev', 'prod'], services }, null, 2) + '\\n');",
"NODE",
@@ -1130,7 +1232,7 @@ echo '{"event":"ci-base-image","phase":"plan-artifacts","image":"${ciToolsRunner
for tool in node git; do command -v "$tool" >/dev/null 2>&1 || { echo '{"event":"ci-base-image","phase":"plan-artifacts","ok":false,"reason":"missing-tool","tool":"'"$tool"'"}'; exit 31; }; done
cd /workspace/source/repo
test "$(git rev-parse HEAD)" = "$(params.revision)"
node scripts/g14-ci-plan.mjs --target-ref HEAD --deploy-json deploy/deploy.json --artifact-catalog "$(params.catalog-path)" --registry-prefix "$(params.registry-prefix)" --services "$(params.services)" > /workspace/source/ci-plan.json
node scripts/g14-ci-plan.mjs --lane "$(params.lane)" --target-ref HEAD --deploy-json deploy/deploy.json --artifact-catalog "$(params.catalog-path)" --registry-prefix "$(params.registry-prefix)" --services "$(params.services)" > /workspace/source/ci-plan.json
node - <<'NODE'
const fs = require("node:fs");
const plan = JSON.parse(fs.readFileSync("/workspace/source/ci-plan.json", "utf8"));
@@ -1138,7 +1240,23 @@ const selected = String(process.env.HWLAB_SELECTED_SERVICES || "").split(",").ma
const allServices = selected.length > 0 ? selected : ${JSON.stringify(defaultServiceIds)};
const affected = new Set(plan.affectedServices || []);
const selectedSet = new Set(selected);
const entries = allServices.map((serviceId) => ({ serviceId, selected: selectedSet.has(serviceId), affected: selectedSet.has(serviceId) && affected.has(serviceId) }));
const byService = new Map((plan.services || []).map((service) => [service.serviceId, service]));
const entries = allServices.map((serviceId) => {
const service = byService.get(serviceId) || {};
const serviceSelected = selectedSet.has(serviceId);
const rolloutAffected = serviceSelected && affected.has(serviceId);
const envReuse = service.runtimeMode === "env-reuse-git-mirror-checkout" || service.envReuse === true;
const buildRequired = envReuse ? service.envChanged === true : rolloutAffected;
return {
serviceId,
selected: serviceSelected,
affected: buildRequired,
rolloutAffected,
runtimeMode: service.runtimeMode || "service-image",
envChanged: service.envChanged ?? null,
codeChanged: service.codeChanged ?? null
};
});
for (const entry of entries) {
fs.writeFileSync("/tekton/results/affected-" + entry.serviceId, entry.affected ? "true" : "false");
}
@@ -1147,6 +1265,7 @@ fs.writeFileSync("/workspace/source/affected-services.json", JSON.stringify({
affectedServices: plan.affectedServices || [],
reusedServices: plan.reusedServices || [],
buildSkippedCount: plan.buildSkippedCount || 0,
services: plan.services || [],
entries
}, null, 2) + String.fromCharCode(10));
console.log(JSON.stringify({ event: "g14-ci-plan", sourceCommitId: plan.sourceCommitId, affectedServices: plan.affectedServices || [], reusedServices: plan.reusedServices || [], buildSkippedCount: plan.buildSkippedCount || 0 }));
@@ -1178,11 +1297,15 @@ if [ -s /workspace/source/affected-services.json ] && ! node -e 'const fs=requir
const fs = require("node:fs");
const serviceId = process.argv[2];
const catalog = JSON.parse(fs.readFileSync(process.env.HWLAB_ARTIFACT_CATALOG_PATH, "utf8"));
const plan = fs.existsSync("/workspace/source/affected-services.json") ? JSON.parse(fs.readFileSync("/workspace/source/affected-services.json", "utf8")) : {};
const service = (catalog.services || []).find((item) => item.serviceId === serviceId) || {};
const image = service.image || "";
const digest = service.digest || "not_published";
const planned = (plan.services || []).find((item) => item.serviceId === serviceId) || {};
const envReuse = planned.runtimeMode === "env-reuse-git-mirror-checkout" || service.runtimeMode === "env-reuse-git-mirror-checkout" || planned.envReuse === true || service.envReuse === true;
const image = envReuse ? (service.environmentImage || service.image || "") : (service.image || "");
const digest = envReuse ? (service.environmentDigest || service.digest || "not_published") : (service.digest || "not_published");
const imageTag = service.imageTag || (image.includes(":") ? image.slice(image.lastIndexOf(":") + 1) : "");
const repository = image.includes(":") ? image.slice(0, image.lastIndexOf(":")) : image;
const revision = process.env.HWLAB_SOURCE_REVISION || planned.bootCommit || service.bootCommit || service.sourceCommitId || service.commitId || imageTag;
const values = {
"service-id": serviceId,
status: /^sha256:[a-f0-9]{64}$/.test(digest) ? "reused" : "blocked_reuse_unavailable",
@@ -1190,11 +1313,17 @@ const values = {
"image-tag": imageTag,
digest,
"repository-digest": /^sha256:[a-f0-9]{64}$/.test(digest) && repository ? repository + "@" + digest : "",
"source-commit-id": service.sourceCommitId || service.commitId || imageTag,
"component-input-hash": service.componentInputHash || "",
"source-commit-id": envReuse ? revision : (service.sourceCommitId || service.commitId || imageTag),
"component-input-hash": planned.componentInputHash || service.componentInputHash || "",
"environment-input-hash": planned.environmentInputHash || service.environmentInputHash || "",
"code-input-hash": planned.codeInputHash || service.codeInputHash || "",
"runtime-mode": envReuse ? "env-reuse-git-mirror-checkout" : "service-image",
"boot-repo": planned.bootRepo || service.bootRepo || "",
"boot-commit": envReuse ? revision : (service.bootCommit || ""),
"boot-sh": planned.bootSh || service.bootSh || "",
"build-created-at": service.buildCreatedAt || "",
"build-backend": "reused-catalog",
"reused-from": service.componentInputHash || service.commitId || imageTag || "catalog"
"build-backend": envReuse ? "reused-env-catalog" : "reused-catalog",
"reused-from": (envReuse ? service.environmentInputHash : service.componentInputHash) || service.commitId || imageTag || "catalog"
};
for (const [name, value] of Object.entries(values)) fs.writeFileSync("/tekton/results/" + name, String(value || ""));
NODE
@@ -1895,6 +2024,12 @@ const serviceResultFields = Object.freeze([
"repository-digest",
"source-commit-id",
"component-input-hash",
"environment-input-hash",
"code-input-hash",
"runtime-mode",
"boot-repo",
"boot-commit",
"boot-sh",
"build-created-at",
"build-backend",
"reused-from"