feat(base-images): add managed base image bundles with cache retention, hosted manifests, and opt-in integration boot testing

This commit is contained in:
2026-05-01 13:30:51 +00:00
parent 0ace928886
commit 9d0a57c5de
19 changed files with 2015 additions and 148 deletions
+23 -3
View File
@@ -1,16 +1,22 @@
import * as plugins from './plugins.js';
import type { ISmartVMOptions, IMicroVMConfig } from './interfaces/index.js';
import type { IBaseImageBundle, IEnsureBaseImageOptions, ISmartVMOptions, IMicroVMConfig } from './interfaces/index.js';
import { SmartVMError } from './interfaces/index.js';
import { ImageManager } from './classes.imagemanager.js';
import { BaseImageManager } from './classes.baseimagemanager.js';
import { NetworkManager } from './classes.networkmanager.js';
import { MicroVM } from './classes.microvm.js';
function getErrorMessage(err: unknown): string {
return err instanceof Error ? err.message : String(err);
}
/**
* Top-level orchestrator for creating and managing Firecracker MicroVMs.
*/
export class SmartVM {
private options: ISmartVMOptions;
public imageManager: ImageManager;
public baseImageManager: BaseImageManager;
public networkManager: NetworkManager;
private activeVMs: Map<string, MicroVM> = new Map();
private smartExitInstance: InstanceType<typeof plugins.smartexit.SmartExit>;
@@ -27,6 +33,13 @@ export class SmartVM {
};
this.imageManager = new ImageManager(this.options.dataDir!, this.options.arch);
this.baseImageManager = new BaseImageManager({
arch: this.options.arch,
cacheDir: this.options.baseImageCacheDir,
maxStoredBaseImages: this.options.maxStoredBaseImages,
hostedManifestUrl: this.options.baseImageManifestUrl,
hostedManifestPath: this.options.baseImageManifestPath,
});
this.networkManager = new NetworkManager({
bridgeName: this.options.bridgeName,
subnet: this.options.subnet,
@@ -115,6 +128,13 @@ export class SmartVM {
return vm;
}
/**
* Ensure a Firecracker CI base image bundle is available locally.
*/
public async ensureBaseImage(options: IEnsureBaseImageOptions = {}): Promise<IBaseImageBundle> {
return this.baseImageManager.ensureBaseImage(options);
}
/**
* Get an active VM by ID.
*/
@@ -145,7 +165,7 @@ export class SmartVM {
if (vm.state === 'running' || vm.state === 'paused') {
stopPromises.push(
vm.stop().catch((err) => {
console.error(`Failed to stop VM ${vm.id}: ${err.message}`);
console.error(`Failed to stop VM ${vm.id}: ${getErrorMessage(err)}`);
}),
);
}
@@ -162,7 +182,7 @@ export class SmartVM {
for (const vm of this.activeVMs.values()) {
cleanupPromises.push(
vm.cleanup().catch((err) => {
console.error(`Failed to clean up VM ${vm.id}: ${err.message}`);
console.error(`Failed to clean up VM ${vm.id}: ${getErrorMessage(err)}`);
}),
);
}