pepr 0.1.25 → 0.1.27
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 +76 -45
- package/dist/pepr-core.js +93 -33
- package/package.json +1 -2
- package/tsconfig.json +2 -0
- package/CODEOWNERS +0 -6
- package/index.ts +0 -7
- package/src/lib/capability.ts +0 -158
- package/src/lib/filter.ts +0 -55
- package/src/lib/k8s/index.ts +0 -10
- package/src/lib/k8s/kinds.ts +0 -470
- package/src/lib/k8s/tls.ts +0 -90
- package/src/lib/k8s/types.ts +0 -170
- package/src/lib/k8s/upstream.ts +0 -47
- package/src/lib/k8s/webhook.ts +0 -540
- package/src/lib/logger.ts +0 -131
- package/src/lib/module.ts +0 -57
- package/src/lib/processor.ts +0 -83
- package/src/lib/request.ts +0 -140
- package/src/lib/types.ts +0 -211
package/dist/pepr-cli.js
CHANGED
|
@@ -13,12 +13,12 @@ var zlib = require('zlib');
|
|
|
13
13
|
var forge = require('node-forge');
|
|
14
14
|
var prompt = require('prompts');
|
|
15
15
|
var child_process = require('child_process');
|
|
16
|
+
var chokidar = require('chokidar');
|
|
16
17
|
var util = require('util');
|
|
17
18
|
var uuid = require('uuid');
|
|
18
19
|
var commander = require('commander');
|
|
19
|
-
var chokidar = require('chokidar');
|
|
20
20
|
|
|
21
|
-
var version = "0.1.
|
|
21
|
+
var version = "0.1.27";
|
|
22
22
|
|
|
23
23
|
// SPDX-License-Identifier: Apache-2.0
|
|
24
24
|
// SPDX-FileCopyrightText: 2023-Present The Pepr Authors
|
|
@@ -806,9 +806,9 @@ function dev (program) {
|
|
|
806
806
|
process.exit(0);
|
|
807
807
|
}
|
|
808
808
|
// Build the module
|
|
809
|
-
const { cfg, path } = await buildModule(opts.dir);
|
|
809
|
+
const { cfg, path: path$1 } = await buildModule(opts.dir);
|
|
810
810
|
// Read the compiled module code
|
|
811
|
-
const code = await fs.promises.readFile(path, { encoding: "utf-8" });
|
|
811
|
+
const code = await fs.promises.readFile(path$1, { encoding: "utf-8" });
|
|
812
812
|
// Generate a secret for the module
|
|
813
813
|
const webhook = new Webhook({
|
|
814
814
|
...cfg.pepr,
|
|
@@ -820,6 +820,25 @@ function dev (program) {
|
|
|
820
820
|
try {
|
|
821
821
|
await webhook.deploy(code);
|
|
822
822
|
types.logger.info(`Module deployed successfully`);
|
|
823
|
+
const moduleFiles = path.resolve(opts.dir, "**", "*.ts");
|
|
824
|
+
const watcher = chokidar.watch(moduleFiles);
|
|
825
|
+
const peprTS = path.resolve(opts.dir, "pepr.ts");
|
|
826
|
+
let program;
|
|
827
|
+
// Run the module once to start the server
|
|
828
|
+
runDev(peprTS);
|
|
829
|
+
// Watch for changes
|
|
830
|
+
watcher.on("ready", () => {
|
|
831
|
+
types.logger.info(`Watching for changes in ${moduleFiles}`);
|
|
832
|
+
watcher.on("all", async (event, path) => {
|
|
833
|
+
types.logger.debug({ event, path }, "File changed");
|
|
834
|
+
// Kill the running process
|
|
835
|
+
if (program) {
|
|
836
|
+
program.kill("SIGKILL");
|
|
837
|
+
}
|
|
838
|
+
// Start the process again
|
|
839
|
+
program = runDev(peprTS);
|
|
840
|
+
});
|
|
841
|
+
});
|
|
823
842
|
}
|
|
824
843
|
catch (e) {
|
|
825
844
|
types.logger.error(`Error deploying module: ${e}`);
|
|
@@ -827,6 +846,28 @@ function dev (program) {
|
|
|
827
846
|
}
|
|
828
847
|
});
|
|
829
848
|
}
|
|
849
|
+
function runDev(path) {
|
|
850
|
+
try {
|
|
851
|
+
const program = child_process.spawn("./node_modules/.bin/ts-node", [path], {
|
|
852
|
+
env: {
|
|
853
|
+
...process.env,
|
|
854
|
+
SSL_KEY_PATH: "insecure-tls.key",
|
|
855
|
+
SSL_CERT_PATH: "insecure-tls.crt",
|
|
856
|
+
},
|
|
857
|
+
});
|
|
858
|
+
program.stdout.on("data", data => console.log(data.toString()));
|
|
859
|
+
program.stderr.on("data", data => console.error(data.toString()));
|
|
860
|
+
program.on("close", code => {
|
|
861
|
+
types.logger.info(`Process exited with code ${code}`);
|
|
862
|
+
});
|
|
863
|
+
return program;
|
|
864
|
+
}
|
|
865
|
+
catch (e) {
|
|
866
|
+
types.logger.debug(e);
|
|
867
|
+
types.logger.error(`Error running module: ${e}`);
|
|
868
|
+
process.exit(1);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
830
871
|
|
|
831
872
|
// SPDX-License-Identifier: Apache-2.0
|
|
832
873
|
/**
|
|
@@ -883,28 +924,18 @@ function genPeprTS() {
|
|
|
883
924
|
path: "pepr.ts",
|
|
884
925
|
data: `import { PeprModule } from "pepr";
|
|
885
926
|
import cfg from "./package.json";
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
// This initializes the Pepr module with the configuration from package.json
|
|
889
|
-
export const { ProcessRequest, Register } = new PeprModule(cfg);
|
|
927
|
+
import { HelloPepr } from "./capabilities/hello-pepr";
|
|
890
928
|
|
|
891
929
|
/**
|
|
892
|
-
*
|
|
893
|
-
* This
|
|
894
|
-
* \`pepr new <capability name>\`
|
|
895
|
-
*
|
|
896
|
-
* Example:
|
|
897
|
-
* import { Capability1 } from "./capabilities/capability1";
|
|
898
|
-
* import { Capability2 } from "./capabilities/capability2";
|
|
899
|
-
*
|
|
900
|
-
* Capability1(Register);
|
|
901
|
-
* Capability2(Register);
|
|
902
|
-
*
|
|
903
|
-
* Uncomment the line below and the import above to use the hello-pepr demo capability
|
|
930
|
+
* This is the main entrypoint for the Pepr module. It is the file that is run when the module is started.
|
|
931
|
+
* This is where you register your configurations and capabilities with the module.
|
|
904
932
|
*/
|
|
933
|
+
new PeprModule(cfg, [
|
|
934
|
+
// "HelloPepr" is a demo capability that is included with Pepr. You can remove it if you want.
|
|
935
|
+
HelloPepr,
|
|
905
936
|
|
|
906
|
-
//
|
|
907
|
-
|
|
937
|
+
// Your additional capabilities go here
|
|
938
|
+
]);
|
|
908
939
|
`,
|
|
909
940
|
};
|
|
910
941
|
}
|
|
@@ -1009,14 +1040,15 @@ const capabilityHelloPeprTS = {
|
|
|
1009
1040
|
path: "hello-pepr.ts",
|
|
1010
1041
|
data: `import { Capability, a } from "pepr";
|
|
1011
1042
|
|
|
1012
|
-
const
|
|
1043
|
+
export const HelloPepr = new Capability({
|
|
1013
1044
|
name: "hello-pepr",
|
|
1014
1045
|
description: "A simple example capability to show how things work.",
|
|
1015
1046
|
namespaces: ["pepr-demo"],
|
|
1016
1047
|
});
|
|
1017
1048
|
|
|
1018
|
-
|
|
1019
|
-
|
|
1049
|
+
// Use the 'When' function to create a new Capability Action
|
|
1050
|
+
const { When } = HelloPepr;
|
|
1051
|
+
|
|
1020
1052
|
/**
|
|
1021
1053
|
* This is a single Capability Action. They can be in the same file or put imported from other files.
|
|
1022
1054
|
* In this exmaple, when a ConfigMap is created with the name \`example-1\`, then add a label and annotation.
|
|
@@ -1079,27 +1111,26 @@ When(a.ConfigMap)
|
|
|
1079
1111
|
const capabilitySnippet = {
|
|
1080
1112
|
path: "pepr.code-snippets",
|
|
1081
1113
|
data: `{
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
}
|
|
1114
|
+
"Create a new Pepr capability": {
|
|
1115
|
+
"prefix": "create pepr capability",
|
|
1116
|
+
"body": [
|
|
1117
|
+
"import { Capability, a } from 'pepr';",
|
|
1118
|
+
"",
|
|
1119
|
+
"export const $\{TM_FILENAME_BASE/(.*)/$\{1:/pascalcase}/} = new Capability({",
|
|
1120
|
+
"\\tname: '$\{TM_FILENAME_BASE}',",
|
|
1121
|
+
"\\tdescription: '$\{1:A brief description of this capability.}',",
|
|
1122
|
+
"\\tnamespaces: [$\{2:}],",
|
|
1123
|
+
"});",
|
|
1124
|
+
"",
|
|
1125
|
+
"// Use the 'When' function to create a new Capability Action",
|
|
1126
|
+
"const { When } = $\{TM_FILENAME_BASE/(.*)/$\{1:/pascalcase}/};",
|
|
1127
|
+
"",
|
|
1128
|
+
"// When(a.<Kind>).Is<Event>().Then(change => change.<changes>",
|
|
1129
|
+
"When($\{3:})"
|
|
1130
|
+
],
|
|
1131
|
+
"description": "Creates a new Pepr capability with a specified description, and optional namespaces, and adds a When statement for the specified value."
|
|
1101
1132
|
}
|
|
1102
|
-
|
|
1133
|
+
}`,
|
|
1103
1134
|
};
|
|
1104
1135
|
|
|
1105
1136
|
// SPDX-License-Identifier: Apache-2.0
|
package/dist/pepr-core.js
CHANGED
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
var dist = require('@kubernetes/client-node/dist');
|
|
5
5
|
var types = require('./types-1709b44f.js');
|
|
6
6
|
var R = require('ramda');
|
|
7
|
+
var express = require('express');
|
|
8
|
+
var fs = require('fs');
|
|
9
|
+
var https = require('https');
|
|
7
10
|
var fastJsonPatch = require('fast-json-patch');
|
|
8
11
|
|
|
9
12
|
function _interopNamespaceDefault(e) {
|
|
@@ -39,7 +42,6 @@ var upstream = /*#__PURE__*/Object.freeze({
|
|
|
39
42
|
CustomResourceDefinition: dist.V1CustomResourceDefinition,
|
|
40
43
|
DaemonSet: dist.V1DaemonSet,
|
|
41
44
|
Deployment: dist.V1Deployment,
|
|
42
|
-
Endpoint: dist.V1Endpoint,
|
|
43
45
|
EndpointSlice: dist.V1EndpointSlice,
|
|
44
46
|
HorizontalPodAutoscaler: dist.V1HorizontalPodAutoscaler,
|
|
45
47
|
Ingress: dist.V1Ingress,
|
|
@@ -535,13 +537,6 @@ class Capability {
|
|
|
535
537
|
// Currently everything is considered a mutation
|
|
536
538
|
this._mutateOrValidate = types.HookPhase.mutate;
|
|
537
539
|
this._bindings = [];
|
|
538
|
-
/**
|
|
539
|
-
* The Register method is used to register a capability with the Pepr runtime. This method is
|
|
540
|
-
* called in the order that the capabilities should be executed.
|
|
541
|
-
*
|
|
542
|
-
* @param callback the state register method to call, passing the capability as an argument
|
|
543
|
-
*/
|
|
544
|
-
this.Register = (register) => register(this);
|
|
545
540
|
/**
|
|
546
541
|
* The When method is used to register a capability action to be executed when a Kubernetes resource is
|
|
547
542
|
* processed by Pepr. The action will be executed if the resource matches the specified kind and any
|
|
@@ -640,19 +635,16 @@ function shouldSkipRequest(binding, req) {
|
|
|
640
635
|
const { namespaces, labels, annotations } = binding.filters;
|
|
641
636
|
const { metadata } = req.object;
|
|
642
637
|
if (kind !== req.kind.kind) {
|
|
643
|
-
types.logger.debug(`${req.kind.kind} does not match ${kind}`);
|
|
644
638
|
return true;
|
|
645
639
|
}
|
|
646
640
|
if (group && group !== req.kind.group) {
|
|
647
|
-
types.logger.debug(`${req.kind.group} does not match ${group}`);
|
|
648
641
|
return true;
|
|
649
642
|
}
|
|
650
643
|
if (version && version !== req.kind.version) {
|
|
651
|
-
types.logger.debug(`${req.kind.version} does not match ${version}`);
|
|
652
644
|
return true;
|
|
653
645
|
}
|
|
654
646
|
if (namespaces.length && !namespaces.includes(req.namespace || "")) {
|
|
655
|
-
types.logger.debug(
|
|
647
|
+
types.logger.debug("Namespace does not match");
|
|
656
648
|
return true;
|
|
657
649
|
}
|
|
658
650
|
for (const [key, value] of Object.entries(labels)) {
|
|
@@ -848,38 +840,106 @@ function processor(config, capabilities, req) {
|
|
|
848
840
|
return response;
|
|
849
841
|
}
|
|
850
842
|
|
|
843
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
844
|
+
// Load SSL certificate and key
|
|
845
|
+
const options = {
|
|
846
|
+
key: fs.readFileSync(process.env.SSL_KEY_PATH || "/etc/certs/tls.key"),
|
|
847
|
+
cert: fs.readFileSync(process.env.SSL_CERT_PATH || "/etc/certs/tls.crt"),
|
|
848
|
+
};
|
|
849
|
+
class Controller {
|
|
850
|
+
constructor(config, capabilities) {
|
|
851
|
+
this.config = config;
|
|
852
|
+
this.capabilities = capabilities;
|
|
853
|
+
this.app = express();
|
|
854
|
+
/** Start the webhook server */
|
|
855
|
+
this.startServer = (port) => {
|
|
856
|
+
// Create HTTPS server
|
|
857
|
+
https.createServer(options, this.app).listen(port, () => {
|
|
858
|
+
console.log(`Server listening on port ${port}`);
|
|
859
|
+
});
|
|
860
|
+
};
|
|
861
|
+
this.logger = (req, res, next) => {
|
|
862
|
+
const startTime = Date.now();
|
|
863
|
+
res.on("finish", () => {
|
|
864
|
+
const now = new Date().toISOString();
|
|
865
|
+
const elapsedTime = Date.now() - startTime;
|
|
866
|
+
const message = `[${now}] ${req.method} ${req.originalUrl} - ${res.statusCode} - ${elapsedTime} ms\n`;
|
|
867
|
+
res.statusCode >= 400 ? console.error(message) : console.info(message);
|
|
868
|
+
});
|
|
869
|
+
next();
|
|
870
|
+
};
|
|
871
|
+
this.healthz = (req, res) => {
|
|
872
|
+
try {
|
|
873
|
+
res.send("OK");
|
|
874
|
+
}
|
|
875
|
+
catch (err) {
|
|
876
|
+
console.error(err);
|
|
877
|
+
res.status(500).send("Internal Server Error");
|
|
878
|
+
}
|
|
879
|
+
};
|
|
880
|
+
this.mutate = (req, res) => {
|
|
881
|
+
try {
|
|
882
|
+
const name = req.body?.request?.name || "";
|
|
883
|
+
const namespace = req.body?.request?.namespace || "";
|
|
884
|
+
const gvk = req.body?.request?.kind || { group: "", version: "", kind: "" };
|
|
885
|
+
console.log(`Mutate request: ${gvk.group}/${gvk.version}/${gvk.kind}`);
|
|
886
|
+
name && console.log(` ${namespace}/${name}\n`);
|
|
887
|
+
// @todo: make this actually do something
|
|
888
|
+
const response = processor(this.config, this.capabilities, req.body.request);
|
|
889
|
+
console.debug(response);
|
|
890
|
+
// Send a no prob bob response
|
|
891
|
+
res.send({
|
|
892
|
+
apiVersion: "admission.k8s.io/v1",
|
|
893
|
+
kind: "AdmissionReview",
|
|
894
|
+
response: {
|
|
895
|
+
uid: req.body.request.uid,
|
|
896
|
+
allowed: true,
|
|
897
|
+
},
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
catch (err) {
|
|
901
|
+
console.error(err);
|
|
902
|
+
res.status(500).send("Internal Server Error");
|
|
903
|
+
}
|
|
904
|
+
};
|
|
905
|
+
// Middleware for logging requests
|
|
906
|
+
this.app.use(this.logger);
|
|
907
|
+
// Middleware for parsing JSON
|
|
908
|
+
this.app.use(express.json());
|
|
909
|
+
// Health check endpoint
|
|
910
|
+
this.app.get("/healthz", this.healthz);
|
|
911
|
+
// Mutate endpoint
|
|
912
|
+
this.app.post("/mutate", this.mutate);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
|
|
851
916
|
// SPDX-License-Identifier: Apache-2.0
|
|
852
917
|
const alwaysIgnore = {
|
|
853
918
|
namespaces: ["kube-system", "pepr-system"],
|
|
854
919
|
labels: [{ "pepr.dev": "ignore" }],
|
|
855
920
|
};
|
|
856
921
|
class PeprModule {
|
|
857
|
-
get kinds() {
|
|
858
|
-
return this._kinds;
|
|
859
|
-
}
|
|
860
|
-
get UUID() {
|
|
861
|
-
return this._config.uuid;
|
|
862
|
-
}
|
|
863
922
|
/**
|
|
864
923
|
* Create a new Pepr runtime
|
|
865
924
|
*
|
|
866
925
|
* @param config The configuration for the Pepr runtime
|
|
867
926
|
*/
|
|
868
|
-
constructor({ description, pepr }) {
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
this.
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
927
|
+
constructor({ description, pepr }, capabilities = [], deferStart = false) {
|
|
928
|
+
const config = R.mergeDeepWith(R.concat, pepr, alwaysIgnore);
|
|
929
|
+
config.description = description;
|
|
930
|
+
this._controller = new Controller(config, capabilities);
|
|
931
|
+
if (!deferStart) {
|
|
932
|
+
this.start();
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
/**
|
|
936
|
+
* Start the Pepr runtime manually.
|
|
937
|
+
* Normally this is called automatically when the Pepr module is instantiated, but can be called manually if `deferStart` is set to `true` in the constructor.
|
|
938
|
+
*
|
|
939
|
+
* @param port
|
|
940
|
+
*/
|
|
941
|
+
start(port = 3000) {
|
|
942
|
+
this._controller.startServer(port);
|
|
883
943
|
}
|
|
884
944
|
}
|
|
885
945
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pepr",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.27",
|
|
4
4
|
"description": "Kubernetes application engine",
|
|
5
5
|
"author": "Defense Unicorns",
|
|
6
6
|
"homepage": "https://github.com/defenseunicorns/pepr",
|
|
@@ -41,7 +41,6 @@
|
|
|
41
41
|
"@rollup/plugin-node-resolve": "^15.0.1",
|
|
42
42
|
"@rollup/plugin-typescript": "^11.0.0",
|
|
43
43
|
"@types/ramda": "^0.28.23",
|
|
44
|
-
"body-parser": "^1.20.2",
|
|
45
44
|
"chokidar": "^3.5.3",
|
|
46
45
|
"commander": "^10.0.0",
|
|
47
46
|
"express": "^4.18.2",
|
package/tsconfig.json
CHANGED
package/CODEOWNERS
DELETED
package/index.ts
DELETED
package/src/lib/capability.ts
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// SPDX-FileCopyrightText: 2023-Present The Pepr Authors
|
|
3
|
-
|
|
4
|
-
import { modelToGroupVersionKind } from "./k8s";
|
|
5
|
-
import logger from "./logger";
|
|
6
|
-
import {
|
|
7
|
-
BindToAction,
|
|
8
|
-
Binding,
|
|
9
|
-
BindingFilter,
|
|
10
|
-
BindingWithName,
|
|
11
|
-
CapabilityAction,
|
|
12
|
-
CapabilityCfg,
|
|
13
|
-
DeepPartial,
|
|
14
|
-
Event,
|
|
15
|
-
GenericClass,
|
|
16
|
-
HookPhase,
|
|
17
|
-
WhenSelector,
|
|
18
|
-
} from "./types";
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* A capability is a unit of functionality that can be registered with the Pepr runtime.
|
|
22
|
-
*/
|
|
23
|
-
export class Capability implements CapabilityCfg {
|
|
24
|
-
private _name: string;
|
|
25
|
-
private _description: string;
|
|
26
|
-
private _namespaces?: string[] | undefined;
|
|
27
|
-
|
|
28
|
-
// Currently everything is considered a mutation
|
|
29
|
-
private _mutateOrValidate = HookPhase.mutate;
|
|
30
|
-
|
|
31
|
-
private _bindings: Binding[] = [];
|
|
32
|
-
|
|
33
|
-
get bindings(): Binding[] {
|
|
34
|
-
return this._bindings;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
get name() {
|
|
38
|
-
return this._name;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
get description() {
|
|
42
|
-
return this._description;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
get namespaces() {
|
|
46
|
-
return this._namespaces || [];
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
get mutateOrValidate() {
|
|
50
|
-
return this._mutateOrValidate;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
constructor(cfg: CapabilityCfg) {
|
|
54
|
-
this._name = cfg.name;
|
|
55
|
-
this._description = cfg.description;
|
|
56
|
-
this._namespaces = cfg.namespaces;
|
|
57
|
-
logger.info(`Capability ${this._name} registered`);
|
|
58
|
-
logger.debug(cfg);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* The Register method is used to register a capability with the Pepr runtime. This method is
|
|
63
|
-
* called in the order that the capabilities should be executed.
|
|
64
|
-
*
|
|
65
|
-
* @param callback the state register method to call, passing the capability as an argument
|
|
66
|
-
*/
|
|
67
|
-
Register = (register: (capability: Capability) => void) => register(this);
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* The When method is used to register a capability action to be executed when a Kubernetes resource is
|
|
71
|
-
* processed by Pepr. The action will be executed if the resource matches the specified kind and any
|
|
72
|
-
* filters that are applied.
|
|
73
|
-
*
|
|
74
|
-
* @param model if using a custom KubernetesObject not available in `a.*`, specify the GroupVersionKind
|
|
75
|
-
* @returns
|
|
76
|
-
*/
|
|
77
|
-
When = <T extends GenericClass>(model: T): WhenSelector<T> => {
|
|
78
|
-
const binding: Binding = {
|
|
79
|
-
// If the kind is not specified, use the default KubernetesObject
|
|
80
|
-
kind: modelToGroupVersionKind(model.name),
|
|
81
|
-
filters: {
|
|
82
|
-
name: "",
|
|
83
|
-
namespaces: [],
|
|
84
|
-
labels: {},
|
|
85
|
-
annotations: {},
|
|
86
|
-
},
|
|
87
|
-
callback: () => null,
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const prefix = `${this._name}: ${model.name}`;
|
|
91
|
-
|
|
92
|
-
logger.info(`Binding created`, prefix);
|
|
93
|
-
|
|
94
|
-
const Then = (cb: CapabilityAction<T>): BindToAction<T> => {
|
|
95
|
-
logger.info(`Binding action created`, prefix);
|
|
96
|
-
logger.debug(cb.toString(), prefix);
|
|
97
|
-
// Push the binding to the list of bindings for this capability as a new BindingAction
|
|
98
|
-
// with the callback function to preserve
|
|
99
|
-
this._bindings.push({
|
|
100
|
-
...binding,
|
|
101
|
-
callback: cb,
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
// Now only allow adding actions to the same binding
|
|
105
|
-
return { Then };
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
const ThenSet = (merge: DeepPartial<InstanceType<T>>): BindToAction<T> => {
|
|
109
|
-
// Add the new action to the binding
|
|
110
|
-
Then(req => req.Merge(merge));
|
|
111
|
-
|
|
112
|
-
return { Then };
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
function InNamespace(...namespaces: string[]): BindingWithName<T> {
|
|
116
|
-
logger.debug(`Add namespaces filter ${namespaces}`, prefix);
|
|
117
|
-
binding.filters.namespaces.push(...namespaces);
|
|
118
|
-
return { WithLabel, WithAnnotation, WithName, Then, ThenSet };
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function WithName(name: string): BindingFilter<T> {
|
|
122
|
-
logger.debug(`Add name filter ${name}`, prefix);
|
|
123
|
-
binding.filters.name = name;
|
|
124
|
-
return { WithLabel, WithAnnotation, Then, ThenSet };
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function WithLabel(key: string, value = ""): BindingFilter<T> {
|
|
128
|
-
logger.debug(`Add label filter ${key}=${value}`, prefix);
|
|
129
|
-
binding.filters.labels[key] = value;
|
|
130
|
-
return { WithLabel, WithAnnotation, Then, ThenSet };
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const WithAnnotation = (key: string, value = ""): BindingFilter<T> => {
|
|
134
|
-
logger.debug(`Add annotation filter ${key}=${value}`, prefix);
|
|
135
|
-
binding.filters.annotations[key] = value;
|
|
136
|
-
return { WithLabel, WithAnnotation, Then, ThenSet };
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
const bindEvent = (event: Event) => {
|
|
140
|
-
binding.event = event;
|
|
141
|
-
return {
|
|
142
|
-
InNamespace,
|
|
143
|
-
Then,
|
|
144
|
-
ThenSet,
|
|
145
|
-
WithAnnotation,
|
|
146
|
-
WithLabel,
|
|
147
|
-
WithName,
|
|
148
|
-
};
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
return {
|
|
152
|
-
IsCreatedOrUpdated: () => bindEvent(Event.CreateOrUpdate),
|
|
153
|
-
IsCreated: () => bindEvent(Event.Create),
|
|
154
|
-
IsUpdated: () => bindEvent(Event.Update),
|
|
155
|
-
IsDeleted: () => bindEvent(Event.Delete),
|
|
156
|
-
};
|
|
157
|
-
};
|
|
158
|
-
}
|
package/src/lib/filter.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// SPDX-FileCopyrightText: 2023-Present The Pepr Authors
|
|
3
|
-
|
|
4
|
-
import { Request } from "./k8s";
|
|
5
|
-
import logger from "./logger";
|
|
6
|
-
import { Binding } from "./types";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* shouldSkipRequest determines if a request should be skipped based on the binding filters.
|
|
10
|
-
*
|
|
11
|
-
* @param binding the capability action binding
|
|
12
|
-
* @param req the incoming request
|
|
13
|
-
* @returns
|
|
14
|
-
*/
|
|
15
|
-
export function shouldSkipRequest(binding: Binding, req: Request) {
|
|
16
|
-
const { group, kind, version } = binding.kind;
|
|
17
|
-
const { namespaces, labels, annotations } = binding.filters;
|
|
18
|
-
const { metadata } = req.object;
|
|
19
|
-
|
|
20
|
-
if (kind !== req.kind.kind) {
|
|
21
|
-
logger.debug(`${req.kind.kind} does not match ${kind}`);
|
|
22
|
-
return true;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (group && group !== req.kind.group) {
|
|
26
|
-
logger.debug(`${req.kind.group} does not match ${group}`);
|
|
27
|
-
return true;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (version && version !== req.kind.version) {
|
|
31
|
-
logger.debug(`${req.kind.version} does not match ${version}`);
|
|
32
|
-
return true;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (namespaces.length && !namespaces.includes(req.namespace || "")) {
|
|
36
|
-
logger.debug(`${req.namespace} is not in ${namespaces}`);
|
|
37
|
-
return true;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
for (const [key, value] of Object.entries(labels)) {
|
|
41
|
-
if (metadata?.labels?.[key] !== value) {
|
|
42
|
-
logger.debug(`${metadata?.labels?.[key]} does not match ${value}`);
|
|
43
|
-
return true;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
for (const [key, value] of Object.entries(annotations)) {
|
|
48
|
-
if (metadata?.annotations?.[key] !== value) {
|
|
49
|
-
logger.debug(`${metadata?.annotations?.[key]} does not match ${value}`);
|
|
50
|
-
return true;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return false;
|
|
55
|
-
}
|
package/src/lib/k8s/index.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// SPDX-FileCopyrightText: 2023-Present The Pepr Authors
|
|
3
|
-
|
|
4
|
-
// Export kinds as a single object
|
|
5
|
-
import * as kind from "./upstream";
|
|
6
|
-
export { kind as a };
|
|
7
|
-
|
|
8
|
-
export { modelToGroupVersionKind, gvkMap } from "./kinds";
|
|
9
|
-
|
|
10
|
-
export * from "./types";
|