feat: add v02 device-pod env reuse boot path
This commit is contained in:
+155
-20
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user