fix: parameterize AgentRun base image
This commit is contained in:
@@ -95,6 +95,8 @@ controlPlane:
|
||||
containerfile: deploy/container/Containerfile
|
||||
repository: agentrun-mgr-env
|
||||
network: host
|
||||
buildArgs:
|
||||
BUN_IMAGE: oven/bun:1.2.15-alpine
|
||||
httpProxy: http://127.0.0.1:10808
|
||||
httpsProxy: http://127.0.0.1:10808
|
||||
noProxy:
|
||||
@@ -225,6 +227,8 @@ controlPlane:
|
||||
containerfile: deploy/container/Containerfile
|
||||
repository: agentrun-mgr-env
|
||||
network: host
|
||||
buildArgs:
|
||||
BUN_IMAGE: oven/bun:1-alpine
|
||||
httpProxy: http://127.0.0.1:18789
|
||||
httpsProxy: http://127.0.0.1:18789
|
||||
noProxy:
|
||||
|
||||
@@ -140,6 +140,7 @@ export interface AgentRunImageBuildSpec {
|
||||
readonly containerfile: string;
|
||||
readonly repository: string;
|
||||
readonly network: string;
|
||||
readonly buildArgs: Readonly<Record<string, string>>;
|
||||
readonly httpProxy: string | null;
|
||||
readonly httpsProxy: string | null;
|
||||
readonly noProxy: readonly string[];
|
||||
@@ -247,6 +248,7 @@ export function agentRunLaneSummary(spec: AgentRunLaneSpec): Record<string, unkn
|
||||
containerfile: spec.deployment.manager.imageBuild.containerfile,
|
||||
repository: spec.deployment.manager.imageBuild.repository,
|
||||
network: spec.deployment.manager.imageBuild.network,
|
||||
buildArgNames: Object.keys(spec.deployment.manager.imageBuild.buildArgs).sort(),
|
||||
proxyConfigured: spec.deployment.manager.imageBuild.httpProxy !== null || spec.deployment.manager.imageBuild.httpsProxy !== null,
|
||||
noProxyCount: spec.deployment.manager.imageBuild.noProxy.length,
|
||||
envIdentityFileCount: spec.deployment.manager.imageBuild.envIdentityFiles.length,
|
||||
@@ -495,6 +497,7 @@ function parseImageBuild(input: Record<string, unknown>, path: string): AgentRun
|
||||
containerfile: relativePathField(input, "containerfile", path),
|
||||
repository: stringField(input, "repository", path),
|
||||
network: stringField(input, "network", path),
|
||||
buildArgs: stringRecordField(recordField(input, "buildArgs", path), `${path}.buildArgs`),
|
||||
httpProxy: optionalStringField(input, "httpProxy", path) ?? null,
|
||||
httpsProxy: optionalStringField(input, "httpsProxy", path) ?? null,
|
||||
noProxy: stringArrayField(input, "noProxy", path),
|
||||
@@ -631,6 +634,16 @@ function stringArrayField(obj: Record<string, unknown>, key: string, path: strin
|
||||
});
|
||||
}
|
||||
|
||||
function stringRecordField(obj: Record<string, unknown>, path: string): Readonly<Record<string, string>> {
|
||||
const result: Record<string, string> = {};
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
if (!/^[A-Za-z_][A-Za-z0-9_]*$/u.test(key)) throw new Error(`${path}.${key} must be a valid build arg name`);
|
||||
if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${path}.${key} must be a non-empty string`);
|
||||
result[key] = value.trim();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function enumField<T extends string>(obj: Record<string, unknown>, key: string, path: string, values: readonly T[]): T {
|
||||
const value = stringField(obj, key, path);
|
||||
if (!values.includes(value as T)) throw new Error(`${path}.${key} must be one of ${values.join(", ")}`);
|
||||
|
||||
+16
-1
@@ -2674,6 +2674,7 @@ async function triggerCurrentYamlLane(config: UniDeskConfig, options: TriggerOpt
|
||||
imageBuild: {
|
||||
repository: `${spec.ci.registryPrefix}/${spec.deployment.manager.imageBuild.repository}`,
|
||||
containerfile: spec.deployment.manager.imageBuild.containerfile,
|
||||
buildArgNames: Object.keys(spec.deployment.manager.imageBuild.buildArgs).sort(),
|
||||
timeoutSeconds: spec.deployment.manager.imageBuild.timeoutSeconds,
|
||||
pollSeconds: spec.deployment.manager.imageBuild.pollSeconds,
|
||||
proxyConfigured: spec.deployment.manager.imageBuild.httpProxy !== null || spec.deployment.manager.imageBuild.httpsProxy !== null,
|
||||
@@ -3296,6 +3297,9 @@ function yamlLaneBuildImageSubmitScript(spec: AgentRunLaneSpec, sourceCommit: st
|
||||
const noProxy = build.noProxy.join(",");
|
||||
const imageRepository = `${spec.ci.registryPrefix}/${build.repository}`;
|
||||
const stateDir = `/tmp/unidesk-agentrun-build-${spec.nodeId}-${spec.lane}`;
|
||||
const buildArgs = Object.entries(build.buildArgs)
|
||||
.sort(([left], [right]) => left.localeCompare(right))
|
||||
.map(([key, value]) => `${key}=${value}`);
|
||||
const script = [
|
||||
"set -eu",
|
||||
`workspace=${shQuote(spec.source.workspace)}`,
|
||||
@@ -3309,14 +3313,17 @@ function yamlLaneBuildImageSubmitScript(spec: AgentRunLaneSpec, sourceCommit: st
|
||||
`https_proxy_value=${build.httpsProxy === null ? "''" : shQuote(build.httpsProxy)}`,
|
||||
`no_proxy_value=${shQuote(noProxy)}`,
|
||||
`env_identity_files=${shQuote(JSON.stringify(build.envIdentityFiles))}`,
|
||||
`build_args_json=${shQuote(JSON.stringify(buildArgs))}`,
|
||||
"mkdir -p \"$state_dir\"",
|
||||
"cd \"$workspace\"",
|
||||
"git checkout \"$source_commit\"",
|
||||
"env_identity=$(ENV_IDENTITY_FILES=\"$env_identity_files\" node <<'NODE'",
|
||||
"env_identity=$(ENV_IDENTITY_FILES=\"$env_identity_files\" BUILD_ARGS_JSON=\"$build_args_json\" node <<'NODE'",
|
||||
"const { createHash } = require('node:crypto');",
|
||||
"const { readFileSync, existsSync } = require('node:fs');",
|
||||
"const files = JSON.parse(process.env.ENV_IDENTITY_FILES || '[]');",
|
||||
"const buildArgs = JSON.parse(process.env.BUILD_ARGS_JSON || '[]');",
|
||||
"const hash = createHash('sha256');",
|
||||
"for (const item of buildArgs) { hash.update('build-arg'); hash.update('\\0'); hash.update(item); hash.update('\\0'); }",
|
||||
"for (const file of files) { hash.update(file); hash.update('\\0'); if (existsSync(file)) hash.update(readFileSync(file)); hash.update('\\0'); }",
|
||||
"process.stdout.write(hash.digest('hex').slice(0, 24));",
|
||||
"NODE",
|
||||
@@ -3343,6 +3350,14 @@ function yamlLaneBuildImageSubmitScript(spec: AgentRunLaneSpec, sourceCommit: st
|
||||
" if [ -n \"$http_proxy_value\" ]; then args=\"$args --build-arg HTTP_PROXY=$http_proxy_value --build-arg http_proxy=$http_proxy_value\"; fi",
|
||||
" if [ -n \"$https_proxy_value\" ]; then args=\"$args --build-arg HTTPS_PROXY=$https_proxy_value --build-arg https_proxy=$https_proxy_value\"; fi",
|
||||
" if [ -n \"$no_proxy_value\" ]; then args=\"$args --build-arg NO_PROXY=$no_proxy_value --build-arg no_proxy=$no_proxy_value\"; fi",
|
||||
" build_arg_values=$(BUILD_ARGS_JSON=\"$build_args_json\" node <<'NODE'",
|
||||
"const values = JSON.parse(process.env.BUILD_ARGS_JSON || '[]');",
|
||||
"for (const value of values) console.log(value);",
|
||||
"NODE",
|
||||
" )",
|
||||
" while IFS= read -r build_arg_value; do [ -n \"$build_arg_value\" ] && args=\"$args --build-arg $build_arg_value\"; done <<EOF",
|
||||
"$build_arg_values",
|
||||
"EOF",
|
||||
" if docker image inspect \"$image\" >/dev/null 2>&1; then build_status=reused; else docker build $args -f \"$containerfile\" -t \"$image\" \"$context_dir\"; build_status=built; fi",
|
||||
" docker push \"$image\"",
|
||||
" digest=$(docker inspect --format='{{index .RepoDigests 0}}' \"$image\" 2>/dev/null | sed 's/^.*@//' || true)",
|
||||
|
||||
Reference in New Issue
Block a user