pepr 0.1.26 → 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 +4 -4
- package/dist/pepr-core.js +0 -1
- package/package.json +1 -1
- package/tsconfig.json +2 -0
- package/CODEOWNERS +0 -6
- package/index.ts +0 -7
- package/src/lib/capability.ts +0 -150
- package/src/lib/controller.ts +0 -92
- package/src/lib/filter.ts +0 -52
- 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 -47
- 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
|
@@ -18,7 +18,7 @@ var util = require('util');
|
|
|
18
18
|
var uuid = require('uuid');
|
|
19
19
|
var commander = require('commander');
|
|
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
|
|
@@ -1117,9 +1117,9 @@ const capabilitySnippet = {
|
|
|
1117
1117
|
"import { Capability, a } from 'pepr';",
|
|
1118
1118
|
"",
|
|
1119
1119
|
"export const $\{TM_FILENAME_BASE/(.*)/$\{1:/pascalcase}/} = new Capability({",
|
|
1120
|
-
"
|
|
1121
|
-
"
|
|
1122
|
-
"
|
|
1120
|
+
"\\tname: '$\{TM_FILENAME_BASE}',",
|
|
1121
|
+
"\\tdescription: '$\{1:A brief description of this capability.}',",
|
|
1122
|
+
"\\tnamespaces: [$\{2:}],",
|
|
1123
1123
|
"});",
|
|
1124
1124
|
"",
|
|
1125
1125
|
"// Use the 'When' function to create a new Capability Action",
|
package/dist/pepr-core.js
CHANGED
|
@@ -42,7 +42,6 @@ var upstream = /*#__PURE__*/Object.freeze({
|
|
|
42
42
|
CustomResourceDefinition: dist.V1CustomResourceDefinition,
|
|
43
43
|
DaemonSet: dist.V1DaemonSet,
|
|
44
44
|
Deployment: dist.V1Deployment,
|
|
45
|
-
Endpoint: dist.V1Endpoint,
|
|
46
45
|
EndpointSlice: dist.V1EndpointSlice,
|
|
47
46
|
HorizontalPodAutoscaler: dist.V1HorizontalPodAutoscaler,
|
|
48
47
|
Ingress: dist.V1Ingress,
|
package/package.json
CHANGED
package/tsconfig.json
CHANGED
package/CODEOWNERS
DELETED
package/index.ts
DELETED
package/src/lib/capability.ts
DELETED
|
@@ -1,150 +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 When method is used to register a capability action to be executed when a Kubernetes resource is
|
|
63
|
-
* processed by Pepr. The action will be executed if the resource matches the specified kind and any
|
|
64
|
-
* filters that are applied.
|
|
65
|
-
*
|
|
66
|
-
* @param model if using a custom KubernetesObject not available in `a.*`, specify the GroupVersionKind
|
|
67
|
-
* @returns
|
|
68
|
-
*/
|
|
69
|
-
When = <T extends GenericClass>(model: T): WhenSelector<T> => {
|
|
70
|
-
const binding: Binding = {
|
|
71
|
-
// If the kind is not specified, use the default KubernetesObject
|
|
72
|
-
kind: modelToGroupVersionKind(model.name),
|
|
73
|
-
filters: {
|
|
74
|
-
name: "",
|
|
75
|
-
namespaces: [],
|
|
76
|
-
labels: {},
|
|
77
|
-
annotations: {},
|
|
78
|
-
},
|
|
79
|
-
callback: () => null,
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
const prefix = `${this._name}: ${model.name}`;
|
|
83
|
-
|
|
84
|
-
logger.info(`Binding created`, prefix);
|
|
85
|
-
|
|
86
|
-
const Then = (cb: CapabilityAction<T>): BindToAction<T> => {
|
|
87
|
-
logger.info(`Binding action created`, prefix);
|
|
88
|
-
logger.debug(cb.toString(), prefix);
|
|
89
|
-
// Push the binding to the list of bindings for this capability as a new BindingAction
|
|
90
|
-
// with the callback function to preserve
|
|
91
|
-
this._bindings.push({
|
|
92
|
-
...binding,
|
|
93
|
-
callback: cb,
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
// Now only allow adding actions to the same binding
|
|
97
|
-
return { Then };
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const ThenSet = (merge: DeepPartial<InstanceType<T>>): BindToAction<T> => {
|
|
101
|
-
// Add the new action to the binding
|
|
102
|
-
Then(req => req.Merge(merge));
|
|
103
|
-
|
|
104
|
-
return { Then };
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
function InNamespace(...namespaces: string[]): BindingWithName<T> {
|
|
108
|
-
logger.debug(`Add namespaces filter ${namespaces}`, prefix);
|
|
109
|
-
binding.filters.namespaces.push(...namespaces);
|
|
110
|
-
return { WithLabel, WithAnnotation, WithName, Then, ThenSet };
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function WithName(name: string): BindingFilter<T> {
|
|
114
|
-
logger.debug(`Add name filter ${name}`, prefix);
|
|
115
|
-
binding.filters.name = name;
|
|
116
|
-
return { WithLabel, WithAnnotation, Then, ThenSet };
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function WithLabel(key: string, value = ""): BindingFilter<T> {
|
|
120
|
-
logger.debug(`Add label filter ${key}=${value}`, prefix);
|
|
121
|
-
binding.filters.labels[key] = value;
|
|
122
|
-
return { WithLabel, WithAnnotation, Then, ThenSet };
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const WithAnnotation = (key: string, value = ""): BindingFilter<T> => {
|
|
126
|
-
logger.debug(`Add annotation filter ${key}=${value}`, prefix);
|
|
127
|
-
binding.filters.annotations[key] = value;
|
|
128
|
-
return { WithLabel, WithAnnotation, Then, ThenSet };
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
const bindEvent = (event: Event) => {
|
|
132
|
-
binding.event = event;
|
|
133
|
-
return {
|
|
134
|
-
InNamespace,
|
|
135
|
-
Then,
|
|
136
|
-
ThenSet,
|
|
137
|
-
WithAnnotation,
|
|
138
|
-
WithLabel,
|
|
139
|
-
WithName,
|
|
140
|
-
};
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
return {
|
|
144
|
-
IsCreatedOrUpdated: () => bindEvent(Event.CreateOrUpdate),
|
|
145
|
-
IsCreated: () => bindEvent(Event.Create),
|
|
146
|
-
IsUpdated: () => bindEvent(Event.Update),
|
|
147
|
-
IsDeleted: () => bindEvent(Event.Delete),
|
|
148
|
-
};
|
|
149
|
-
};
|
|
150
|
-
}
|
package/src/lib/controller.ts
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// SPDX-FileCopyrightText: 2023-Present The Pepr Authors
|
|
3
|
-
|
|
4
|
-
import express from "express";
|
|
5
|
-
import fs from "fs";
|
|
6
|
-
import https from "https";
|
|
7
|
-
import { ModuleConfig } from "./types";
|
|
8
|
-
import { Capability } from "./capability";
|
|
9
|
-
import { processor } from "./processor";
|
|
10
|
-
|
|
11
|
-
// Load SSL certificate and key
|
|
12
|
-
const options = {
|
|
13
|
-
key: fs.readFileSync(process.env.SSL_KEY_PATH || "/etc/certs/tls.key"),
|
|
14
|
-
cert: fs.readFileSync(process.env.SSL_CERT_PATH || "/etc/certs/tls.crt"),
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export class Controller {
|
|
18
|
-
private readonly app = express();
|
|
19
|
-
|
|
20
|
-
constructor(private readonly config: ModuleConfig, private readonly capabilities: Capability[]) {
|
|
21
|
-
// Middleware for logging requests
|
|
22
|
-
this.app.use(this.logger);
|
|
23
|
-
|
|
24
|
-
// Middleware for parsing JSON
|
|
25
|
-
this.app.use(express.json());
|
|
26
|
-
|
|
27
|
-
// Health check endpoint
|
|
28
|
-
this.app.get("/healthz", this.healthz);
|
|
29
|
-
|
|
30
|
-
// Mutate endpoint
|
|
31
|
-
this.app.post("/mutate", this.mutate);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/** Start the webhook server */
|
|
35
|
-
public startServer = (port: number) => {
|
|
36
|
-
// Create HTTPS server
|
|
37
|
-
https.createServer(options, this.app).listen(port, () => {
|
|
38
|
-
console.log(`Server listening on port ${port}`);
|
|
39
|
-
});
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
private logger = (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
|
43
|
-
const startTime = Date.now();
|
|
44
|
-
|
|
45
|
-
res.on("finish", () => {
|
|
46
|
-
const now = new Date().toISOString();
|
|
47
|
-
const elapsedTime = Date.now() - startTime;
|
|
48
|
-
const message = `[${now}] ${req.method} ${req.originalUrl} - ${res.statusCode} - ${elapsedTime} ms\n`;
|
|
49
|
-
|
|
50
|
-
res.statusCode >= 400 ? console.error(message) : console.info(message);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
next();
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
private healthz = (req: express.Request, res: express.Response) => {
|
|
57
|
-
try {
|
|
58
|
-
res.send("OK");
|
|
59
|
-
} catch (err) {
|
|
60
|
-
console.error(err);
|
|
61
|
-
res.status(500).send("Internal Server Error");
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
private mutate = (req: express.Request, res: express.Response) => {
|
|
66
|
-
try {
|
|
67
|
-
const name = req.body?.request?.name || "";
|
|
68
|
-
const namespace = req.body?.request?.namespace || "";
|
|
69
|
-
const gvk = req.body?.request?.kind || { group: "", version: "", kind: "" };
|
|
70
|
-
|
|
71
|
-
console.log(`Mutate request: ${gvk.group}/${gvk.version}/${gvk.kind}`);
|
|
72
|
-
name && console.log(` ${namespace}/${name}\n`);
|
|
73
|
-
|
|
74
|
-
// @todo: make this actually do something
|
|
75
|
-
const response = processor(this.config, this.capabilities, req.body.request);
|
|
76
|
-
console.debug(response);
|
|
77
|
-
|
|
78
|
-
// Send a no prob bob response
|
|
79
|
-
res.send({
|
|
80
|
-
apiVersion: "admission.k8s.io/v1",
|
|
81
|
-
kind: "AdmissionReview",
|
|
82
|
-
response: {
|
|
83
|
-
uid: req.body.request.uid,
|
|
84
|
-
allowed: true,
|
|
85
|
-
},
|
|
86
|
-
});
|
|
87
|
-
} catch (err) {
|
|
88
|
-
console.error(err);
|
|
89
|
-
res.status(500).send("Internal Server Error");
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
}
|
package/src/lib/filter.ts
DELETED
|
@@ -1,52 +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
|
-
return true;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (group && group !== req.kind.group) {
|
|
25
|
-
return true;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (version && version !== req.kind.version) {
|
|
29
|
-
return true;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (namespaces.length && !namespaces.includes(req.namespace || "")) {
|
|
33
|
-
logger.debug("Namespace does not match");
|
|
34
|
-
return true;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
for (const [key, value] of Object.entries(labels)) {
|
|
38
|
-
if (metadata?.labels?.[key] !== value) {
|
|
39
|
-
logger.debug(`${metadata?.labels?.[key]} does not match ${value}`);
|
|
40
|
-
return true;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
for (const [key, value] of Object.entries(annotations)) {
|
|
45
|
-
if (metadata?.annotations?.[key] !== value) {
|
|
46
|
-
logger.debug(`${metadata?.annotations?.[key]} does not match ${value}`);
|
|
47
|
-
return true;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return false;
|
|
52
|
-
}
|
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";
|