UNPKG

@controlplane/cli

Version:

Control Plane Corporation CLI

208 lines 8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AgentCmd = void 0; const os = require("os"); const path = require("path"); const options_1 = require("./options"); const generic_1 = require("./generic"); const resolver_1 = require("./resolver"); const version_1 = require("../util/version"); const command_1 = require("../cli/command"); const agentDefaults_1 = require("./agentDefaults"); const agentManifest_1 = require("./agentManifest"); const logger_1 = require("../util/logger"); const functions_1 = require("../util/functions"); const io_1 = require("../util/io"); const child_process_1 = require("child_process"); class AgentCmd extends command_1.Command { constructor() { super(...arguments); this.command = 'agent'; this.describe = 'Manage agents'; } builder(yargs) { const resolver = (0, resolver_1.kindResolver)('agent'); const opts = [options_1.withOrgOptions, options_1.withStandardOptions]; const commandName = 'agent'; const commandNamePlural = 'agents'; const commandNameA = 'an agent'; return (yargs .demandCommand() .version(false) .help() // generic .command(new generic_1.Get(commandNamePlural, resolver, ...opts).toYargs()) .command(new generic_1.Edit(commandName, resolver, ...opts).toYargs()) .command(new generic_1.Query(commandNamePlural, resolver, undefined, ...opts).toYargs()) .command(new generic_1.Delete(commandNamePlural, resolver, ...opts).toYargs()) .command(new generic_1.Eventlog(commandName, resolver, ...opts).toYargs()) .command(new generic_1.Tag(commandNamePlural, resolver, ...opts).toYargs()) .command(new generic_1.Patch(commandName, resolver, ...opts).toYargs()) .command(new generic_1.ListPermissions(commandNameA, resolver, ...opts).toYargs()) .command(new generic_1.ViewAccessReport(commandName, resolver, ...opts).toYargs()) .command(new generic_1.Update(commandName, resolver, [ { path: 'description', }, { path: 'tags.<key>', }, ], ...opts).toYargs()) // specific .command(new Create(resolver).toYargs()) .command(new Up().toYargs()) .command(new agentManifest_1.Manifest().toYargs()) .command(new Info(resolver).toYargs())); } handle() { } } exports.AgentCmd = AgentCmd; class Create extends command_1.Command { constructor(resolve) { super(); this.resolve = resolve; this.command = 'create'; this.describe = 'Create a new agent'; } withCreateOptions(yargs) { return yargs.options({ name: { describe: 'Name of the agent', requiresArg: true, demandOption: true, }, description: { alias: 'desc', requiresArg: true, describe: 'Optional description, defaults to the name if not set', }, }); } builder(yargs) { return (0, functions_1.pipe)( // this.withCreateOptions, generic_1.withTagOptions, options_1.withOrgOptions, options_1.withStandardOptions)(yargs); } async handle(args) { const body = { name: args.name, description: args.description, tags: (0, generic_1.fromTagOptions)(args), }; const agentsHome = this.resolve.homeLink(this.session.context); // must not use create() as it follows the `location` link const data = await this.client.post(agentsHome, body); this.session.outFormat(data.status.bootstrapConfig); } } class Up extends command_1.Command { constructor() { super(); this.command = 'up'; this.describe = 'Run an agent within a local Docker instance'; } withUpOptions(yargs) { return yargs.options({ 'bootstrap-file': { describe: 'Path to the bootstrap config file', requiresArg: true, demandOption: true, }, background: { alias: 'b', boolean: true, describe: 'If set, run the agent as a background process', }, image: { requiresArg: true, describe: 'Advanced use: Use a different agent Docker image', }, net: { requiresArg: true, describe: 'Docker network to use', default: 'bridge', }, }); } builder(yargs) { return (0, functions_1.pipe)(this.withUpOptions)(yargs); } async createVol(agentId) { const volName = `agent-${agentId}`; try { await (0, child_process_1.spawn)('docker', ['volume', 'create', volName]); } catch (e) { // ignore error, volume already exists } return volName; } async handle(args) { const bootstrapFile = path.resolve(args.bootstrapFile); const bootstrapConfig = JSON.parse(await (0, io_1.readTextFile)(bootstrapFile)); const info = { cloudProvider: 'docker', image: args.image || agentDefaults_1.DEFAULT_IMAGE, cliVersion: version_1.About.build, session: this.session.id, username: os.userInfo().username, hostname: os.hostname(), }; const volName = await this.createVol(bootstrapConfig.agentId); const dockerArgs = ['run']; dockerArgs.push('--init'); dockerArgs.push('--cap-add'); dockerArgs.push('CAP_NET_ADMIN'); dockerArgs.push('--name'); dockerArgs.push(`agent-${bootstrapConfig.agentId}`); dockerArgs.push('--hostname'); dockerArgs.push(`agent-${bootstrapConfig.agentId}`); dockerArgs.push('--net'); dockerArgs.push(args.net); dockerArgs.push('--mount'); dockerArgs.push(`source=${volName},target=/etc/controlplane-keys`); dockerArgs.push('--volume'); dockerArgs.push(`${bootstrapFile}:/etc/controlplane/bootstrap.json:ro`); dockerArgs.push('--env'); dockerArgs.push(`BOOTSTRAP_PATH=/etc/controlplane/bootstrap.json`); dockerArgs.push('--env'); dockerArgs.push(`WG_PRIVATE_KEY_PATH=/etc/controlplane-keys/agent.private`); dockerArgs.push('--env'); dockerArgs.push(`WG_PUBLIC_KEY_PATH=/etc/controlplane-keys/agent.public`); dockerArgs.push('--env'); dockerArgs.push(`ENV_INFO=${JSON.stringify(info)}`); dockerArgs.push('--entrypoint'); dockerArgs.push(`/docker-entrypoint.sh`); if (args.background) { dockerArgs.push('-td'); } else { dockerArgs.push('--env'); dockerArgs.push(`PRETTY_LOGS=1`); dockerArgs.push('-ti'); dockerArgs.push('--rm'); } dockerArgs.push(args.image || agentDefaults_1.DEFAULT_IMAGE); logger_1.logger.debug('Invoking docker as ' + dockerArgs); await (0, child_process_1.spawn)('docker', dockerArgs, { stdio: 'inherit', }); } } class Info extends command_1.Command { constructor(resolve) { super(); this.resolve = resolve; this.command = 'info <ref>'; this.describe = 'Get info about an agent'; } builder(yargs) { return (0, functions_1.pipe)(generic_1.withSingleRef, options_1.withOrgOptions, options_1.withStandardOptions)(yargs); } async handle(args) { const link = this.resolve.resourceLink(args.ref, this.session.context); const body = await this.client.get(link + '/-info'); this.session.outFormat(body); } } //# sourceMappingURL=agent.js.map