UNPKG

@controlplane/cli

Version:

Control Plane Corporation CLI

327 lines 11.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Manifest = void 0; const path = require("path"); const command_1 = require("../cli/command"); const agentDefaults_1 = require("./agentDefaults"); const functions_1 = require("../util/functions"); const io_1 = require("../util/io"); const js_yaml_1 = require("js-yaml"); class Manifest extends command_1.Command { constructor() { super(); this.command = 'manifest'; this.describe = 'Generate a manifest for running an agent in K8S'; } withUpOptions(yargs) { return yargs.options({ 'bootstrap-file': { describe: 'Path to the bootstrap config file', requiresArg: true, demandOption: true, }, namespace: { alias: 'n', requiresArg: true, demandOption: true, describe: 'Namespace where the agent deployment(s) will live', }, image: { requiresArg: true, describe: 'Advanced use: Use a different agent Docker image', }, cluster: { requiresArg: true, describe: "Add metadata to agent's environment, useful to remind you which cluster an agent is running in", }, replicas: { requiresArg: true, describe: 'Number of agents deployments to create', default: 1, }, 'create-namespace': { type: 'boolean', describe: 'Create the namespace', default: true, }, }); } builder(yargs) { return (0, functions_1.pipe)(this.withUpOptions)(yargs); } async handle(args) { const bootstrapFile = path.resolve(args.bootstrapFile); const bootstrapConfig = JSON.parse(await (0, io_1.readTextFile)(bootstrapFile)); const ctx = { namespace: args.namespace, image: args.image || agentDefaults_1.DEFAULT_IMAGE, serviceAccountName: 'cpln-agent', agentId: bootstrapConfig.agentId, bootstrapSecretName: `bootstrap-${bootstrapConfig.agentId.substring(0, 18)}`, shortName: bootstrapConfig.agentId.substring(0, 18), clusterName: args.cluster || 'unknown', keysSecretName(i) { return `keys-${ctx.shortName}-${i}`; }, labels: { app() { return { app: 'cpln-agent', }; }, agent() { return { ...this.app(), 'cpln/agent-id': ctx.agentId, }; }, replica(i) { return { ...this.agent(), 'cpln/replica': '' + i, }; }, }, }; const objects = []; if (args.createNamespace) { objects.push(namespace(ctx)); } [ // sa(ctx), role(ctx), roleBinding(ctx), bootstrapSecret(ctx, bootstrapConfig), ].forEach((x) => objects.push(x)); for (let i = 0; i < args.replicas; i++) { objects.push(deployment(ctx, i)); } objects.forEach((obj) => { this.session.out('---'); this.session.out((0, js_yaml_1.safeDump)(obj, {})); }); } } exports.Manifest = Manifest; function namespace(ctx) { return { apiVersion: 'v1', kind: 'Namespace', metadata: { name: ctx.namespace, labels: ctx.labels.app(), }, }; } function sa(ctx) { return { apiVersion: 'v1', kind: 'ServiceAccount', metadata: { name: ctx.serviceAccountName, namespace: ctx.namespace, labels: ctx.labels.app(), }, }; } function role(ctx) { return { apiVersion: 'rbac.authorization.k8s.io/v1', kind: 'Role', metadata: { name: ctx.serviceAccountName, namespace: ctx.namespace, labels: ctx.labels.app(), }, rules: [ { apiGroups: [''], resources: ['secrets'], verbs: ['*'], }, ], }; } function roleBinding(ctx) { return { apiVersion: 'rbac.authorization.k8s.io/v1', kind: 'RoleBinding', metadata: { name: ctx.serviceAccountName, namespace: ctx.namespace, labels: ctx.labels.app(), }, roleRef: { apiGroup: 'rbac.authorization.k8s.io', kind: 'Role', name: ctx.serviceAccountName, }, subjects: [ { kind: 'ServiceAccount', name: ctx.serviceAccountName, namespace: ctx.namespace, }, ], }; } function bootstrapSecret(ctx, bootstrapConfig) { return { apiVersion: 'v1', kind: 'Secret', metadata: { name: ctx.bootstrapSecretName, namespace: ctx.namespace, labels: ctx.labels.agent(), }, data: { 'bootstrap.json': Buffer.from(JSON.stringify(bootstrapConfig)).toString('base64'), }, }; } function deployment(ctx, index) { return { apiVersion: 'apps/v1', kind: 'Deployment', metadata: { name: `agent-${ctx.shortName}-${index}`, namespace: ctx.namespace, labels: ctx.labels.replica(index), }, spec: { replicas: 1, selector: { matchLabels: ctx.labels.replica(index), }, template: { metadata: { labels: ctx.labels.replica(index), annotations: { 'sidecar.istio.io/inject': 'false', }, }, spec: { affinity: { nodeAffinity: { requiredDuringSchedulingIgnoredDuringExecution: { nodeSelectorTerms: [ { matchExpressions: [ { key: 'beta.kubernetes.io/arch', operator: 'In', values: ['amd64'], }, ], }, ], }, }, podAntiAffinity: { requiredDuringSchedulingIgnoredDuringExecution: [ { labelSelector: { matchExpressions: [ { key: 'app', operator: 'In', values: ['cpln-agent'], }, { key: 'cpln/agent-id', operator: 'In', values: [ctx.agentId], }, ], }, topologyKey: 'kubernetes.io/hostname', }, ], }, }, serviceAccountName: ctx.serviceAccountName, volumes: [ { name: 'keys', secret: { secretName: ctx.keysSecretName(index), optional: true, }, }, { name: 'bootstrap', secret: { secretName: ctx.bootstrapSecretName, }, }, ], containers: [ { name: 'agent', image: ctx.image, securityContext: { privileged: true, capabilities: { drop: ['ALL'], add: [ 'NET_ADMIN', 'NET_RAW', 'MKNOD', 'SYS_ADMIN', ], }, }, ports: [ { containerPort: 4015, name: 'monitoring', }, ], command: ['/k8s-entrypoint.sh'], env: [ { name: 'NAMESPACE', valueFrom: { fieldRef: { fieldPath: 'metadata.namespace', }, }, }, { name: 'SECRET_NAME', value: ctx.keysSecretName(index), }, { name: 'CLUSTER_NAME', value: ctx.clusterName, }, { name: 'MOUNT_POINT', value: '/config/keys', }, { name: 'BOOTSTRAP_PATH', value: '/config/bootstrap/bootstrap.json', }, ], volumeMounts: [ { mountPath: '/config/bootstrap', name: 'bootstrap', readOnly: true, }, { mountPath: '/config/keys', name: 'keys', readOnly: true, }, ], }, ], }, }, }, }; } //# sourceMappingURL=agentManifest.js.map