@controlplane/cli
Version:
Control Plane Corporation CLI
208 lines • 8 kB
JavaScript
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
;