feat: add baseos raw image builds
This commit is contained in:
@@ -9,6 +9,7 @@ import * as plugins from './plugins.js';
|
||||
import type {
|
||||
IBaseOsImageArtifactResult,
|
||||
IBaseOsImageJob,
|
||||
TBaseOsImageKind,
|
||||
} from './types.js';
|
||||
|
||||
export interface IBaseOsImageBuilderOptions {
|
||||
@@ -23,22 +24,22 @@ export class BaseOsImageBuilder {
|
||||
artifact: IBaseOsImageArtifactResult;
|
||||
logs: string[];
|
||||
}> {
|
||||
if (jobArg.architecture === 'rpi') {
|
||||
throw new Error('Raspberry Pi image builds require a raw-image preset and are not supported by the current isocreator ISO pipeline yet');
|
||||
}
|
||||
|
||||
const logs: string[] = [];
|
||||
const imageKind = this.getImageKind(jobArg);
|
||||
const jobDir = path.join(this.options.workdir, jobArg.id);
|
||||
const outputDir = path.join(jobDir, 'output');
|
||||
await fsp.rm(jobDir, { recursive: true, force: true });
|
||||
await fsp.mkdir(outputDir, { recursive: true });
|
||||
|
||||
const filename = jobArg.architecture === 'amd64' ? 'baseos.iso' : 'baseos-arm64.iso';
|
||||
const filename = this.getArtifactFilename(jobArg, imageKind);
|
||||
const outputPath = path.join(outputDir, filename);
|
||||
const configPath = path.join(jobDir, 'isocreator.config.json');
|
||||
await fsp.writeFile(configPath, `${JSON.stringify(this.createIsoCreatorConfig(jobArg, outputDir, filename), null, 2)}\n`);
|
||||
const isoCreatorConfig = imageKind === 'balena-raw'
|
||||
? this.createRawImageConfig(jobArg, outputDir, filename)
|
||||
: this.createIsoCreatorConfig(jobArg, outputDir, filename);
|
||||
await fsp.writeFile(configPath, `${JSON.stringify(isoCreatorConfig, null, 2)}\n`);
|
||||
|
||||
logs.push(`Starting isocreator for ${jobArg.architecture}`);
|
||||
logs.push(`Starting isocreator for ${jobArg.architecture} ${imageKind}`);
|
||||
await this.runIsoCreator(configPath, logs);
|
||||
|
||||
const stat = await fsp.stat(outputPath);
|
||||
@@ -51,7 +52,7 @@ export class BaseOsImageBuilder {
|
||||
bucketName: jobArg.s3Descriptor.bucketName,
|
||||
key: jobArg.artifactKey,
|
||||
filename,
|
||||
contentType: 'application/x-iso9660-image',
|
||||
contentType: this.getContentType(filename, imageKind),
|
||||
size: stat.size,
|
||||
sha256,
|
||||
createdAt: Date.now(),
|
||||
@@ -66,6 +67,7 @@ export class BaseOsImageBuilder {
|
||||
const envFile = this.createBaseOsEnvFile(jobArg);
|
||||
return {
|
||||
version: '1.0',
|
||||
imageKind: 'iso',
|
||||
...(jobArg.sourceImageUrl
|
||||
? {
|
||||
source: {
|
||||
@@ -136,6 +138,85 @@ export class BaseOsImageBuilder {
|
||||
};
|
||||
}
|
||||
|
||||
private createRawImageConfig(jobArg: IBaseOsImageJob, outputDirArg: string, filenameArg: string) {
|
||||
if (!jobArg.sourceImageUrl) {
|
||||
throw new Error('sourceImageUrl is required for balena-raw BaseOS image builds');
|
||||
}
|
||||
|
||||
return {
|
||||
version: '1.0',
|
||||
imageKind: 'raw-image',
|
||||
source: {
|
||||
type: 'url',
|
||||
url: jobArg.sourceImageUrl,
|
||||
},
|
||||
output: {
|
||||
filename: filenameArg,
|
||||
path: outputDirArg,
|
||||
},
|
||||
...(jobArg.wifi?.ssid
|
||||
? {
|
||||
network: {
|
||||
wifi: jobArg.wifi,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
raw_image: {
|
||||
sourceFormat: 'auto',
|
||||
bootPartition: '/dev/sda1',
|
||||
outputCompression: filenameArg.endsWith('.xz') ? 'xz' : 'none',
|
||||
},
|
||||
balena_os: {
|
||||
hostname: jobArg.hostname || `baseos-${jobArg.id.slice(0, 8)}`,
|
||||
sshPublicKeys: jobArg.sshPublicKey ? [jobArg.sshPublicKey] : [],
|
||||
configJson: {
|
||||
serveZone: {
|
||||
baseos: {
|
||||
buildId: jobArg.id,
|
||||
cloudlyUrl: jobArg.cloudlyUrl,
|
||||
provisioningToken: jobArg.provisioningToken,
|
||||
},
|
||||
},
|
||||
},
|
||||
baseOsEnv: {
|
||||
BASEOS_CLOUDLY_URL: jobArg.cloudlyUrl,
|
||||
BASEOS_JOIN_TOKEN: jobArg.provisioningToken,
|
||||
BASEOS_STATE_PATH: '/data/baseos/state.json',
|
||||
BASEOS_HEARTBEAT_INTERVAL_MS: '60000',
|
||||
SERVEZONE_RUNTIME: 'baseos',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private getImageKind(jobArg: IBaseOsImageJob): TBaseOsImageKind {
|
||||
if (jobArg.imageKind) {
|
||||
return jobArg.imageKind;
|
||||
}
|
||||
if (jobArg.architecture === 'rpi') {
|
||||
return 'balena-raw';
|
||||
}
|
||||
if (jobArg.sourceImageUrl && /\.(img|img\.xz|zip)(\?|$)/i.test(jobArg.sourceImageUrl)) {
|
||||
return 'balena-raw';
|
||||
}
|
||||
return 'ubuntu-iso';
|
||||
}
|
||||
|
||||
private getArtifactFilename(jobArg: IBaseOsImageJob, imageKindArg: TBaseOsImageKind) {
|
||||
const architectureSuffix = jobArg.architecture === 'amd64' ? '' : `-${jobArg.architecture}`;
|
||||
if (imageKindArg === 'balena-raw') {
|
||||
return `baseos${architectureSuffix}.img.xz`;
|
||||
}
|
||||
return `baseos${architectureSuffix}.iso`;
|
||||
}
|
||||
|
||||
private getContentType(filenameArg: string, imageKindArg: TBaseOsImageKind) {
|
||||
if (imageKindArg === 'ubuntu-iso') {
|
||||
return 'application/x-iso9660-image';
|
||||
}
|
||||
return filenameArg.endsWith('.xz') ? 'application/x-xz' : 'application/octet-stream';
|
||||
}
|
||||
|
||||
private createBaseOsEnvFile(jobArg: IBaseOsImageJob) {
|
||||
return [
|
||||
`BASEOS_CLOUDLY_URL=${this.escapeEnvValue(jobArg.cloudlyUrl)}`,
|
||||
|
||||
@@ -104,7 +104,8 @@ export class CoreBuildServer {
|
||||
return {
|
||||
workerId: this.options.workerId,
|
||||
supportedBuildTypes: ['baseos-image'],
|
||||
supportedArchitectures: ['amd64', 'arm64'],
|
||||
supportedArchitectures: ['amd64', 'arm64', 'rpi'],
|
||||
supportedImageKinds: ['ubuntu-iso', 'balena-raw'],
|
||||
cpuCores: os.cpus().length,
|
||||
memoryGb: Math.round(os.totalmem() / 1024 / 1024 / 1024),
|
||||
workdir: this.options.workdir,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { Readable } from 'node:stream';
|
||||
|
||||
export type TBaseOsImageArchitecture = 'amd64' | 'arm64' | 'rpi';
|
||||
export type TBaseOsImageKind = 'ubuntu-iso' | 'balena-raw';
|
||||
|
||||
export interface IS3Descriptor {
|
||||
endpoint: string;
|
||||
@@ -15,6 +16,7 @@ export interface IS3Descriptor {
|
||||
export interface IBaseOsImageJob {
|
||||
id: string;
|
||||
architecture: TBaseOsImageArchitecture;
|
||||
imageKind?: TBaseOsImageKind;
|
||||
cloudlyUrl: string;
|
||||
provisioningToken: string;
|
||||
sourceImageUrl?: string;
|
||||
@@ -55,6 +57,7 @@ export interface ICoreBuildCapabilities {
|
||||
workerId: string;
|
||||
supportedBuildTypes: string[];
|
||||
supportedArchitectures: TBaseOsImageArchitecture[];
|
||||
supportedImageKinds: TBaseOsImageKind[];
|
||||
cpuCores: number;
|
||||
memoryGb?: number;
|
||||
workdir: string;
|
||||
|
||||
Reference in New Issue
Block a user