import * as plugins from '../plugins.js'; import { Cloudly } from '../classes.cloudly.js'; import { BareMetal } from './classes.baremetal.js'; import { logger } from '../logger.js'; export class CloudlyBaremetalManager { public cloudlyRef: Cloudly; public typedRouter = new plugins.typedrequest.TypedRouter(); public hetznerAccount: plugins.hetznercloud.HetznerAccount; public get db() { return this.cloudlyRef.mongodbConnector.smartdataDb; } public CBareMetal = plugins.smartdata.setDefaultManagerForDoc(this, BareMetal); constructor(cloudlyRefArg: Cloudly) { this.cloudlyRef = cloudlyRefArg; this.cloudlyRef.typedrouter.addTypedRouter(this.typedRouter); // API endpoint to get baremetal servers this.typedRouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'getBaremetalServers', async (requestData) => { const baremetals = await this.getAllBaremetals(); return { baremetals: await Promise.all( baremetals.map((baremetal) => baremetal.createSavableObject()) ), }; }, ), ); // API endpoint to control baremetal via IPMI this.typedRouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'controlBaremetal', async (requestData) => { const baremetal = await this.CBareMetal.getInstance({ id: requestData.baremetalId, }); if (!baremetal) { return { success: false, message: 'BareMetal not found', }; } let success = false; switch (requestData.action) { case 'powerOn': success = await baremetal.powerOn(); break; case 'powerOff': success = await baremetal.powerOff(); break; case 'reset': success = await baremetal.reset(); break; } return { success, message: success ? `Action ${requestData.action} completed` : `Action ${requestData.action} failed`, }; }, ), ); } public async start() { const hetznerToken = await this.cloudlyRef.settingsManager.getSetting('hetznerToken'); if (hetznerToken) { this.hetznerAccount = new plugins.hetznercloud.HetznerAccount(hetznerToken); } logger.log('info', 'BareMetal manager started'); } public async stop() { logger.log('info', 'BareMetal manager stopped'); } /** * Get all baremetal servers */ public async getAllBaremetals(): Promise { const baremetals = await this.CBareMetal.getInstances({}); return baremetals; } /** * Get baremetal by ID */ public async getBaremetalById(id: string): Promise { const baremetal = await this.CBareMetal.getInstance({ id, }); return baremetal; } /** * Get baremetals by provider */ public async getBaremetalsByProvider(provider: 'hetzner' | 'aws' | 'digitalocean' | 'onpremise'): Promise { const baremetals = await this.CBareMetal.getInstances({ data: { provider, }, }); return baremetals; } /** * Create baremetal from Hetzner server */ public async createBaremetalFromHetznerServer(hetznerServer: plugins.hetznercloud.HetznerServer): Promise { // Check if baremetal already exists for this Hetzner server const existingBaremetals = await this.CBareMetal.getInstances({}); for (const baremetal of existingBaremetals) { if (baremetal.data.providerMetadata?.hetznerServerId === hetznerServer.data.id) { logger.log('info', `BareMetal already exists for Hetzner server ${hetznerServer.data.id}`); return baremetal; } } // Create new baremetal const newBaremetal = await BareMetal.createFromHetznerServer(hetznerServer); logger.log('success', `Created new BareMetal ${newBaremetal.id} from Hetzner server ${hetznerServer.data.id}`); return newBaremetal; } /** * Sync baremetals with Hetzner */ public async syncWithHetzner() { if (!this.hetznerAccount) { logger.log('warn', 'Cannot sync with Hetzner - no account configured'); return; } const hetznerServers = await this.hetznerAccount.getServers(); for (const hetznerServer of hetznerServers) { await this.createBaremetalFromHetznerServer(hetznerServer); } logger.log('success', `Synced ${hetznerServers.length} servers from Hetzner`); } /** * Provision a new baremetal server */ public async provisionBaremetal(options: { provider: 'hetzner' | 'aws' | 'digitalocean'; location: any; // TODO: Import proper type from hetznercloud when available type: any; // TODO: Import proper type from hetznercloud when available }): Promise { if (options.provider === 'hetzner' && this.hetznerAccount) { const hetznerServer = await this.hetznerAccount.createServer({ name: plugins.smartunique.uniSimple('baremetal'), location: options.location, type: options.type, }); const baremetal = await this.createBaremetalFromHetznerServer(hetznerServer); return baremetal; } throw new Error(`Provider ${options.provider} not supported or not configured`); } }