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