feat(core): Initial project scaffold and implementation: Deno CLI, ISO tooling, cloud-init generation, packaging and installer scripts

This commit is contained in:
2025-10-24 08:10:02 +00:00
commit ce06b5855a
31 changed files with 2873 additions and 0 deletions

View File

@@ -0,0 +1,168 @@
/**
* Cloud-Init Generator
* Generates cloud-init configuration files
*/
import { yaml, path as pathUtil } from '../plugins.ts';
import { log } from '../logging.ts';
import type { ICloudInitConfig } from '../interfaces/iso-config.interface.ts';
export interface INetworkConfig {
wifi?: {
ssid: string;
password: string;
};
}
export class CloudInitGenerator {
/**
* Generate user-data file content
*/
generateUserData(config: ICloudInitConfig): string {
const userDataObj: Record<string, unknown> = {
'#cloud-config': null,
};
// Hostname
if (config.hostname) {
userDataObj.hostname = config.hostname;
}
// Users
if (config.users && config.users.length > 0) {
userDataObj.users = config.users.map((user) => ({
name: user.name,
...(user.ssh_authorized_keys && { ssh_authorized_keys: user.ssh_authorized_keys }),
...(user.sudo && { sudo: user.sudo }),
...(user.shell && { shell: user.shell }),
...(user.groups && { groups: user.groups }),
...(user.lock_passwd !== undefined && { lock_passwd: user.lock_passwd }),
...(user.passwd && { passwd: user.passwd }),
}));
}
// Packages
if (config.packages && config.packages.length > 0) {
userDataObj.packages = config.packages;
}
// Package update/upgrade
if (config.package_update !== undefined) {
userDataObj.package_update = config.package_update;
}
if (config.package_upgrade !== undefined) {
userDataObj.package_upgrade = config.package_upgrade;
}
// Run commands
if (config.runcmd && config.runcmd.length > 0) {
userDataObj.runcmd = config.runcmd;
}
// Write files
if (config.write_files && config.write_files.length > 0) {
userDataObj.write_files = config.write_files;
}
// Timezone
if (config.timezone) {
userDataObj.timezone = config.timezone;
}
// Locale
if (config.locale) {
userDataObj.locale = config.locale;
}
// SSH settings
if (config.ssh) {
userDataObj.ssh = config.ssh;
}
// Add any additional custom directives
for (const [key, value] of Object.entries(config)) {
if (!['hostname', 'users', 'packages', 'package_update', 'package_upgrade',
'runcmd', 'write_files', 'timezone', 'locale', 'ssh'].includes(key)) {
userDataObj[key] = value;
}
}
// Remove the cloud-config comment from the object before YAML conversion
delete userDataObj['#cloud-config'];
// Convert to YAML and add the cloud-config header
const yamlContent = yaml.stringify(userDataObj);
return `#cloud-config\n${yamlContent}`;
}
/**
* Generate network-config file content (for WiFi)
*/
generateNetworkConfig(networkConfig: INetworkConfig): string {
if (!networkConfig.wifi) {
return yaml.stringify({ version: 2 });
}
const { ssid, password } = networkConfig.wifi;
const netConfig = {
version: 2,
wifis: {
wlan0: {
dhcp4: true,
optional: true,
'access-points': {
[ssid]: {
password: password,
},
},
},
},
};
return yaml.stringify(netConfig);
}
/**
* Generate meta-data file content
*/
generateMetaData(hostname?: string): string {
const metaData = {
'instance-id': `iid-${Date.now()}`,
'local-hostname': hostname || 'ubuntu',
};
return yaml.stringify(metaData);
}
/**
* Write cloud-init files to a directory
*/
async writeCloudInitFiles(
outputDir: string,
cloudInitConfig: ICloudInitConfig,
networkConfig?: INetworkConfig,
): Promise<void> {
log.info('Generating cloud-init configuration files...');
// Generate user-data
const userData = this.generateUserData(cloudInitConfig);
const userDataPath = pathUtil.join(outputDir, 'user-data');
await Deno.writeTextFile(userDataPath, userData);
log.success('Generated user-data');
// Generate network-config
if (networkConfig) {
const netConfig = this.generateNetworkConfig(networkConfig);
const netConfigPath = pathUtil.join(outputDir, 'network-config');
await Deno.writeTextFile(netConfigPath, netConfig);
log.success('Generated network-config');
}
// Generate meta-data
const metaData = this.generateMetaData(cloudInitConfig.hostname);
const metaDataPath = pathUtil.join(outputDir, 'meta-data');
await Deno.writeTextFile(metaDataPath, metaData);
log.success('Generated meta-data');
}
}