UNPKG

@liara/cli

Version:

The command line interface for Liara

185 lines (184 loc) 6.91 kB
import ora from 'ora'; import inquirer from 'inquirer'; import { Flags } from '@oclif/core'; import Command from '../../base.js'; import { IAAS_API_URL } from '../../constants.js'; import { checkVMNameRegexPattern, } from '../../utils/name-regex.js'; import { createDebugLogger } from '../../utils/output.js'; class VmCreate extends Command { constructor() { super(...arguments); this.SSHConfirmationCount = 0; } async setGotConfig(config) { await super.setGotConfig(config); this.got = this.got.extend({ prefixUrl: IAAS_API_URL, }); } async run() { const { flags } = await this.parse(VmCreate); const debug = createDebugLogger(flags.debug); this.spinner = ora(); await this.setGotConfig(flags); try { const oss = await this.getOperatingSystems(); const vmName = await this.promptVMName(); const osName = await this.promptOperatingSystems(oss); const osVersion = await this.promptOperatingSystemVersions(osName, oss); const plan = await this.promptPlan(); const SSHKeys = await this.promptSSHKey(); const newSSH = SSHKeys.length > 0 ? { config: { SSHKeys: SSHKeys, }, } : null; const newVM = { OS: `${osName}-${osVersion}`, name: vmName, plan, ...newSSH, }; await this.got.post('vm', { json: newVM, }); if (flags.detach) { this.spinner.succeed(`vm "${vmName}" creation request submitted successfully in detach mode. Use "liara vm info" to view connection details.`); return; } this.spinner.start(`creating vm "${vmName}"...`); const intervalID = setInterval(async () => { const vmState = await this.getVmState(vmName); if (vmState === 'CREATED') { this.spinner.succeed(`vm "${vmName}" is created successfully. Use "liara vm info" to view connection details.`); clearInterval(intervalID); } }, 2000); } catch (error) { debug(error.message); if (error.response && error.response.data) { debug(JSON.stringify(error.response.data)); } if (error.response && error.response.statusCode === 409) { this.error(`A vm with this name already exists. Please choose a unique name.`); } throw error; } } async getOperatingSystems() { this.spinner.start('Loading...'); try { const oss = await this.got('oss').json(); this.spinner.stop(); return oss; } catch (error) { this.spinner.stop(); throw error; } } async promptOperatingSystems(oss) { const { os } = (await inquirer.prompt({ name: 'os', type: 'list', message: 'Select an OS:', choices: [...Object.keys(oss).map((platform) => platform)], })); return os; } async promptOperatingSystemVersions(osName, oss) { const { osVersion } = (await inquirer.prompt({ name: 'osVersion', type: 'list', message: `Select the ${osName[0].toUpperCase() + osName.slice(1)} version:`, choices: [...oss[osName].map((version) => version)], })); return osVersion; } async promptVMName() { const { vmName } = (await inquirer.prompt({ message: 'Enter vm name: ', type: 'input', name: 'vmName', validate: (input) => input.length > 3 && input.length < 20, })); if (!checkVMNameRegexPattern(vmName)) { this.error('Invalid vm name. It must start with a lowercase letter, contain only lowercase letters, numbers, or hyphens, and be between 4 and 19 characters long.'); } return vmName; } async promptPlan() { this.spinner.start('Loading...'); try { const { plans } = await this.got('plans').json(); this.spinner.stop(); const { plan } = (await inquirer.prompt({ name: 'plan', type: 'list', message: 'Please select a plan:', choices: Object.keys(plans).map((planKey) => { const planDetails = plans[planKey]; const { RAM, CPU, volume, monthlyPrice } = planDetails; const ram = `RAM: ${RAM.amount}${' '.repeat(4 - RAM.amount.toString().length)} GB`; const cpu = `CPU: ${CPU.amount}${' '.repeat(4 - CPU.amount.toString().length)} Core${CPU.amount > 1 ? 's' : ' '}`; const disk = `Disk: ${volume}${' '.repeat(4 - volume.toString().length)} GB`; const price = `Price: ${monthlyPrice.toLocaleString()}${' '.repeat(10 - monthlyPrice.toLocaleString().length)} Tomans/Month`; return { value: planKey, name: `${ram.padEnd(8)} | ${cpu.padEnd(10)} | ${disk.padEnd(8)} | ${price}`, }; }), })); return plan; } catch (error) { this.spinner.stop(); throw error; } } async promptSSHKey() { const SSHKeys = []; while (await this.SSHKeyConfirmation()) { const { SSHKey } = (await inquirer.prompt({ message: 'Enter SSH Key: ', name: 'SSHKey', type: 'input', validate: (input) => input.length !== 0, })); SSHKeys.push(SSHKey); } return SSHKeys; } async SSHKeyConfirmation() { const { shouldContinue } = (await inquirer.prompt({ message: `${this.SSHConfirmationCount == 0 ? 'Add SSH Key?' : 'Add another SSH Key?'} (Default: No)`, type: 'confirm', default: false, name: 'shouldContinue', })); if (shouldContinue) this.SSHConfirmationCount++; return shouldContinue; } async getVmState(vmName) { const { vms } = await this.got('vm').json(); const vm = vms.filter((vm) => vm.name === vmName)[0]; return vm.state; } } VmCreate.flags = { ...Command.flags, vm: Flags.string({ char: 'v', description: 'vm name', }), detach: Flags.boolean({ char: 'd', description: 'run command in detach mode', }), }; VmCreate.description = 'create a vm'; export default VmCreate;