pepr 0.1.7 → 0.1.9
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/dist/pepr-cli.js +427 -95
- package/dist/pepr-cli.js.map +1 -1
- package/package.json +12 -6
- package/src/lib/k8s/tls.ts +57 -0
- package/src/lib/k8s/types.ts +0 -5
- package/src/lib/k8s/webhook.ts +282 -227
- package/src/lib/module.ts +11 -18
- package/src/lib/types.ts +8 -9
- package/tsconfig.json +2 -1
- package/dist/pepr-20e17cf6-a2e4-46b2-b626-75d88d96c88b.js +0 -393
- package/src/lib/k8s/stub-tls.ts +0 -88
package/dist/pepr-cli.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var clientNode = require('@kubernetes/client-node');
|
|
5
4
|
var json = require('@rollup/plugin-json');
|
|
6
5
|
var nodeResolve = require('@rollup/plugin-node-resolve');
|
|
7
6
|
var typescript = require('@rollup/plugin-typescript');
|
|
@@ -11,7 +10,9 @@ var rollup = require('rollup');
|
|
|
11
10
|
require('@kubernetes/client-node/dist');
|
|
12
11
|
require('ramda');
|
|
13
12
|
require('fast-json-patch');
|
|
13
|
+
var clientNode = require('@kubernetes/client-node');
|
|
14
14
|
var zlib = require('zlib');
|
|
15
|
+
var forge = require('node-forge');
|
|
15
16
|
var util = require('util');
|
|
16
17
|
var uuid = require('uuid');
|
|
17
18
|
var prompt = require('prompts');
|
|
@@ -19,7 +20,7 @@ var commander = require('commander');
|
|
|
19
20
|
var child_process = require('child_process');
|
|
20
21
|
var chokidar = require('chokidar');
|
|
21
22
|
|
|
22
|
-
var version = "0.1.
|
|
23
|
+
var version = "0.1.9";
|
|
23
24
|
var dependencies = {
|
|
24
25
|
"@kubernetes/client-node": "^0.18.1",
|
|
25
26
|
"@rollup/plugin-json": "^6.0.0",
|
|
@@ -30,21 +31,23 @@ var dependencies = {
|
|
|
30
31
|
commander: "^10.0.0",
|
|
31
32
|
express: "^4.18.2",
|
|
32
33
|
"fast-json-patch": "^3.1.1",
|
|
34
|
+
"node-forge": "^1.3.1",
|
|
35
|
+
prettier: "^2.8.7",
|
|
33
36
|
prompts: "^2.4.2",
|
|
34
37
|
ramda: "^0.28.0",
|
|
35
38
|
rollup: "^3.20.2",
|
|
36
|
-
uuid: "^9.0.0",
|
|
37
39
|
tslib: "^2.5.0",
|
|
38
|
-
typescript: "^5.0.2"
|
|
40
|
+
typescript: "^5.0.2",
|
|
41
|
+
uuid: "^9.0.0"
|
|
39
42
|
};
|
|
40
43
|
var devDependencies = {
|
|
44
|
+
"@types/node-forge": "^1.3.2",
|
|
41
45
|
"@types/prompts": "^2.4.4",
|
|
42
46
|
"@types/uuid": "^9.0.1",
|
|
43
47
|
"@typescript-eslint/eslint-plugin": "^5.57.0",
|
|
44
48
|
"@typescript-eslint/parser": "^5.57.0",
|
|
45
49
|
ava: "^5.2.0",
|
|
46
50
|
eslint: "^8.37.0",
|
|
47
|
-
prettier: "^2.8.7",
|
|
48
51
|
"rollup-plugin-visualizer": "^5.9.0",
|
|
49
52
|
"ts-node": "^10.9.1",
|
|
50
53
|
"tsconfig-paths": "^4.1.2"
|
|
@@ -278,21 +281,341 @@ var Event;
|
|
|
278
281
|
})(Event || (Event = {}));
|
|
279
282
|
|
|
280
283
|
// SPDX-License-Identifier: Apache-2.0
|
|
281
|
-
function
|
|
282
|
-
//
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
284
|
+
function genTLS(name) {
|
|
285
|
+
// Generate a new CA key pair
|
|
286
|
+
const caKeys = forge.pki.rsa.generateKeyPair(2048);
|
|
287
|
+
const caCert = forge.pki.createCertificate();
|
|
288
|
+
caCert.publicKey = caKeys.publicKey;
|
|
289
|
+
caCert.serialNumber = "01";
|
|
290
|
+
caCert.validity.notBefore = new Date();
|
|
291
|
+
caCert.validity.notAfter = new Date();
|
|
292
|
+
caCert.validity.notAfter.setFullYear(caCert.validity.notBefore.getFullYear() + 1);
|
|
293
|
+
const caAttrs = [
|
|
294
|
+
{
|
|
295
|
+
name: "commonName",
|
|
296
|
+
value: "Pepr Ephemeral CA",
|
|
290
297
|
},
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
298
|
+
];
|
|
299
|
+
caCert.setSubject(caAttrs);
|
|
300
|
+
caCert.setIssuer(caAttrs);
|
|
301
|
+
caCert.sign(caKeys.privateKey, forge.md.sha256.create());
|
|
302
|
+
// Generate a new key pair
|
|
303
|
+
const keys = forge.pki.rsa.generateKeyPair(2048);
|
|
304
|
+
const cert = forge.pki.createCertificate();
|
|
305
|
+
cert.publicKey = keys.publicKey;
|
|
306
|
+
cert.serialNumber = "01";
|
|
307
|
+
cert.validity.notBefore = new Date();
|
|
308
|
+
cert.validity.notAfter = new Date();
|
|
309
|
+
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1);
|
|
310
|
+
const attrs = [
|
|
311
|
+
{
|
|
312
|
+
name: "commonName",
|
|
313
|
+
value: `${name}.pepr-system.svc`,
|
|
294
314
|
},
|
|
295
|
-
|
|
315
|
+
];
|
|
316
|
+
cert.setSubject(attrs);
|
|
317
|
+
cert.setIssuer(caCert.subject.attributes);
|
|
318
|
+
cert.sign(caKeys.privateKey, forge.md.sha256.create());
|
|
319
|
+
// Convert the keys and certificates to PEM format
|
|
320
|
+
const ca = Buffer.from(forge.pki.certificateToPem(caCert)).toString("base64");
|
|
321
|
+
const key = Buffer.from(forge.pki.privateKeyToPem(keys.privateKey)).toString("base64");
|
|
322
|
+
const crt = Buffer.from(forge.pki.certificateToPem(cert)).toString("base64");
|
|
323
|
+
return { ca, key, crt };
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
327
|
+
const peprIgnore = {
|
|
328
|
+
key: "pepr.dev",
|
|
329
|
+
operator: "NotIn",
|
|
330
|
+
values: ["ignore"],
|
|
331
|
+
};
|
|
332
|
+
class Webhook {
|
|
333
|
+
constructor(config) {
|
|
334
|
+
this.config = config;
|
|
335
|
+
this.name = `pepr-${config.uuid}`;
|
|
336
|
+
this.image = `ghcr.io/defenseunicorns/pepr-controller:${config.version}`;
|
|
337
|
+
// Generate the ephemeral tls things
|
|
338
|
+
this.tls = genTLS(this.name);
|
|
339
|
+
}
|
|
340
|
+
/** Generate the pepr-system namespace */
|
|
341
|
+
namespace() {
|
|
342
|
+
return {
|
|
343
|
+
apiVersion: "v1",
|
|
344
|
+
kind: "Namespace",
|
|
345
|
+
metadata: { name: "pepr-system" },
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Grants the controller access to cluster resources beyond the mutating webhook.
|
|
350
|
+
*
|
|
351
|
+
* @todo: should dynamically generate this based on resources used by the module. will also need to explore how this should work for multiple modules.
|
|
352
|
+
* @returns
|
|
353
|
+
*/
|
|
354
|
+
clusterRole() {
|
|
355
|
+
return {
|
|
356
|
+
apiVersion: "rbac.authorization.k8s.io/v1",
|
|
357
|
+
kind: "ClusterRole",
|
|
358
|
+
metadata: { name: this.name },
|
|
359
|
+
rules: [
|
|
360
|
+
{
|
|
361
|
+
// @todo: make this configurable
|
|
362
|
+
apiGroups: ["*"],
|
|
363
|
+
resources: ["*"],
|
|
364
|
+
verbs: ["create", "delete", "get", "list", "patch", "update", "watch"],
|
|
365
|
+
},
|
|
366
|
+
],
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
clusterRoleBinding() {
|
|
370
|
+
const name = this.name;
|
|
371
|
+
return {
|
|
372
|
+
apiVersion: "rbac.authorization.k8s.io/v1",
|
|
373
|
+
kind: "ClusterRoleBinding",
|
|
374
|
+
metadata: { name },
|
|
375
|
+
roleRef: {
|
|
376
|
+
apiGroup: "rbac.authorization.k8s.io",
|
|
377
|
+
kind: "ClusterRole",
|
|
378
|
+
name,
|
|
379
|
+
},
|
|
380
|
+
subjects: [
|
|
381
|
+
{
|
|
382
|
+
kind: "ServiceAccount",
|
|
383
|
+
name,
|
|
384
|
+
namespace: "pepr-system",
|
|
385
|
+
},
|
|
386
|
+
],
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
serviceAccount() {
|
|
390
|
+
return {
|
|
391
|
+
apiVersion: "v1",
|
|
392
|
+
kind: "ServiceAccount",
|
|
393
|
+
metadata: {
|
|
394
|
+
name: this.name,
|
|
395
|
+
namespace: "pepr-system",
|
|
396
|
+
},
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
tlsSecret() {
|
|
400
|
+
return {
|
|
401
|
+
apiVersion: "v1",
|
|
402
|
+
kind: "Secret",
|
|
403
|
+
metadata: {
|
|
404
|
+
name: `${this.name}-tls`,
|
|
405
|
+
namespace: "pepr-system",
|
|
406
|
+
},
|
|
407
|
+
type: "kubernetes.io/tls",
|
|
408
|
+
data: {
|
|
409
|
+
"tls.crt": this.tls.crt,
|
|
410
|
+
"tls.key": this.tls.key,
|
|
411
|
+
},
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
mutatingWebhook() {
|
|
415
|
+
const { name } = this;
|
|
416
|
+
const ignore = [peprIgnore];
|
|
417
|
+
// Add any namespaces to ignore
|
|
418
|
+
if (this.config.alwaysIgnore.namespaces.length > 0) {
|
|
419
|
+
ignore.push({
|
|
420
|
+
key: "kubernetes.io/metadata.name",
|
|
421
|
+
operator: "NotIn",
|
|
422
|
+
values: this.config.alwaysIgnore.namespaces,
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
return {
|
|
426
|
+
apiVersion: "admissionregistration.k8s.io/v1",
|
|
427
|
+
kind: "MutatingWebhookConfiguration",
|
|
428
|
+
metadata: { name },
|
|
429
|
+
webhooks: [
|
|
430
|
+
{
|
|
431
|
+
name: `${name}.pepr.dev`,
|
|
432
|
+
admissionReviewVersions: ["v1", "v1beta1"],
|
|
433
|
+
clientConfig: {
|
|
434
|
+
caBundle: this.tls.ca,
|
|
435
|
+
service: {
|
|
436
|
+
name: this.name,
|
|
437
|
+
namespace: "pepr-system",
|
|
438
|
+
path: "/mutate",
|
|
439
|
+
},
|
|
440
|
+
},
|
|
441
|
+
failurePolicy: "Ignore",
|
|
442
|
+
matchPolicy: "Equivalent",
|
|
443
|
+
timeoutSeconds: 15,
|
|
444
|
+
namespaceSelector: {
|
|
445
|
+
matchExpressions: ignore,
|
|
446
|
+
},
|
|
447
|
+
objectSelector: {
|
|
448
|
+
matchExpressions: ignore,
|
|
449
|
+
},
|
|
450
|
+
// @todo: make this configurable
|
|
451
|
+
rules: [
|
|
452
|
+
{
|
|
453
|
+
apiGroups: ["*"],
|
|
454
|
+
apiVersions: ["*"],
|
|
455
|
+
operations: ["CREATE", "UPDATE", "DELETE"],
|
|
456
|
+
resources: ["*"],
|
|
457
|
+
},
|
|
458
|
+
],
|
|
459
|
+
// @todo: track side effects state
|
|
460
|
+
sideEffects: "None",
|
|
461
|
+
},
|
|
462
|
+
],
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
deployment() {
|
|
466
|
+
return {
|
|
467
|
+
apiVersion: "apps/v1",
|
|
468
|
+
kind: "Deployment",
|
|
469
|
+
metadata: {
|
|
470
|
+
name: this.name,
|
|
471
|
+
namespace: "pepr-system",
|
|
472
|
+
labels: {
|
|
473
|
+
app: this.name,
|
|
474
|
+
},
|
|
475
|
+
},
|
|
476
|
+
spec: {
|
|
477
|
+
replicas: 2,
|
|
478
|
+
selector: {
|
|
479
|
+
matchLabels: {
|
|
480
|
+
app: this.name,
|
|
481
|
+
},
|
|
482
|
+
},
|
|
483
|
+
template: {
|
|
484
|
+
metadata: {
|
|
485
|
+
labels: {
|
|
486
|
+
app: this.name,
|
|
487
|
+
},
|
|
488
|
+
},
|
|
489
|
+
spec: {
|
|
490
|
+
priorityClassName: "system-node-critical",
|
|
491
|
+
serviceAccountName: this.name,
|
|
492
|
+
containers: [
|
|
493
|
+
{
|
|
494
|
+
name: "server",
|
|
495
|
+
image: this.image,
|
|
496
|
+
imagePullPolicy: "IfNotPresent",
|
|
497
|
+
livenessProbe: {
|
|
498
|
+
httpGet: {
|
|
499
|
+
path: "/healthz",
|
|
500
|
+
port: 3000,
|
|
501
|
+
scheme: "HTTPS",
|
|
502
|
+
},
|
|
503
|
+
},
|
|
504
|
+
ports: [
|
|
505
|
+
{
|
|
506
|
+
containerPort: 3000,
|
|
507
|
+
},
|
|
508
|
+
],
|
|
509
|
+
resources: {
|
|
510
|
+
requests: {
|
|
511
|
+
memory: "64Mi",
|
|
512
|
+
cpu: "100m",
|
|
513
|
+
},
|
|
514
|
+
limits: {
|
|
515
|
+
memory: "256Mi",
|
|
516
|
+
cpu: "500m",
|
|
517
|
+
},
|
|
518
|
+
},
|
|
519
|
+
volumeMounts: [
|
|
520
|
+
{
|
|
521
|
+
name: "tls-certs",
|
|
522
|
+
mountPath: "/etc/certs",
|
|
523
|
+
readOnly: true,
|
|
524
|
+
},
|
|
525
|
+
],
|
|
526
|
+
},
|
|
527
|
+
],
|
|
528
|
+
volumes: [
|
|
529
|
+
{
|
|
530
|
+
name: "tls-certs",
|
|
531
|
+
secret: {
|
|
532
|
+
secretName: `${this.name}-tls`,
|
|
533
|
+
},
|
|
534
|
+
},
|
|
535
|
+
],
|
|
536
|
+
},
|
|
537
|
+
},
|
|
538
|
+
},
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
service() {
|
|
542
|
+
return {
|
|
543
|
+
apiVersion: "v1",
|
|
544
|
+
kind: "Service",
|
|
545
|
+
metadata: {
|
|
546
|
+
name: this.name,
|
|
547
|
+
namespace: "pepr-system",
|
|
548
|
+
},
|
|
549
|
+
spec: {
|
|
550
|
+
selector: {
|
|
551
|
+
app: this.name,
|
|
552
|
+
},
|
|
553
|
+
ports: [
|
|
554
|
+
{
|
|
555
|
+
port: 443,
|
|
556
|
+
targetPort: 3000,
|
|
557
|
+
},
|
|
558
|
+
],
|
|
559
|
+
},
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
moduleSecret(data) {
|
|
563
|
+
// Compress the data
|
|
564
|
+
const compressed = zlib.gzipSync(data);
|
|
565
|
+
return {
|
|
566
|
+
apiVersion: "v1",
|
|
567
|
+
kind: "Secret",
|
|
568
|
+
metadata: {
|
|
569
|
+
name: `${this.name}-module`,
|
|
570
|
+
namespace: "pepr-system",
|
|
571
|
+
},
|
|
572
|
+
type: "Opaque",
|
|
573
|
+
data: {
|
|
574
|
+
module: compressed.toString("base64"),
|
|
575
|
+
},
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
zarfYaml(path) {
|
|
579
|
+
const zarfCfg = {
|
|
580
|
+
kind: "ZarfPackageConfig",
|
|
581
|
+
metadata: {
|
|
582
|
+
name: this.name,
|
|
583
|
+
description: `Pepr Module: ${this.config.description}`,
|
|
584
|
+
url: "https://github.com/defenseunicorns/pepr",
|
|
585
|
+
version: this.config.version,
|
|
586
|
+
},
|
|
587
|
+
components: [
|
|
588
|
+
{
|
|
589
|
+
name: "module",
|
|
590
|
+
required: true,
|
|
591
|
+
manifests: [
|
|
592
|
+
{
|
|
593
|
+
name: "module",
|
|
594
|
+
namespace: "pepr-system",
|
|
595
|
+
files: [path],
|
|
596
|
+
},
|
|
597
|
+
],
|
|
598
|
+
images: [this.image],
|
|
599
|
+
},
|
|
600
|
+
],
|
|
601
|
+
};
|
|
602
|
+
return clientNode.dumpYaml(zarfCfg, { noRefs: true });
|
|
603
|
+
}
|
|
604
|
+
allYaml(code) {
|
|
605
|
+
const resources = [
|
|
606
|
+
this.namespace(),
|
|
607
|
+
this.clusterRole(),
|
|
608
|
+
this.clusterRoleBinding(),
|
|
609
|
+
this.serviceAccount(),
|
|
610
|
+
this.tlsSecret(),
|
|
611
|
+
this.mutatingWebhook(),
|
|
612
|
+
this.deployment(),
|
|
613
|
+
this.service(),
|
|
614
|
+
this.moduleSecret(code),
|
|
615
|
+
];
|
|
616
|
+
// Convert the resources to a single YAML string
|
|
617
|
+
return resources.map(r => clientNode.dumpYaml(r, { noRefs: true })).join("---\n");
|
|
618
|
+
}
|
|
296
619
|
}
|
|
297
620
|
|
|
298
621
|
// SPDX-License-Identifier: Apache-2.0
|
|
@@ -303,14 +626,21 @@ function build (program) {
|
|
|
303
626
|
.option("-d, --dir [directory]", "Pepr module directory", ".")
|
|
304
627
|
.action(async (opts) => {
|
|
305
628
|
// Build the module
|
|
306
|
-
const { path: path$1, uuid } = await buildModule(opts.dir);
|
|
629
|
+
const { cfg, path: path$1, uuid } = await buildModule(opts.dir);
|
|
307
630
|
// Read the compiled module code
|
|
308
631
|
const code = await fs.promises.readFile(path$1, { encoding: "utf-8" });
|
|
309
632
|
// Generate a secret for the module
|
|
310
|
-
const
|
|
311
|
-
|
|
312
|
-
|
|
633
|
+
const webhook = new Webhook({
|
|
634
|
+
...cfg.pepr,
|
|
635
|
+
description: cfg.description,
|
|
636
|
+
});
|
|
637
|
+
const yamlFile = `pepr-module-${uuid}.yaml`;
|
|
638
|
+
const yamlPath = path.resolve("dist", yamlFile);
|
|
639
|
+
const yaml = webhook.allYaml(code);
|
|
640
|
+
const zarfPath = path.resolve("dist", "zarf.yaml");
|
|
641
|
+
const zarf = webhook.zarfYaml(yamlFile);
|
|
313
642
|
await fs.promises.writeFile(yamlPath, yaml);
|
|
643
|
+
await fs.promises.writeFile(zarfPath, zarf);
|
|
314
644
|
Log.debug(`Module compiled successfully at ${path$1}`);
|
|
315
645
|
Log.info(`K8s resource for the module saved to ${yamlPath}`);
|
|
316
646
|
});
|
|
@@ -320,6 +650,7 @@ const externalLibs = [
|
|
|
320
650
|
"commander",
|
|
321
651
|
"express",
|
|
322
652
|
"fast-json-patch",
|
|
653
|
+
"pepr",
|
|
323
654
|
"ramda",
|
|
324
655
|
];
|
|
325
656
|
async function buildModule(moduleDir) {
|
|
@@ -329,7 +660,8 @@ async function buildModule(moduleDir) {
|
|
|
329
660
|
const input = path.resolve(moduleDir, "pepr.ts");
|
|
330
661
|
// Read the module's UUID from the package.json filel
|
|
331
662
|
const moduleText = await fs.promises.readFile(cfgPath, { encoding: "utf-8" });
|
|
332
|
-
const
|
|
663
|
+
const cfg = JSON.parse(moduleText);
|
|
664
|
+
const { uuid } = cfg.pepr;
|
|
333
665
|
const name = `pepr-${uuid}.js`;
|
|
334
666
|
// Exit if the module's UUID could not be found
|
|
335
667
|
if (!uuid) {
|
|
@@ -363,7 +695,8 @@ async function buildModule(moduleDir) {
|
|
|
363
695
|
});
|
|
364
696
|
return {
|
|
365
697
|
path: path.resolve("dist", name),
|
|
366
|
-
|
|
698
|
+
cfg,
|
|
699
|
+
uuid,
|
|
367
700
|
};
|
|
368
701
|
}
|
|
369
702
|
catch (e) {
|
|
@@ -445,12 +778,7 @@ import cfg from "./package.json";
|
|
|
445
778
|
// import { HelloPepr } from "./capabilities/hello-pepr";
|
|
446
779
|
|
|
447
780
|
// This initializes the Pepr module with the configuration from package.json
|
|
448
|
-
export const { ProcessRequest, Register } = new PeprModule(cfg
|
|
449
|
-
alwaysIgnore: {
|
|
450
|
-
namespaces: [],
|
|
451
|
-
labels: [],
|
|
452
|
-
},
|
|
453
|
-
});
|
|
781
|
+
export const { ProcessRequest, Register } = new PeprModule(cfg);
|
|
454
782
|
|
|
455
783
|
/**
|
|
456
784
|
* Each Pepr Capability is registered with the module using the Register function.
|
|
@@ -490,6 +818,10 @@ function genPkgJSON(opts) {
|
|
|
490
818
|
version,
|
|
491
819
|
uuid: uuid$1,
|
|
492
820
|
onError: opts.errorBehavior,
|
|
821
|
+
alwaysIgnore: {
|
|
822
|
+
namespaces: [],
|
|
823
|
+
labels: [],
|
|
824
|
+
},
|
|
493
825
|
},
|
|
494
826
|
scripts: {
|
|
495
827
|
build: "pepr build",
|
|
@@ -576,72 +908,72 @@ const capabilityHelloPeprTS = {
|
|
|
576
908
|
path: "hello-pepr.ts",
|
|
577
909
|
data: `import { Capability, a } from "pepr";
|
|
578
910
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
},
|
|
616
|
-
annotations: {
|
|
617
|
-
"pepr.dev": "annotations-work-too",
|
|
618
|
-
},
|
|
911
|
+
const { Register, When } = new Capability({
|
|
912
|
+
name: "hello-pepr",
|
|
913
|
+
description: "A simple example capability to show how things work.",
|
|
914
|
+
namespaces: ["pepr-demo"],
|
|
915
|
+
});
|
|
916
|
+
|
|
917
|
+
export { Register as HelloPepr };
|
|
918
|
+
|
|
919
|
+
/**
|
|
920
|
+
* This is a single Capability Action. They can be in the same file or put imported from other files.
|
|
921
|
+
* In this exmaple, when a ConfigMap is created with the name \`example-1\`, then add a label and annotation.
|
|
922
|
+
*
|
|
923
|
+
* Equivelant to manually running:
|
|
924
|
+
* \`kubectl label configmap example-1 pepr=was-here\`
|
|
925
|
+
* \`kubectl annotate configmap example-1 pepr.dev=annotations-work-too\`
|
|
926
|
+
*/
|
|
927
|
+
When(a.ConfigMap)
|
|
928
|
+
.IsCreated()
|
|
929
|
+
.WithName("example-1")
|
|
930
|
+
.Then(request =>
|
|
931
|
+
request
|
|
932
|
+
.SetLabel("pepr", "was-here")
|
|
933
|
+
.SetAnnotation("pepr.dev", "annotations-work-too")
|
|
934
|
+
);
|
|
935
|
+
|
|
936
|
+
/**
|
|
937
|
+
* This Capabiility Action does the exact same changes for example-2, except this time it uses the \`.ThenSet()\` feature.
|
|
938
|
+
* You can stack multiple \`.Then()\` calls, but only a single \`.ThenSet()\`
|
|
939
|
+
*/
|
|
940
|
+
When(a.ConfigMap)
|
|
941
|
+
.IsCreated()
|
|
942
|
+
.WithName("example-2")
|
|
943
|
+
.ThenSet({
|
|
944
|
+
metadata: {
|
|
945
|
+
labels: {
|
|
946
|
+
pepr: "was-here",
|
|
619
947
|
},
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
948
|
+
annotations: {
|
|
949
|
+
"pepr.dev": "annotations-work-too",
|
|
950
|
+
},
|
|
951
|
+
},
|
|
952
|
+
});
|
|
953
|
+
|
|
954
|
+
/**
|
|
955
|
+
* This Capability Action combines different styles. Unlike the previous actions, this one will look for any ConfigMap
|
|
956
|
+
* in the \`pepr-demo\` namespace that has the label \`change=by-label\`. Note that all conditions added such as \`WithName()\`,
|
|
957
|
+
* \`WithLabel()\`, \`InNamespace()\`, are ANDs so all conditions must be true for the request to be procssed.
|
|
958
|
+
*/
|
|
959
|
+
When(a.ConfigMap)
|
|
960
|
+
.IsCreated()
|
|
961
|
+
.WithLabel("change", "by-label")
|
|
962
|
+
.Then(request => {
|
|
963
|
+
// The K8s object e are going to mutate
|
|
964
|
+
const cm = request.Raw;
|
|
965
|
+
|
|
966
|
+
// Get the username and uid of the K8s reuest
|
|
967
|
+
const { username, uid } = request.Request.userInfo;
|
|
968
|
+
|
|
969
|
+
// Store some data about the request in the configmap
|
|
970
|
+
cm.data["username"] = username;
|
|
971
|
+
cm.data["uid"] = uid;
|
|
972
|
+
|
|
973
|
+
// You can still mix other ways of making changes too
|
|
974
|
+
request.SetAnnotation("pepr.dev", "making-waves");
|
|
975
|
+
});
|
|
976
|
+
`,
|
|
645
977
|
};
|
|
646
978
|
const capabilitySnippet = {
|
|
647
979
|
path: "pepr.code-snippets",
|