feat(core): Initial project scaffold and implementation: Deno CLI, ISO tooling, cloud-init generation, packaging and installer scripts
This commit is contained in:
168
ts/classes/cloud-init-generator.ts
Normal file
168
ts/classes/cloud-init-generator.ts
Normal 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');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user