pepr 0.1.21 → 0.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  <img align="right" width="40%" src=".images/pepr.png" />
4
4
 
5
+ Pepr is on a mission to save Kubernetes from the tyranny of YAML, intimidating glue code, bash scripts, and other makeshift solutions. As a Kubernetes controller, Pepr empowers you to define Kubernetes transformations using TypeScript, without software development expertise thanks to plain-english configurations. Pepr transforms a patchwork of forks, scripts, overlays, and other chaos into a cohesive, well-structured, and maintainable system. With Pepr, you can seamlessly transition IT ops tribal knowledge into code, simplifying documentation, testing, validation, and coordination of changes for a more predictable outcome.
6
+
7
+ ## Features
8
+
9
+ - Define a set of Kubernetes transformations/actions as Pepr capabilities.
10
+ - Write capabilities in TypeScript and bundle them for in-cluster processing in [NodeJS](https://nodejs.org/).
11
+ - React to cluster resources by mutating them, creating new Kubernetes resources, or performing arbitrary exec/API operations.
12
+
5
13
  Pepr is an open-source project that helps IT Ops teams of all skill levels manage and modify resources in a Kubernetes (K8s) cluster using TypeScript. Kubernetes simplifies the management of multiple computers working together to run and scale applications. Pepr acts as a smart assistant, automatically changing or validating parts of the system as needed.
6
14
 
7
15
  TypeScript is used to create Pepr capabilities, benefiting from its error-catching and clean code features, but without requiring specialized software engineering experience or prior Typescript knowledge. Pepr also provides a user-friendly interface for writing commands in plain English in a [Fluent Interface](https://en.wikipedia.org/wiki/Fluent_interface) style.
@@ -10,12 +18,6 @@ Capabilities are logical groupings of actions, which are the atomic units of cha
10
18
 
11
19
  Imagine Pepr as a smart home system where different devices communicate with each other. Pepr provides instructions, simplifying the management of the smart home. The project enables both expert and novice capability authors to improve management and interactions within the Kubernetes environment, making its features accessible to everyone.
12
20
 
13
- ## Features
14
-
15
- - Define a set of Kubernetes transformations/actions as Pepr capabilities.
16
- - Write capabilities in TypeScript and bundle them for in-cluster processing in [NodeJS](https://nodejs.org/).
17
- - React to cluster resources by mutating them, creating new Kubernetes resources, or performing arbitrary exec/API operations.
18
-
19
21
  ## Concepts
20
22
 
21
23
  ### Module
package/dist/pepr-cli.js CHANGED
@@ -7,10 +7,7 @@ var typescript = require('@rollup/plugin-typescript');
7
7
  var fs = require('fs');
8
8
  var path = require('path');
9
9
  var rollup = require('rollup');
10
- var types = require('./types-672dd6e4.js');
11
- require('@kubernetes/client-node/dist');
12
- require('ramda');
13
- require('fast-json-patch');
10
+ var types = require('./types-1709b44f.js');
14
11
  var clientNode = require('@kubernetes/client-node');
15
12
  var zlib = require('zlib');
16
13
  var forge = require('node-forge');
@@ -21,7 +18,7 @@ var uuid = require('uuid');
21
18
  var commander = require('commander');
22
19
  var chokidar = require('chokidar');
23
20
 
24
- var version = "0.1.21";
21
+ var version = "0.1.24";
25
22
 
26
23
  // SPDX-License-Identifier: Apache-2.0
27
24
  // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
@@ -118,15 +115,21 @@ function genTLS(name) {
118
115
  ]);
119
116
  // Generate a new server key pair and create a server certificate signed by the CA
120
117
  const serverKeys = forge.pki.rsa.generateKeyPair(2048);
121
- const serverCert = genCert(serverKeys, `${name}.pepr-system.svc`, caCert.subject.attributes);
118
+ const serverCert = genCert(serverKeys, name, caCert.subject.attributes);
122
119
  // Sign both certificates with the CA private key
123
120
  caCert.sign(caKeys.privateKey, forge.md.sha256.create());
124
121
  serverCert.sign(caKeys.privateKey, forge.md.sha256.create());
125
- // Convert the keys and certificates to PEM format and Base64-encode them
126
- const ca = Buffer.from(forge.pki.certificateToPem(caCert)).toString("base64");
127
- const key = Buffer.from(forge.pki.privateKeyToPem(serverKeys.privateKey)).toString("base64");
128
- const crt = Buffer.from(forge.pki.certificateToPem(serverCert)).toString("base64");
129
- return { ca, key, crt };
122
+ // Convert the keys and certificates to PEM format
123
+ const pem = {
124
+ ca: forge.pki.certificateToPem(caCert),
125
+ crt: forge.pki.certificateToPem(serverCert),
126
+ key: forge.pki.privateKeyToPem(serverKeys.privateKey),
127
+ };
128
+ // Base64-encode the PEM strings
129
+ const ca = Buffer.from(pem.ca).toString("base64");
130
+ const key = Buffer.from(pem.key).toString("base64");
131
+ const crt = Buffer.from(pem.crt).toString("base64");
132
+ return { ca, key, crt, pem };
130
133
  }
131
134
  function genCert(key, name, issuer) {
132
135
  const crt = forge.pki.createCertificate();
@@ -159,12 +162,16 @@ const peprIgnore = {
159
162
  values: ["ignore"],
160
163
  };
161
164
  class Webhook {
162
- constructor(config) {
165
+ get tls() {
166
+ return this._tls;
167
+ }
168
+ constructor(config, host) {
163
169
  this.config = config;
170
+ this.host = host;
164
171
  this.name = `pepr-${config.uuid}`;
165
172
  this.image = `ghcr.io/defenseunicorns/pepr/controller:${config.version}`;
166
173
  // Generate the ephemeral tls things
167
- this.tls = genTLS(this.name);
174
+ this._tls = genTLS(this.host || `${this.name}.pepr-system.svc`);
168
175
  }
169
176
  /** Generate the pepr-system namespace */
170
177
  namespace() {
@@ -235,8 +242,8 @@ class Webhook {
235
242
  },
236
243
  type: "kubernetes.io/tls",
237
244
  data: {
238
- "tls.crt": this.tls.crt,
239
- "tls.key": this.tls.key,
245
+ "tls.crt": this._tls.crt,
246
+ "tls.key": this._tls.key,
240
247
  },
241
248
  };
242
249
  }
@@ -251,6 +258,21 @@ class Webhook {
251
258
  values: this.config.alwaysIgnore.namespaces,
252
259
  });
253
260
  }
261
+ const clientConfig = {
262
+ caBundle: this._tls.ca,
263
+ };
264
+ // If a host is specified, use that with a port of 3000
265
+ if (this.host) {
266
+ clientConfig.url = `https://${this.host}:3000/mutate`;
267
+ }
268
+ else {
269
+ // Otherwise, use the service
270
+ clientConfig.service = {
271
+ name: this.name,
272
+ namespace: "pepr-system",
273
+ path: "/mutate",
274
+ };
275
+ }
254
276
  return {
255
277
  apiVersion: "admissionregistration.k8s.io/v1",
256
278
  kind: "MutatingWebhookConfiguration",
@@ -259,14 +281,7 @@ class Webhook {
259
281
  {
260
282
  name: `${name}.pepr.dev`,
261
283
  admissionReviewVersions: ["v1", "v1beta1"],
262
- clientConfig: {
263
- caBundle: this.tls.ca,
264
- service: {
265
- name: this.name,
266
- namespace: "pepr-system",
267
- path: "/mutate",
268
- },
269
- },
284
+ clientConfig,
270
285
  failurePolicy: "Ignore",
271
286
  matchPolicy: "Equivalent",
272
287
  timeoutSeconds: 15,
@@ -351,6 +366,11 @@ class Webhook {
351
366
  mountPath: "/etc/certs",
352
367
  readOnly: true,
353
368
  },
369
+ {
370
+ name: "module",
371
+ mountPath: "/app/module.js.gz",
372
+ readOnly: true,
373
+ },
354
374
  ],
355
375
  },
356
376
  ],
@@ -361,12 +381,56 @@ class Webhook {
361
381
  secretName: `${this.name}-tls`,
362
382
  },
363
383
  },
384
+ {
385
+ name: "module",
386
+ secret: {
387
+ secretName: `${this.name}-module`,
388
+ },
389
+ },
364
390
  ],
365
391
  },
366
392
  },
367
393
  },
368
394
  };
369
395
  }
396
+ /** Only permit the */
397
+ networkPolicy() {
398
+ return {
399
+ apiVersion: "networking.k8s.io/v1",
400
+ kind: "NetworkPolicy",
401
+ metadata: {
402
+ name: this.name,
403
+ namespace: "pepr-system",
404
+ },
405
+ spec: {
406
+ podSelector: {
407
+ matchLabels: {
408
+ app: this.name,
409
+ },
410
+ },
411
+ policyTypes: ["Ingress"],
412
+ ingress: [
413
+ {
414
+ from: [
415
+ {
416
+ namespaceSelector: {
417
+ matchLabels: {
418
+ "kubernetes.io/metadata.name": "kube-system",
419
+ },
420
+ },
421
+ },
422
+ ],
423
+ ports: [
424
+ {
425
+ protocol: "TCP",
426
+ port: 443,
427
+ },
428
+ ],
429
+ },
430
+ ],
431
+ },
432
+ };
433
+ }
370
434
  service() {
371
435
  return {
372
436
  apiVersion: "v1",
@@ -433,6 +497,7 @@ class Webhook {
433
497
  allYaml(code) {
434
498
  const resources = [
435
499
  this.namespace(),
500
+ this.networkPolicy(),
436
501
  this.clusterRole(),
437
502
  this.clusterRoleBinding(),
438
503
  this.serviceAccount(),
@@ -446,7 +511,7 @@ class Webhook {
446
511
  return resources.map(r => clientNode.dumpYaml(r, { noRefs: true })).join("---\n");
447
512
  }
448
513
  async deploy(code) {
449
- types.Log.info("Establishing connection to Kubernetes");
514
+ types.logger.info("Establishing connection to Kubernetes");
450
515
  const namespace = "pepr-system";
451
516
  // Deploy the resources using the k8s API
452
517
  const kubeConfig = new clientNode.KubeConfig();
@@ -455,106 +520,121 @@ class Webhook {
455
520
  const rbacApi = kubeConfig.makeApiClient(clientNode.RbacAuthorizationV1Api);
456
521
  const appsApi = kubeConfig.makeApiClient(clientNode.AppsV1Api);
457
522
  const admissionApi = kubeConfig.makeApiClient(clientNode.AdmissionregistrationV1Api);
523
+ const networkApi = kubeConfig.makeApiClient(clientNode.NetworkingV1Api);
458
524
  const ns = this.namespace();
459
525
  try {
460
- types.Log.info("Checking for namespace");
526
+ types.logger.info("Checking for namespace");
461
527
  await coreV1Api.readNamespace(namespace);
462
528
  }
463
529
  catch (e) {
464
- types.Log.debug(e.body);
465
- types.Log.info("Creating namespace");
530
+ types.logger.debug(e.body);
531
+ types.logger.info("Creating namespace");
466
532
  await coreV1Api.createNamespace(ns);
467
533
  }
534
+ const netpol = this.networkPolicy();
535
+ try {
536
+ types.logger.info("Checking for network policy");
537
+ await networkApi.readNamespacedNetworkPolicy(netpol.metadata.name, namespace);
538
+ }
539
+ catch (e) {
540
+ types.logger.debug(e.body);
541
+ types.logger.info("Creating network policy");
542
+ await networkApi.createNamespacedNetworkPolicy(namespace, netpol);
543
+ }
468
544
  const wh = this.mutatingWebhook();
469
545
  try {
470
- types.Log.info("Creating mutating webhook");
546
+ types.logger.info("Creating mutating webhook");
471
547
  await admissionApi.createMutatingWebhookConfiguration(wh);
472
548
  }
473
549
  catch (e) {
474
- types.Log.debug(e.body);
475
- types.Log.info("Removing and re-creating mutating webhook");
550
+ types.logger.debug(e.body);
551
+ types.logger.info("Removing and re-creating mutating webhook");
476
552
  await admissionApi.deleteMutatingWebhookConfiguration(wh.metadata.name);
477
553
  await admissionApi.createMutatingWebhookConfiguration(wh);
478
554
  }
479
555
  const crb = this.clusterRoleBinding();
480
556
  try {
481
- types.Log.info("Creating cluster role binding");
557
+ types.logger.info("Creating cluster role binding");
482
558
  await rbacApi.createClusterRoleBinding(crb);
483
559
  }
484
560
  catch (e) {
485
- types.Log.debug(e.body);
486
- types.Log.info("Removing and re-creating cluster role binding");
561
+ types.logger.debug(e.body);
562
+ types.logger.info("Removing and re-creating cluster role binding");
487
563
  await rbacApi.deleteClusterRoleBinding(crb.metadata.name);
488
564
  await rbacApi.createClusterRoleBinding(crb);
489
565
  }
490
566
  const cr = this.clusterRole();
491
567
  try {
492
- types.Log.info("Creating cluster role");
568
+ types.logger.info("Creating cluster role");
493
569
  await rbacApi.createClusterRole(cr);
494
570
  }
495
571
  catch (e) {
496
- types.Log.debug(e.body);
497
- types.Log.info("Removing and re-creating the cluster role");
572
+ types.logger.debug(e.body);
573
+ types.logger.info("Removing and re-creating the cluster role");
498
574
  try {
499
575
  await rbacApi.deleteClusterRole(cr.metadata.name);
500
576
  await rbacApi.createClusterRole(cr);
501
577
  }
502
578
  catch (e) {
503
- types.Log.debug(e.body);
579
+ types.logger.debug(e.body);
504
580
  }
505
581
  }
506
582
  const sa = this.serviceAccount();
507
583
  try {
508
- types.Log.info("Creating service account");
584
+ types.logger.info("Creating service account");
509
585
  await coreV1Api.createNamespacedServiceAccount(namespace, sa);
510
586
  }
511
587
  catch (e) {
512
- types.Log.debug(e.body);
513
- types.Log.info("Removing and re-creating service account");
588
+ types.logger.debug(e.body);
589
+ types.logger.info("Removing and re-creating service account");
514
590
  await coreV1Api.deleteNamespacedServiceAccount(sa.metadata.name, namespace);
515
591
  await coreV1Api.createNamespacedServiceAccount(namespace, sa);
516
592
  }
593
+ // If a host is specified, we don't need to deploy the rest of the resources
594
+ if (this.host) {
595
+ return;
596
+ }
517
597
  const mod = this.moduleSecret(code);
518
598
  try {
519
- types.Log.info("Creating module secret");
599
+ types.logger.info("Creating module secret");
520
600
  await coreV1Api.createNamespacedSecret(namespace, mod);
521
601
  }
522
602
  catch (e) {
523
- types.Log.debug(e.body);
524
- types.Log.info("Removing and re-creating module secret");
603
+ types.logger.debug(e.body);
604
+ types.logger.info("Removing and re-creating module secret");
525
605
  await coreV1Api.deleteNamespacedSecret(mod.metadata.name, namespace);
526
606
  await coreV1Api.createNamespacedSecret(namespace, mod);
527
607
  }
528
608
  const svc = this.service();
529
609
  try {
530
- types.Log.info("Creating service");
610
+ types.logger.info("Creating service");
531
611
  await coreV1Api.createNamespacedService(namespace, svc);
532
612
  }
533
613
  catch (e) {
534
- types.Log.debug(e.body);
535
- types.Log.info("Removing and re-creating service");
614
+ types.logger.debug(e.body);
615
+ types.logger.info("Removing and re-creating service");
536
616
  await coreV1Api.deleteNamespacedService(svc.metadata.name, namespace);
537
617
  await coreV1Api.createNamespacedService(namespace, svc);
538
618
  }
539
619
  const tls = this.tlsSecret();
540
620
  try {
541
- types.Log.info("Creating TLS secret");
621
+ types.logger.info("Creating TLS secret");
542
622
  await coreV1Api.createNamespacedSecret(namespace, tls);
543
623
  }
544
624
  catch (e) {
545
- types.Log.debug(e.body);
546
- types.Log.info("Removing and re-creating TLS secret");
625
+ types.logger.debug(e.body);
626
+ types.logger.info("Removing and re-creating TLS secret");
547
627
  await coreV1Api.deleteNamespacedSecret(tls.metadata.name, namespace);
548
628
  await coreV1Api.createNamespacedSecret(namespace, tls);
549
629
  }
550
630
  const dep = this.deployment();
551
631
  try {
552
- types.Log.info("Creating deployment");
632
+ types.logger.info("Creating deployment");
553
633
  await appsApi.createNamespacedDeployment(namespace, dep);
554
634
  }
555
635
  catch (e) {
556
- types.Log.debug(e.body);
557
- types.Log.info("Removing and re-creating deployment");
636
+ types.logger.debug(e.body);
637
+ types.logger.info("Removing and re-creating deployment");
558
638
  await appsApi.deleteNamespacedDeployment(dep.metadata.name, namespace);
559
639
  await appsApi.createNamespacedDeployment(namespace, dep);
560
640
  }
@@ -584,8 +664,8 @@ function build (program) {
584
664
  const zarf = webhook.zarfYaml(yamlFile);
585
665
  await fs.promises.writeFile(yamlPath, yaml);
586
666
  await fs.promises.writeFile(zarfPath, zarf);
587
- types.Log.debug(`Module compiled successfully at ${path$1}`);
588
- types.Log.info(`K8s resource for the module saved to ${yamlPath}`);
667
+ types.logger.debug(`Module compiled successfully at ${path$1}`);
668
+ types.logger.info(`K8s resource for the module saved to ${yamlPath}`);
589
669
  });
590
670
  }
591
671
  const externalLibs = [
@@ -644,8 +724,8 @@ async function buildModule(moduleDir) {
644
724
  }
645
725
  catch (e) {
646
726
  // On any other error, exit with a non-zero exit code
647
- types.Log.debug(e);
648
- types.Log.error(e.message);
727
+ types.logger.debug(e);
728
+ types.logger.error(e.message);
649
729
  process.exit(1);
650
730
  }
651
731
  }
@@ -698,10 +778,51 @@ function deploy (program) {
698
778
  }
699
779
  try {
700
780
  await webhook.deploy(code);
701
- types.Log.info(`Module deployed successfully`);
781
+ types.logger.info(`Module deployed successfully`);
702
782
  }
703
783
  catch (e) {
704
- types.Log.error(`Error deploying module: ${e}`);
784
+ types.logger.error(`Error deploying module: ${e}`);
785
+ process.exit(1);
786
+ }
787
+ });
788
+ }
789
+
790
+ // SPDX-License-Identifier: Apache-2.0
791
+ function dev (program) {
792
+ program
793
+ .command("dev")
794
+ .description("Setup a local webhook development environment")
795
+ .option("-d, --dir [directory]", "Pepr module directory", ".")
796
+ .option("-h, --host [host]", "Host to listen on", "host.docker.internal")
797
+ .action(async (opts) => {
798
+ // Prompt the user to confirm
799
+ const confirm = await prompt.prompt({
800
+ type: "confirm",
801
+ name: "confirm",
802
+ message: "This will remove and redeploy the module. Continue?",
803
+ });
804
+ // Exit if the user doesn't confirm
805
+ if (!confirm.confirm) {
806
+ process.exit(0);
807
+ }
808
+ // Build the module
809
+ const { cfg, path } = await buildModule(opts.dir);
810
+ // Read the compiled module code
811
+ const code = await fs.promises.readFile(path, { encoding: "utf-8" });
812
+ // Generate a secret for the module
813
+ const webhook = new Webhook({
814
+ ...cfg.pepr,
815
+ description: cfg.description,
816
+ }, opts.host);
817
+ // Write the TLS cert and key to disk
818
+ await fs.promises.writeFile("insecure-tls.crt", webhook.tls.pem.crt);
819
+ await fs.promises.writeFile("insecure-tls.key", webhook.tls.pem.key);
820
+ try {
821
+ await webhook.deploy(code);
822
+ types.logger.info(`Module deployed successfully`);
823
+ }
824
+ catch (e) {
825
+ types.logger.error(`Error deploying module: ${e}`);
705
826
  process.exit(1);
706
827
  }
707
828
  });
@@ -1027,11 +1148,7 @@ function walkthrough() {
1027
1148
  },
1028
1149
  ],
1029
1150
  };
1030
- return prompt([
1031
- askName,
1032
- askDescription,
1033
- askErrorBehavior,
1034
- ]);
1151
+ return prompt([askName, askDescription, askErrorBehavior]);
1035
1152
  }
1036
1153
  async function confirm(dirName, packageJSON, peprTSPath) {
1037
1154
  console.log(`
@@ -1090,8 +1207,8 @@ function init (program) {
1090
1207
  console.log(`Open VSCode or your editor of choice in ${dirName} to get started!`);
1091
1208
  }
1092
1209
  catch (e) {
1093
- types.Log.debug(e);
1094
- types.Log.error(e.message);
1210
+ types.logger.debug(e);
1211
+ types.logger.error(e.message);
1095
1212
  process.exit(1);
1096
1213
  }
1097
1214
  }
@@ -1104,7 +1221,7 @@ class RootCmd extends commander.Command {
1104
1221
  const cmd = new commander.Command(name);
1105
1222
  cmd.option("-l, --log-level [level]", "Log level: debug, info, warn, error", "info");
1106
1223
  cmd.hook("preAction", run => {
1107
- types.Log.SetLogLevel(run.opts().logLevel);
1224
+ types.logger.SetLogLevel(run.opts().logLevel);
1108
1225
  });
1109
1226
  return cmd;
1110
1227
  }
@@ -1119,15 +1236,15 @@ function test (program) {
1119
1236
  .option("-d, --dir [directory]", "Pepr module directory", ".")
1120
1237
  .option("-w, --watch", "Watch for changes and re-run the test")
1121
1238
  .action(async (opts) => {
1122
- types.Log.info("Test Module");
1239
+ types.logger.info("Test Module");
1123
1240
  await buildAndTest(opts.dir);
1124
1241
  if (opts.watch) {
1125
1242
  const moduleFiles = path.resolve(opts.dir, "**", "*.ts");
1126
1243
  const watcher = chokidar.watch(moduleFiles);
1127
1244
  watcher.on("ready", () => {
1128
- types.Log.info(`Watching for changes in ${moduleFiles}`);
1245
+ types.logger.info(`Watching for changes in ${moduleFiles}`);
1129
1246
  watcher.on("all", async (event, path) => {
1130
- types.Log.debug({ event, path }, "File changed");
1247
+ types.logger.debug({ event, path }, "File changed");
1131
1248
  await buildAndTest(opts.dir);
1132
1249
  });
1133
1250
  });
@@ -1136,15 +1253,15 @@ function test (program) {
1136
1253
  }
1137
1254
  async function buildAndTest(dir) {
1138
1255
  const { path } = await buildModule(dir);
1139
- types.Log.info(`Module built successfully at ${path}`);
1256
+ types.logger.info(`Module built successfully at ${path}`);
1140
1257
  try {
1141
1258
  const { stdout, stderr } = await exec(`node ${path}`);
1142
1259
  console.log(stdout);
1143
1260
  console.log(stderr);
1144
1261
  }
1145
1262
  catch (e) {
1146
- types.Log.debug(e);
1147
- types.Log.error(`Error running module: ${e}`);
1263
+ types.logger.debug(e);
1264
+ types.logger.error(`Error running module: ${e}`);
1148
1265
  process.exit(1);
1149
1266
  }
1150
1267
  }
@@ -1165,4 +1282,5 @@ build(program);
1165
1282
  capability(program);
1166
1283
  test(program);
1167
1284
  deploy(program);
1285
+ dev(program);
1168
1286
  program.parse();
package/dist/pepr-core.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
- var types = require('./types-672dd6e4.js');
5
4
  var dist = require('@kubernetes/client-node/dist');
5
+ var types = require('./types-1709b44f.js');
6
6
  var R = require('ramda');
7
7
  var fastJsonPatch = require('fast-json-patch');
8
8
 
@@ -501,6 +501,16 @@ function modelToGroupVersionKind(key) {
501
501
  return gvkMap[key];
502
502
  }
503
503
 
504
+ // SPDX-License-Identifier: Apache-2.0
505
+ // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
506
+ var Operation;
507
+ (function (Operation) {
508
+ Operation["CREATE"] = "CREATE";
509
+ Operation["UPDATE"] = "UPDATE";
510
+ Operation["DELETE"] = "DELETE";
511
+ Operation["CONNECT"] = "CONNECT";
512
+ })(Operation || (Operation = {}));
513
+
504
514
  // SPDX-License-Identifier: Apache-2.0
505
515
  /**
506
516
  * A capability is a unit of functionality that can be registered with the Pepr runtime.
@@ -553,10 +563,10 @@ class Capability {
553
563
  callback: () => null,
554
564
  };
555
565
  const prefix = `${this._name}: ${model.name}`;
556
- types.Log.info(`Binding created`, prefix);
566
+ types.logger.info(`Binding created`, prefix);
557
567
  const Then = (cb) => {
558
- types.Log.info(`Binding action created`, prefix);
559
- types.Log.debug(cb.toString(), prefix);
568
+ types.logger.info(`Binding action created`, prefix);
569
+ types.logger.debug(cb.toString(), prefix);
560
570
  // Push the binding to the list of bindings for this capability as a new BindingAction
561
571
  // with the callback function to preserve
562
572
  this._bindings.push({
@@ -572,22 +582,22 @@ class Capability {
572
582
  return { Then };
573
583
  };
574
584
  function InNamespace(...namespaces) {
575
- types.Log.debug(`Add namespaces filter ${namespaces}`, prefix);
585
+ types.logger.debug(`Add namespaces filter ${namespaces}`, prefix);
576
586
  binding.filters.namespaces.push(...namespaces);
577
587
  return { WithLabel, WithAnnotation, WithName, Then, ThenSet };
578
588
  }
579
589
  function WithName(name) {
580
- types.Log.debug(`Add name filter ${name}`, prefix);
590
+ types.logger.debug(`Add name filter ${name}`, prefix);
581
591
  binding.filters.name = name;
582
592
  return { WithLabel, WithAnnotation, Then, ThenSet };
583
593
  }
584
594
  function WithLabel(key, value = "") {
585
- types.Log.debug(`Add label filter ${key}=${value}`, prefix);
595
+ types.logger.debug(`Add label filter ${key}=${value}`, prefix);
586
596
  binding.filters.labels[key] = value;
587
597
  return { WithLabel, WithAnnotation, Then, ThenSet };
588
598
  }
589
599
  const WithAnnotation = (key, value = "") => {
590
- types.Log.debug(`Add annotation filter ${key}=${value}`, prefix);
600
+ types.logger.debug(`Add annotation filter ${key}=${value}`, prefix);
591
601
  binding.filters.annotations[key] = value;
592
602
  return { WithLabel, WithAnnotation, Then, ThenSet };
593
603
  };
@@ -612,11 +622,54 @@ class Capability {
612
622
  this._name = cfg.name;
613
623
  this._description = cfg.description;
614
624
  this._namespaces = cfg.namespaces;
615
- types.Log.info(`Capability ${this._name} registered`);
616
- types.Log.debug(cfg);
625
+ types.logger.info(`Capability ${this._name} registered`);
626
+ types.logger.debug(cfg);
617
627
  }
618
628
  }
619
629
 
630
+ // SPDX-License-Identifier: Apache-2.0
631
+ /**
632
+ * shouldSkipRequest determines if a request should be skipped based on the binding filters.
633
+ *
634
+ * @param binding the capability action binding
635
+ * @param req the incoming request
636
+ * @returns
637
+ */
638
+ function shouldSkipRequest(binding, req) {
639
+ const { group, kind, version } = binding.kind;
640
+ const { namespaces, labels, annotations } = binding.filters;
641
+ const { metadata } = req.object;
642
+ if (kind !== req.kind.kind) {
643
+ types.logger.debug(`${req.kind.kind} does not match ${kind}`);
644
+ return true;
645
+ }
646
+ if (group && group !== req.kind.group) {
647
+ types.logger.debug(`${req.kind.group} does not match ${group}`);
648
+ return true;
649
+ }
650
+ if (version && version !== req.kind.version) {
651
+ types.logger.debug(`${req.kind.version} does not match ${version}`);
652
+ return true;
653
+ }
654
+ if (namespaces.length && !namespaces.includes(req.namespace || "")) {
655
+ types.logger.debug(`${req.namespace} is not in ${namespaces}`);
656
+ return true;
657
+ }
658
+ for (const [key, value] of Object.entries(labels)) {
659
+ if (metadata?.labels?.[key] !== value) {
660
+ types.logger.debug(`${metadata?.labels?.[key]} does not match ${value}`);
661
+ return true;
662
+ }
663
+ }
664
+ for (const [key, value] of Object.entries(annotations)) {
665
+ if (metadata?.annotations?.[key] !== value) {
666
+ types.logger.debug(`${metadata?.annotations?.[key]} does not match ${value}`);
667
+ return true;
668
+ }
669
+ }
670
+ return false;
671
+ }
672
+
620
673
  // SPDX-License-Identifier: Apache-2.0
621
674
  /**
622
675
  * The RequestWrapper class provides methods to modify Kubernetes objects in the context
@@ -733,49 +786,6 @@ class RequestWrapper {
733
786
  }
734
787
  }
735
788
 
736
- // SPDX-License-Identifier: Apache-2.0
737
- /**
738
- * shouldSkipRequest determines if a request should be skipped based on the binding filters.
739
- *
740
- * @param binding the capability action binding
741
- * @param req the incoming request
742
- * @returns
743
- */
744
- function shouldSkipRequest(binding, req) {
745
- const { group, kind, version } = binding.kind;
746
- const { namespaces, labels, annotations } = binding.filters;
747
- const { metadata } = req.object;
748
- if (kind !== req.kind.kind) {
749
- types.Log.debug(`${req.kind.kind} does not match ${kind}`);
750
- return true;
751
- }
752
- if (group && group !== req.kind.group) {
753
- types.Log.debug(`${req.kind.group} does not match ${group}`);
754
- return true;
755
- }
756
- if (version && version !== req.kind.version) {
757
- types.Log.debug(`${req.kind.version} does not match ${version}`);
758
- return true;
759
- }
760
- if (namespaces.length && !namespaces.includes(req.namespace || "")) {
761
- types.Log.debug(`${req.namespace} is not in ${namespaces}`);
762
- return true;
763
- }
764
- for (const [key, value] of Object.entries(labels)) {
765
- if (metadata?.labels?.[key] !== value) {
766
- types.Log.debug(`${metadata?.labels?.[key]} does not match ${value}`);
767
- return true;
768
- }
769
- }
770
- for (const [key, value] of Object.entries(annotations)) {
771
- if (metadata?.annotations?.[key] !== value) {
772
- types.Log.debug(`${metadata?.annotations?.[key]} does not match ${value}`);
773
- return true;
774
- }
775
- }
776
- return false;
777
- }
778
-
779
789
  // SPDX-License-Identifier: Apache-2.0
780
790
  function processor(config, capabilities, req) {
781
791
  const wrapped = new RequestWrapper(req);
@@ -785,16 +795,16 @@ function processor(config, capabilities, req) {
785
795
  warnings: [],
786
796
  allowed: false,
787
797
  };
788
- types.Log.info(`Processing '${req.uid}' for '${req.kind.kind}' '${req.name}'`);
798
+ types.logger.info(`Processing '${req.uid}' for '${req.kind.kind}' '${req.name}'`);
789
799
  for (const { name, bindings } of capabilities) {
790
800
  const prefix = `${req.uid} ${req.name}: ${name}`;
791
- types.Log.info(`Processing capability ${name}`, prefix);
801
+ types.logger.info(`Processing capability ${name}`, prefix);
792
802
  for (const action of bindings) {
793
803
  // Continue to the next action without doing anything if this one should be skipped
794
804
  if (shouldSkipRequest(action, req)) {
795
805
  continue;
796
806
  }
797
- types.Log.info(`Processing matched action ${action.kind.kind}`, prefix);
807
+ types.logger.info(`Processing matched action ${action.kind.kind}`, prefix);
798
808
  // Add annotations to the request to indicate that the capability started processing
799
809
  // this will allow tracking of failed mutations that were permitted to continue
800
810
  const { metadata } = wrapped.Raw;
@@ -811,12 +821,12 @@ function processor(config, capabilities, req) {
811
821
  response.warnings.push(`Action failed: ${e}`);
812
822
  // If errors are not allowed, note the failure in the Reponse
813
823
  if (config.onError) {
814
- types.Log.error(`Action failed: ${e}`, prefix);
824
+ types.logger.error(`Action failed: ${e}`, prefix);
815
825
  response.result = "Pepr module configured to reject on error";
816
826
  return response;
817
827
  }
818
828
  else {
819
- types.Log.warn(`Action failed: ${e}`, prefix);
829
+ types.logger.warn(`Action failed: ${e}`, prefix);
820
830
  metadata.annotations[identifier] = "warning";
821
831
  }
822
832
  }
@@ -834,7 +844,7 @@ function processor(config, capabilities, req) {
834
844
  if (response.warnings.length < 1) {
835
845
  delete response.warnings;
836
846
  }
837
- types.Log.debug(patches);
847
+ types.logger.debug(patches);
838
848
  return response;
839
849
  }
840
850
 
@@ -859,7 +869,7 @@ class PeprModule {
859
869
  this._state = [];
860
870
  this._kinds = [];
861
871
  this.Register = (capability) => {
862
- types.Log.info(`Registering capability ${capability.name}`);
872
+ types.logger.info(`Registering capability ${capability.name}`);
863
873
  // Add the kinds to the list of kinds (ignoring duplicates for now)
864
874
  this._kinds = capability.bindings.map(({ kind }) => kind);
865
875
  // Add the capability to the state
@@ -873,26 +883,7 @@ class PeprModule {
873
883
  }
874
884
  }
875
885
 
876
- Object.defineProperty(exports, 'ErrorBehavior', {
877
- enumerable: true,
878
- get: function () { return types.ErrorBehavior; }
879
- });
880
- Object.defineProperty(exports, 'Event', {
881
- enumerable: true,
882
- get: function () { return types.Event; }
883
- });
884
- Object.defineProperty(exports, 'HookPhase', {
885
- enumerable: true,
886
- get: function () { return types.HookPhase; }
887
- });
888
- exports.Log = types.Log;
889
- Object.defineProperty(exports, 'Operation', {
890
- enumerable: true,
891
- get: function () { return types.Operation; }
892
- });
886
+ exports.Log = types.logger;
893
887
  exports.Capability = Capability;
894
888
  exports.PeprModule = PeprModule;
895
- exports.RequestWrapper = RequestWrapper;
896
889
  exports.a = upstream;
897
- exports.gvkMap = gvkMap;
898
- exports.modelToGroupVersionKind = modelToGroupVersionKind;
@@ -116,17 +116,7 @@ class Logger {
116
116
  return color + text + ConsoleColors.Reset;
117
117
  }
118
118
  }
119
- var Log = new Logger(LogLevel.info);
120
-
121
- // SPDX-License-Identifier: Apache-2.0
122
- // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
123
- exports.Operation = void 0;
124
- (function (Operation) {
125
- Operation["CREATE"] = "CREATE";
126
- Operation["UPDATE"] = "UPDATE";
127
- Operation["DELETE"] = "DELETE";
128
- Operation["CONNECT"] = "CONNECT";
129
- })(exports.Operation || (exports.Operation = {}));
119
+ var logger = new Logger(LogLevel.info);
130
120
 
131
121
  // SPDX-License-Identifier: Apache-2.0
132
122
  // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
@@ -160,4 +150,4 @@ exports.Event = void 0;
160
150
  Event["CreateOrUpdate"] = "createOrUpdate";
161
151
  })(exports.Event || (exports.Event = {}));
162
152
 
163
- exports.Log = Log;
153
+ exports.logger = logger;
package/index.ts CHANGED
@@ -1,2 +1,7 @@
1
- export * from "./src/lib";
2
- export * from "./src/lib/k8s";
1
+ import { Capability } from './src/lib/capability';
2
+ import { a } from './src/lib/k8s';
3
+ import Log from './src/lib/logger';
4
+ import { PeprModule } from './src/lib/module';
5
+
6
+ export { a, PeprModule, Capability, Log };
7
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pepr",
3
- "version": "0.1.21",
3
+ "version": "0.1.24",
4
4
  "description": "Kubernetes application engine",
5
5
  "author": "Defense Unicorns",
6
6
  "homepage": "https://github.com/defenseunicorns/pepr",
@@ -29,7 +29,10 @@
29
29
  "prettier": "npx prettier src --check",
30
30
  "prettier:fix": "npm run prettier -- --write",
31
31
  "prepublishOnly": "rm -fr dist/* && npm run lint:fix && npm run prettier:fix && npm run test && npm run build",
32
- "e2e-dev": "npm run build && docker buildx build --tag pepr:dev . && k3d image import pepr:dev && node dist/pepr-cli.js deploy -f -i pepr:dev"
32
+ "e2e-dev-setup": "k3d cluster delete pepr-dev && k3d cluster create pepr-dev",
33
+ "e2e-dev": "npm run build && docker buildx build --tag pepr:dev . && k3d image import pepr:dev -c pepr-dev && node dist/pepr-cli.js deploy -f -i pepr:dev",
34
+ "prestart": "ts-node src/cli dev",
35
+ "start": "chokidar 'src/**/*.ts' -c 'SSL_KEY_PATH=insecure-tls.key SSL_CERT_PATH=insecure-tls.crt ts-node src/controller/index.ts' --initial --silent"
33
36
  },
34
37
  "dependencies": {
35
38
  "@kubernetes/client-node": "^0.18.1",
@@ -59,6 +62,7 @@
59
62
  "@typescript-eslint/eslint-plugin": "^5.57.0",
60
63
  "@typescript-eslint/parser": "^5.57.0",
61
64
  "ava": "^5.2.0",
65
+ "chokidar-cli": "^3.0.0",
62
66
  "eslint": "^8.37.0",
63
67
  "ts-node": "^10.9.1",
64
68
  "tsconfig-paths": "^4.1.2"
@@ -6,6 +6,11 @@ export interface TLSOut {
6
6
  ca: string;
7
7
  crt: string;
8
8
  key: string;
9
+ pem: {
10
+ ca: string;
11
+ crt: string;
12
+ key: string;
13
+ };
9
14
  }
10
15
 
11
16
  /**
@@ -36,18 +41,25 @@ export function genTLS(name: string): TLSOut {
36
41
 
37
42
  // Generate a new server key pair and create a server certificate signed by the CA
38
43
  const serverKeys = forge.pki.rsa.generateKeyPair(2048);
39
- const serverCert = genCert(serverKeys, `${name}.pepr-system.svc`, caCert.subject.attributes);
44
+ const serverCert = genCert(serverKeys, name, caCert.subject.attributes);
40
45
 
41
46
  // Sign both certificates with the CA private key
42
47
  caCert.sign(caKeys.privateKey, forge.md.sha256.create());
43
48
  serverCert.sign(caKeys.privateKey, forge.md.sha256.create());
44
49
 
45
- // Convert the keys and certificates to PEM format and Base64-encode them
46
- const ca = Buffer.from(forge.pki.certificateToPem(caCert)).toString("base64");
47
- const key = Buffer.from(forge.pki.privateKeyToPem(serverKeys.privateKey)).toString("base64");
48
- const crt = Buffer.from(forge.pki.certificateToPem(serverCert)).toString("base64");
50
+ // Convert the keys and certificates to PEM format
51
+ const pem = {
52
+ ca: forge.pki.certificateToPem(caCert),
53
+ crt: forge.pki.certificateToPem(serverCert),
54
+ key: forge.pki.privateKeyToPem(serverKeys.privateKey),
55
+ };
49
56
 
50
- return { ca, key, crt };
57
+ // Base64-encode the PEM strings
58
+ const ca = Buffer.from(pem.ca).toString("base64");
59
+ const key = Buffer.from(pem.key).toString("base64");
60
+ const crt = Buffer.from(pem.crt).toString("base64");
61
+
62
+ return { ca, key, crt, pem };
51
63
  }
52
64
 
53
65
  function genCert(key: forge.pki.rsa.KeyPair, name: string, issuer: forge.pki.CertificateField[]) {
@@ -3,9 +3,11 @@
3
3
 
4
4
  import {
5
5
  AdmissionregistrationV1Api,
6
+ AdmissionregistrationV1WebhookClientConfig,
6
7
  AppsV1Api,
7
8
  CoreV1Api,
8
9
  KubeConfig,
10
+ NetworkingV1Api,
9
11
  RbacAuthorizationV1Api,
10
12
  V1ClusterRole,
11
13
  V1ClusterRoleBinding,
@@ -13,13 +15,14 @@ import {
13
15
  V1LabelSelectorRequirement,
14
16
  V1MutatingWebhookConfiguration,
15
17
  V1Namespace,
18
+ V1NetworkPolicy,
16
19
  V1Secret,
17
20
  V1Service,
18
21
  V1ServiceAccount,
19
22
  dumpYaml,
20
23
  } from "@kubernetes/client-node";
21
24
  import { gzipSync } from "zlib";
22
- import logger from "../logger";
25
+ import Log from "../logger";
23
26
  import { ModuleConfig } from "../types";
24
27
  import { TLSOut, genTLS } from "./tls";
25
28
 
@@ -31,17 +34,21 @@ const peprIgnore: V1LabelSelectorRequirement = {
31
34
 
32
35
  export class Webhook {
33
36
  private name: string;
34
- private tls: TLSOut;
37
+ private _tls: TLSOut;
35
38
 
36
39
  public image: string;
37
40
 
38
- constructor(private readonly config: ModuleConfig) {
41
+ public get tls(): TLSOut {
42
+ return this._tls;
43
+ }
44
+
45
+ constructor(private readonly config: ModuleConfig, private readonly host?: string) {
39
46
  this.name = `pepr-${config.uuid}`;
40
47
 
41
48
  this.image = `ghcr.io/defenseunicorns/pepr/controller:${config.version}`;
42
49
 
43
50
  // Generate the ephemeral tls things
44
- this.tls = genTLS(this.name);
51
+ this._tls = genTLS(this.host || `${this.name}.pepr-system.svc`);
45
52
  }
46
53
 
47
54
  /** Generate the pepr-system namespace */
@@ -117,8 +124,8 @@ export class Webhook {
117
124
  },
118
125
  type: "kubernetes.io/tls",
119
126
  data: {
120
- "tls.crt": this.tls.crt,
121
- "tls.key": this.tls.key,
127
+ "tls.crt": this._tls.crt,
128
+ "tls.key": this._tls.key,
122
129
  },
123
130
  };
124
131
  }
@@ -136,6 +143,22 @@ export class Webhook {
136
143
  });
137
144
  }
138
145
 
146
+ const clientConfig: AdmissionregistrationV1WebhookClientConfig = {
147
+ caBundle: this._tls.ca,
148
+ };
149
+
150
+ // If a host is specified, use that with a port of 3000
151
+ if (this.host) {
152
+ clientConfig.url = `https://${this.host}:3000/mutate`;
153
+ } else {
154
+ // Otherwise, use the service
155
+ clientConfig.service = {
156
+ name: this.name,
157
+ namespace: "pepr-system",
158
+ path: "/mutate",
159
+ };
160
+ }
161
+
139
162
  return {
140
163
  apiVersion: "admissionregistration.k8s.io/v1",
141
164
  kind: "MutatingWebhookConfiguration",
@@ -144,14 +167,7 @@ export class Webhook {
144
167
  {
145
168
  name: `${name}.pepr.dev`,
146
169
  admissionReviewVersions: ["v1", "v1beta1"],
147
- clientConfig: {
148
- caBundle: this.tls.ca,
149
- service: {
150
- name: this.name,
151
- namespace: "pepr-system",
152
- path: "/mutate",
153
- },
154
- },
170
+ clientConfig,
155
171
  failurePolicy: "Ignore",
156
172
  matchPolicy: "Equivalent",
157
173
  timeoutSeconds: 15,
@@ -237,6 +253,11 @@ export class Webhook {
237
253
  mountPath: "/etc/certs",
238
254
  readOnly: true,
239
255
  },
256
+ {
257
+ name: "module",
258
+ mountPath: "/app/module.js.gz",
259
+ readOnly: true,
260
+ },
240
261
  ],
241
262
  },
242
263
  ],
@@ -247,6 +268,12 @@ export class Webhook {
247
268
  secretName: `${this.name}-tls`,
248
269
  },
249
270
  },
271
+ {
272
+ name: "module",
273
+ secret: {
274
+ secretName: `${this.name}-module`,
275
+ },
276
+ },
250
277
  ],
251
278
  },
252
279
  },
@@ -254,6 +281,45 @@ export class Webhook {
254
281
  };
255
282
  }
256
283
 
284
+ /** Only permit the */
285
+ networkPolicy(): V1NetworkPolicy {
286
+ return {
287
+ apiVersion: "networking.k8s.io/v1",
288
+ kind: "NetworkPolicy",
289
+ metadata: {
290
+ name: this.name,
291
+ namespace: "pepr-system",
292
+ },
293
+ spec: {
294
+ podSelector: {
295
+ matchLabels: {
296
+ app: this.name,
297
+ },
298
+ },
299
+ policyTypes: ["Ingress"],
300
+ ingress: [
301
+ {
302
+ from: [
303
+ {
304
+ namespaceSelector: {
305
+ matchLabels: {
306
+ "kubernetes.io/metadata.name": "kube-system",
307
+ },
308
+ },
309
+ },
310
+ ],
311
+ ports: [
312
+ {
313
+ protocol: "TCP",
314
+ port: 443,
315
+ },
316
+ ],
317
+ },
318
+ ],
319
+ },
320
+ };
321
+ }
322
+
257
323
  service(): V1Service {
258
324
  return {
259
325
  apiVersion: "v1",
@@ -324,6 +390,7 @@ export class Webhook {
324
390
  allYaml(code: string) {
325
391
  const resources = [
326
392
  this.namespace(),
393
+ this.networkPolicy(),
327
394
  this.clusterRole(),
328
395
  this.clusterRoleBinding(),
329
396
  this.serviceAccount(),
@@ -339,7 +406,7 @@ export class Webhook {
339
406
  }
340
407
 
341
408
  async deploy(code: string) {
342
- logger.info("Establishing connection to Kubernetes");
409
+ Log.info("Establishing connection to Kubernetes");
343
410
 
344
411
  const namespace = "pepr-system";
345
412
 
@@ -351,105 +418,121 @@ export class Webhook {
351
418
  const rbacApi = kubeConfig.makeApiClient(RbacAuthorizationV1Api);
352
419
  const appsApi = kubeConfig.makeApiClient(AppsV1Api);
353
420
  const admissionApi = kubeConfig.makeApiClient(AdmissionregistrationV1Api);
421
+ const networkApi = kubeConfig.makeApiClient(NetworkingV1Api);
354
422
 
355
423
  const ns = this.namespace();
356
424
  try {
357
- logger.info("Checking for namespace");
425
+ Log.info("Checking for namespace");
358
426
  await coreV1Api.readNamespace(namespace);
359
427
  } catch (e) {
360
- logger.debug(e.body);
361
- logger.info("Creating namespace");
428
+ Log.debug(e.body);
429
+ Log.info("Creating namespace");
362
430
  await coreV1Api.createNamespace(ns);
363
431
  }
364
432
 
433
+ const netpol = this.networkPolicy();
434
+ try {
435
+ Log.info("Checking for network policy");
436
+ await networkApi.readNamespacedNetworkPolicy(netpol.metadata.name, namespace);
437
+ } catch (e) {
438
+ Log.debug(e.body);
439
+ Log.info("Creating network policy");
440
+ await networkApi.createNamespacedNetworkPolicy(namespace, netpol);
441
+ }
442
+
365
443
  const wh = this.mutatingWebhook();
366
444
  try {
367
- logger.info("Creating mutating webhook");
445
+ Log.info("Creating mutating webhook");
368
446
  await admissionApi.createMutatingWebhookConfiguration(wh);
369
447
  } catch (e) {
370
- logger.debug(e.body);
371
- logger.info("Removing and re-creating mutating webhook");
448
+ Log.debug(e.body);
449
+ Log.info("Removing and re-creating mutating webhook");
372
450
  await admissionApi.deleteMutatingWebhookConfiguration(wh.metadata.name);
373
451
  await admissionApi.createMutatingWebhookConfiguration(wh);
374
452
  }
375
453
 
376
454
  const crb = this.clusterRoleBinding();
377
455
  try {
378
- logger.info("Creating cluster role binding");
456
+ Log.info("Creating cluster role binding");
379
457
  await rbacApi.createClusterRoleBinding(crb);
380
458
  } catch (e) {
381
- logger.debug(e.body);
382
- logger.info("Removing and re-creating cluster role binding");
459
+ Log.debug(e.body);
460
+ Log.info("Removing and re-creating cluster role binding");
383
461
  await rbacApi.deleteClusterRoleBinding(crb.metadata.name);
384
462
  await rbacApi.createClusterRoleBinding(crb);
385
463
  }
386
464
 
387
465
  const cr = this.clusterRole();
388
466
  try {
389
- logger.info("Creating cluster role");
467
+ Log.info("Creating cluster role");
390
468
  await rbacApi.createClusterRole(cr);
391
469
  } catch (e) {
392
- logger.debug(e.body);
393
- logger.info("Removing and re-creating the cluster role");
470
+ Log.debug(e.body);
471
+ Log.info("Removing and re-creating the cluster role");
394
472
  try {
395
473
  await rbacApi.deleteClusterRole(cr.metadata.name);
396
474
  await rbacApi.createClusterRole(cr);
397
475
  } catch (e) {
398
- logger.debug(e.body);
476
+ Log.debug(e.body);
399
477
  }
400
478
  }
401
479
 
402
480
  const sa = this.serviceAccount();
403
481
  try {
404
- logger.info("Creating service account");
482
+ Log.info("Creating service account");
405
483
  await coreV1Api.createNamespacedServiceAccount(namespace, sa);
406
484
  } catch (e) {
407
- logger.debug(e.body);
408
- logger.info("Removing and re-creating service account");
485
+ Log.debug(e.body);
486
+ Log.info("Removing and re-creating service account");
409
487
  await coreV1Api.deleteNamespacedServiceAccount(sa.metadata.name, namespace);
410
488
  await coreV1Api.createNamespacedServiceAccount(namespace, sa);
411
489
  }
412
490
 
491
+ // If a host is specified, we don't need to deploy the rest of the resources
492
+ if (this.host) {
493
+ return;
494
+ }
495
+
413
496
  const mod = this.moduleSecret(code);
414
497
  try {
415
- logger.info("Creating module secret");
498
+ Log.info("Creating module secret");
416
499
  await coreV1Api.createNamespacedSecret(namespace, mod);
417
500
  } catch (e) {
418
- logger.debug(e.body);
419
- logger.info("Removing and re-creating module secret");
501
+ Log.debug(e.body);
502
+ Log.info("Removing and re-creating module secret");
420
503
  await coreV1Api.deleteNamespacedSecret(mod.metadata.name, namespace);
421
504
  await coreV1Api.createNamespacedSecret(namespace, mod);
422
505
  }
423
506
 
424
507
  const svc = this.service();
425
508
  try {
426
- logger.info("Creating service");
509
+ Log.info("Creating service");
427
510
  await coreV1Api.createNamespacedService(namespace, svc);
428
511
  } catch (e) {
429
- logger.debug(e.body);
430
- logger.info("Removing and re-creating service");
512
+ Log.debug(e.body);
513
+ Log.info("Removing and re-creating service");
431
514
  await coreV1Api.deleteNamespacedService(svc.metadata.name, namespace);
432
515
  await coreV1Api.createNamespacedService(namespace, svc);
433
516
  }
434
517
 
435
518
  const tls = this.tlsSecret();
436
519
  try {
437
- logger.info("Creating TLS secret");
520
+ Log.info("Creating TLS secret");
438
521
  await coreV1Api.createNamespacedSecret(namespace, tls);
439
522
  } catch (e) {
440
- logger.debug(e.body);
441
- logger.info("Removing and re-creating TLS secret");
523
+ Log.debug(e.body);
524
+ Log.info("Removing and re-creating TLS secret");
442
525
  await coreV1Api.deleteNamespacedSecret(tls.metadata.name, namespace);
443
526
  await coreV1Api.createNamespacedSecret(namespace, tls);
444
527
  }
445
528
 
446
529
  const dep = this.deployment();
447
530
  try {
448
- logger.info("Creating deployment");
531
+ Log.info("Creating deployment");
449
532
  await appsApi.createNamespacedDeployment(namespace, dep);
450
533
  } catch (e) {
451
- logger.debug(e.body);
452
- logger.info("Removing and re-creating deployment");
534
+ Log.debug(e.body);
535
+ Log.info("Removing and re-creating deployment");
453
536
  await appsApi.deleteNamespacedDeployment(dep.metadata.name, namespace);
454
537
  await appsApi.createNamespacedDeployment(namespace, dep);
455
538
  }
package/src/lib/index.ts DELETED
@@ -1,10 +0,0 @@
1
- // SPDX-License-Identifier: Apache-2.0
2
- // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
3
-
4
- import logger from "./logger";
5
-
6
- export { logger as Log };
7
- export * from "./capability";
8
- export * from "./request";
9
- export * from "./module";
10
- export * from "./types";