@devmn/cloud-cli
Version:
CLI tool for Intelligo Cloud.
251 lines (239 loc) • 9.37 kB
text/typescript
import { isAbsolute, join } from 'path'
import { writeFileSync } from 'fs'
import Constants from '../utils/Constants'
import Utils from '../utils/Utils'
import StdOutUtil from '../utils/StdOutUtil'
import CliHelper from '../utils/CliHelper'
import CliApiManager from '../api/CliApiManager'
import {
getErrorForDomain,
getErrorForPassword,
getErrorForMachineName,
userCancelOperation
} from '../utils/ValidationsHandler'
import { IMachine } from '../models/storage/StoredObjects'
import Command, {
IParams,
IOption,
ParamType,
ICommandLineOptions,
IParam
} from './Command'
const K = Utils.extendCommonKeys({
path: 'path',
method: 'method',
data: 'data',
out: 'output'
})
export default class Api extends Command {
protected command = 'api'
protected usage =
'[options]\n' +
' api -c file\n' +
' api [-c file] [-n name] [-t path] [-m method] [-d dataJsonString]\n' +
' api [-c file] -u url [-p password] [-n name] [-t path] [-m method] [-d dataJsonString]\n' +
' Use --caproverName to use an already logged in CapRover machine\n' +
' Use --caproverUrl and --caproverPassword to login on the fly to a CapRover machine, if also --caproverName is present, login credetials are stored locally'
protected description =
'Call a generic API on a specific CapRover machine. Use carefully only if you really know what you are doing!'
private machines = CliHelper.get().getMachinesAsOptions()
private machine: IMachine
protected options = (params?: IParams): IOption[] => [
this.getDefaultConfigFileOption(),
{
name: K.url,
char: 'u',
env: 'CAPROVER_URL',
type: 'input',
message: `CapRover machine URL address, it is "[http[s]://][${Constants.ADMIN_DOMAIN}.]your-root.domain"`,
when: false,
filter: (url: string) => Utils.cleanAdminDomainUrl(url) || url, // If not cleaned url, leave url to fail validation with correct error
validate: (url: string) => getErrorForDomain(url, true)
},
{
name: K.pwd,
char: 'p',
env: 'CAPROVER_PASSWORD',
type: 'password',
message: 'CapRover machine password',
when: !!this.findParamValue(params, K.url),
validate: (password: string) => getErrorForPassword(password)
},
{
name: K.name,
char: 'n',
env: 'CAPROVER_NAME',
message: params
? 'select the CapRover machine name you want to call API to'
: 'CapRover machine name, to load/store credentials',
type: 'list',
choices: this.machines,
when: !this.findParamValue(params, K.url),
filter: (name: string) =>
!this.findParamValue(params, K.name)
? userCancelOperation(!name, true) || name
: name.trim(),
validate: !this.findParamValue(params, K.url)
? (name: string) => getErrorForMachineName(name, true)
: undefined
},
CliHelper.get().getEnsureAuthenticationOption(
'',
() => this.paramValue(params, K.url),
() => this.paramValue(params, K.pwd),
() => this.paramValue(params, K.name),
async (machine: IMachine) => {
this.machine = machine
try {
await CliApiManager.get(machine).getCaptainInfo()
} catch (e) {
StdOutUtil.printError(
`\nSomething bad happened during calling API to ${StdOutUtil.getColoredMachineUrl(
machine.baseUrl
)}.\n${e.message || e}`,
true
)
}
}
),
{
name: K.path,
char: 't',
env: 'CAPROVER_API_PATH',
message:
'API path to call, starting with / (eg. "/user/system/info")',
type: 'input',
default: params && '/user/system/info',
filter: (path: string) => path.trim(),
validate: (path: string) =>
path && path.startsWith('/')
? true
: 'Please enter a valid path.'
},
{
name: K.method,
char: 'm',
env: 'CAPROVER_API_METHOD',
message: params
? 'select the API method you want to call'
: `API method to call, one of: ${CliHelper.get().getApiMethodsDescription()}`,
type: 'list',
default: params && 'GET',
choices: CliHelper.get().getApiMethodsAsOptions(),
filter: (method: string) =>
!this.findParamValue(params, K.method)
? userCancelOperation(!method, true) || method
: method.trim(),
validate: (method: string) =>
method && Constants.API_METHODS.includes(method)
? true
: `Please enter a valid method, one of: ${CliHelper.get().getApiMethodsDescription()}`
},
{
name: K.data,
char: 'd',
env: 'CAPROVER_API_DATA',
message:
'API data JSON string' +
(params
? ''
: ' (or also JSON object from config file), for "GET" method they are interpreted as querystring values to be appended to the path'),
type: 'input',
filter: data => {
if (data && typeof data === 'string') {
try {
return JSON.parse(data)
} catch {
// do nothing
}
}
return data
},
validate: data => {
if (data && typeof data === 'string') {
try {
JSON.parse(data)
} catch (e) {
return e as string
}
}
return true
}
},
{
name: K.out,
char: 'o',
env: 'CAPROVER_API_OUTPUT',
message:
'where to log API response output: if "true" log to console, if "false" suppress output, otherwise log to specified file (overwrite already existing)',
type: 'input',
default: 'true',
filter: (out: string) => {
if (!out) {
return 'false'
}
out = out.trim() || 'false'
if (out === 'true' || out === 'false' || isAbsolute(out)) {
return out
}
return join(process.cwd(), out)
}
},
{
name: 'confirmedToCall',
type: 'confirm',
message: 'are you sure you want to procede?',
default: true,
hide: true,
when: () =>
this.paramFrom(params, K.name) === ParamType.Question ||
this.paramFrom(params, K.path) === ParamType.Question ||
this.paramFrom(params, K.data) === ParamType.Question,
preProcessParam: (param: IParam) =>
param && userCancelOperation(!param.value)
}
]
protected async preAction(
cmdLineoptions: ICommandLineOptions
): Promise<ICommandLineOptions> {
StdOutUtil.printMessage(
'Call generic CapRover API [Experimental Feature]...\n'
)
return Promise.resolve(cmdLineoptions)
}
protected async action(params: IParams): Promise<void> {
try {
const resp = await CliApiManager.get(this.machine).callApi(
this.findParamValue(params, K.path)!.value,
this.findParamValue(params, K.method)!.value,
this.paramValue(params, K.data)
)
StdOutUtil.printGreenMessage(`API call completed successfully!\n`)
const out = this.paramValue<string>(params, K.out)!
const data = JSON.stringify(resp, null, 2)
if (out === 'true') {
StdOutUtil.printMessage(data + '\n')
} else if (out !== 'false') {
try {
writeFileSync(out, data)
} catch (e) {
StdOutUtil.printWarning(
`Error writing API response to file: "${out}".\n`
)
}
}
} catch (error) {
StdOutUtil.printError(
`\nSomething bad happened calling API ${StdOutUtil.getColoredMachineUrl(
this.paramValue<string>(params, K.path)!
)} at ${
this.machine.name
? StdOutUtil.getColoredMachineName(this.machine.name)
: StdOutUtil.getColoredMachineUrl(this.machine.baseUrl)
}.`
)
StdOutUtil.errorHandler(error)
}
}
}