pepr 0.2.10 → 0.3.0-rc0
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/fixtures/data/cm1.json +75 -0
- package/dist/fixtures/data/deployment1.json +170 -0
- package/dist/fixtures/data/ns1.json +72 -0
- package/dist/fixtures/data/pod1.json +271 -0
- package/dist/fixtures/data/pod2.json +257 -0
- package/dist/fixtures/data/svc1.json +100 -0
- package/dist/fixtures/loader.js +60 -0
- package/dist/package.json +21 -39
- package/dist/src/cli/build.js +3 -1
- package/dist/src/cli/dev.js +31 -19
- package/dist/src/cli/index.js +1 -0
- package/dist/src/cli/init/index.js +3 -1
- package/dist/src/cli/init/templates.js +3 -2
- package/dist/src/cli/init/utils.js +1 -1
- package/dist/src/cli/init/utils.test.js +29 -0
- package/dist/src/cli/init/walkthrough.js +1 -1
- package/dist/src/cli/init/walkthrough.test.js +21 -0
- package/dist/src/cli/run.js +17 -17
- package/dist/src/cli/update.js +3 -1
- package/dist/src/lib/capability.js +1 -1
- package/dist/src/lib/controller.js +9 -1
- package/dist/src/lib/fetch.js +39 -6
- package/dist/src/lib/fetch.test.js +98 -0
- package/dist/src/lib/filter.test.js +208 -0
- package/dist/src/lib/k8s/kinds.test.js +296 -0
- package/dist/src/lib/k8s/webhook.js +22 -22
- package/dist/src/lib/logger.test.js +64 -0
- package/dist/src/lib/processor.js +4 -1
- package/{dist/index.d.ts → index.ts} +21 -3
- package/package.json +21 -39
- package/src/lib/capability.ts +158 -0
- package/src/lib/controller.ts +127 -0
- package/src/lib/fetch.test.ts +115 -0
- package/src/lib/fetch.ts +75 -0
- package/src/lib/filter.test.ts +231 -0
- package/src/lib/filter.ts +87 -0
- package/{dist/src/lib/k8s/index.d.ts → src/lib/k8s/index.ts} +6 -0
- package/src/lib/k8s/kinds.test.ts +333 -0
- package/src/lib/k8s/kinds.ts +489 -0
- package/src/lib/k8s/tls.ts +90 -0
- package/src/lib/k8s/types.ts +183 -0
- package/src/lib/k8s/upstream.ts +49 -0
- package/src/lib/k8s/webhook.ts +547 -0
- package/src/lib/logger.test.ts +80 -0
- package/src/lib/logger.ts +136 -0
- package/src/lib/module.ts +63 -0
- package/src/lib/processor.ts +98 -0
- package/src/lib/request.ts +140 -0
- package/src/lib/types.ts +211 -0
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +0 -4
- package/dist/run.d.ts +0 -2
- package/dist/run.js +0 -4
- package/dist/src/cli/banner.d.ts +0 -1
- package/dist/src/cli/build.d.ts +0 -7
- package/dist/src/cli/capability.d.ts +0 -2
- package/dist/src/cli/deploy.d.ts +0 -2
- package/dist/src/cli/dev.d.ts +0 -2
- package/dist/src/cli/index.d.ts +0 -1
- package/dist/src/cli/init/index.d.ts +0 -2
- package/dist/src/cli/init/templates.d.ts +0 -94
- package/dist/src/cli/init/utils.d.ts +0 -20
- package/dist/src/cli/init/walkthrough.d.ts +0 -7
- package/dist/src/cli/root.d.ts +0 -4
- package/dist/src/cli/run.d.ts +0 -1
- package/dist/src/cli/test.d.ts +0 -2
- package/dist/src/cli/update.d.ts +0 -2
- package/dist/src/lib/capability.d.ts +0 -28
- package/dist/src/lib/controller.d.ts +0 -17
- package/dist/src/lib/fetch.d.ts +0 -23
- package/dist/src/lib/filter.d.ts +0 -10
- package/dist/src/lib/k8s/kinds.d.ts +0 -11
- package/dist/src/lib/k8s/tls.d.ts +0 -17
- package/dist/src/lib/k8s/types.d.ts +0 -147
- package/dist/src/lib/k8s/upstream.d.ts +0 -3
- package/dist/src/lib/k8s/webhook.d.ts +0 -34
- package/dist/src/lib/logger.d.ts +0 -55
- package/dist/src/lib/module.d.ts +0 -32
- package/dist/src/lib/processor.d.ts +0 -4
- package/dist/src/lib/request.d.ts +0 -77
- package/dist/src/lib/types.d.ts +0 -187
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// SPDX-FileCopyrightText: 2023-Present The Pepr Authors
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
AdmissionregistrationV1Api,
|
|
6
|
+
AdmissionregistrationV1WebhookClientConfig,
|
|
7
|
+
AppsV1Api,
|
|
8
|
+
CoreV1Api,
|
|
9
|
+
HttpError,
|
|
10
|
+
KubeConfig,
|
|
11
|
+
NetworkingV1Api,
|
|
12
|
+
RbacAuthorizationV1Api,
|
|
13
|
+
V1ClusterRole,
|
|
14
|
+
V1ClusterRoleBinding,
|
|
15
|
+
V1Deployment,
|
|
16
|
+
V1LabelSelectorRequirement,
|
|
17
|
+
V1MutatingWebhookConfiguration,
|
|
18
|
+
V1Namespace,
|
|
19
|
+
V1NetworkPolicy,
|
|
20
|
+
V1Secret,
|
|
21
|
+
V1Service,
|
|
22
|
+
V1ServiceAccount,
|
|
23
|
+
dumpYaml,
|
|
24
|
+
} from "@kubernetes/client-node";
|
|
25
|
+
import crypto from "crypto";
|
|
26
|
+
import { gzipSync } from "zlib";
|
|
27
|
+
import Log from "../logger";
|
|
28
|
+
import { ModuleConfig } from "../types";
|
|
29
|
+
import { TLSOut, genTLS } from "./tls";
|
|
30
|
+
|
|
31
|
+
const peprIgnore: V1LabelSelectorRequirement = {
|
|
32
|
+
key: "pepr.dev",
|
|
33
|
+
operator: "NotIn",
|
|
34
|
+
values: ["ignore"],
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export class Webhook {
|
|
38
|
+
private name: string;
|
|
39
|
+
private _tls: TLSOut;
|
|
40
|
+
|
|
41
|
+
public image: string;
|
|
42
|
+
|
|
43
|
+
public get tls(): TLSOut {
|
|
44
|
+
return this._tls;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
constructor(private readonly config: ModuleConfig, private readonly host?: string) {
|
|
48
|
+
this.name = `pepr-${config.uuid}`;
|
|
49
|
+
|
|
50
|
+
this.image = `ghcr.io/defenseunicorns/pepr/controller:v${config.version}`;
|
|
51
|
+
|
|
52
|
+
// Generate the ephemeral tls things
|
|
53
|
+
this._tls = genTLS(this.host || `${this.name}.pepr-system.svc`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Generate the pepr-system namespace */
|
|
57
|
+
namespace(): V1Namespace {
|
|
58
|
+
return {
|
|
59
|
+
apiVersion: "v1",
|
|
60
|
+
kind: "Namespace",
|
|
61
|
+
metadata: { name: "pepr-system" },
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Grants the controller access to cluster resources beyond the mutating webhook.
|
|
67
|
+
*
|
|
68
|
+
* @todo: should dynamically generate this based on resources used by the module. will also need to explore how this should work for multiple modules.
|
|
69
|
+
* @returns
|
|
70
|
+
*/
|
|
71
|
+
clusterRole(): V1ClusterRole {
|
|
72
|
+
return {
|
|
73
|
+
apiVersion: "rbac.authorization.k8s.io/v1",
|
|
74
|
+
kind: "ClusterRole",
|
|
75
|
+
metadata: { name: this.name },
|
|
76
|
+
rules: [
|
|
77
|
+
{
|
|
78
|
+
// @todo: make this configurable
|
|
79
|
+
apiGroups: ["*"],
|
|
80
|
+
resources: ["*"],
|
|
81
|
+
verbs: ["create", "delete", "get", "list", "patch", "update", "watch"],
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
clusterRoleBinding(): V1ClusterRoleBinding {
|
|
88
|
+
const name = this.name;
|
|
89
|
+
return {
|
|
90
|
+
apiVersion: "rbac.authorization.k8s.io/v1",
|
|
91
|
+
kind: "ClusterRoleBinding",
|
|
92
|
+
metadata: { name },
|
|
93
|
+
roleRef: {
|
|
94
|
+
apiGroup: "rbac.authorization.k8s.io",
|
|
95
|
+
kind: "ClusterRole",
|
|
96
|
+
name,
|
|
97
|
+
},
|
|
98
|
+
subjects: [
|
|
99
|
+
{
|
|
100
|
+
kind: "ServiceAccount",
|
|
101
|
+
name,
|
|
102
|
+
namespace: "pepr-system",
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
serviceAccount(): V1ServiceAccount {
|
|
109
|
+
return {
|
|
110
|
+
apiVersion: "v1",
|
|
111
|
+
kind: "ServiceAccount",
|
|
112
|
+
metadata: {
|
|
113
|
+
name: this.name,
|
|
114
|
+
namespace: "pepr-system",
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
tlsSecret(): V1Secret {
|
|
120
|
+
return {
|
|
121
|
+
apiVersion: "v1",
|
|
122
|
+
kind: "Secret",
|
|
123
|
+
metadata: {
|
|
124
|
+
name: `${this.name}-tls`,
|
|
125
|
+
namespace: "pepr-system",
|
|
126
|
+
},
|
|
127
|
+
type: "kubernetes.io/tls",
|
|
128
|
+
data: {
|
|
129
|
+
"tls.crt": this._tls.crt,
|
|
130
|
+
"tls.key": this._tls.key,
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
mutatingWebhook(): V1MutatingWebhookConfiguration {
|
|
136
|
+
const { name } = this;
|
|
137
|
+
const ignore = [peprIgnore];
|
|
138
|
+
|
|
139
|
+
// Add any namespaces to ignore
|
|
140
|
+
if (this.config.alwaysIgnore.namespaces && this.config.alwaysIgnore.namespaces.length > 0) {
|
|
141
|
+
ignore.push({
|
|
142
|
+
key: "kubernetes.io/metadata.name",
|
|
143
|
+
operator: "NotIn",
|
|
144
|
+
values: this.config.alwaysIgnore.namespaces,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const clientConfig: AdmissionregistrationV1WebhookClientConfig = {
|
|
149
|
+
caBundle: this._tls.ca,
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// If a host is specified, use that with a port of 3000
|
|
153
|
+
if (this.host) {
|
|
154
|
+
clientConfig.url = `https://${this.host}:3000/mutate`;
|
|
155
|
+
} else {
|
|
156
|
+
// Otherwise, use the service
|
|
157
|
+
clientConfig.service = {
|
|
158
|
+
name: this.name,
|
|
159
|
+
namespace: "pepr-system",
|
|
160
|
+
path: "/mutate",
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
apiVersion: "admissionregistration.k8s.io/v1",
|
|
166
|
+
kind: "MutatingWebhookConfiguration",
|
|
167
|
+
metadata: { name },
|
|
168
|
+
webhooks: [
|
|
169
|
+
{
|
|
170
|
+
name: `${name}.pepr.dev`,
|
|
171
|
+
admissionReviewVersions: ["v1", "v1beta1"],
|
|
172
|
+
clientConfig,
|
|
173
|
+
failurePolicy: "Ignore",
|
|
174
|
+
matchPolicy: "Equivalent",
|
|
175
|
+
timeoutSeconds: 15,
|
|
176
|
+
namespaceSelector: {
|
|
177
|
+
matchExpressions: ignore,
|
|
178
|
+
},
|
|
179
|
+
objectSelector: {
|
|
180
|
+
matchExpressions: ignore,
|
|
181
|
+
},
|
|
182
|
+
// @todo: make this configurable
|
|
183
|
+
rules: [
|
|
184
|
+
{
|
|
185
|
+
apiGroups: ["*"],
|
|
186
|
+
apiVersions: ["*"],
|
|
187
|
+
operations: ["CREATE", "UPDATE", "DELETE"],
|
|
188
|
+
resources: ["*/*"],
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
// @todo: track side effects state
|
|
192
|
+
sideEffects: "None",
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
deployment(hash: string): V1Deployment {
|
|
199
|
+
return {
|
|
200
|
+
apiVersion: "apps/v1",
|
|
201
|
+
kind: "Deployment",
|
|
202
|
+
metadata: {
|
|
203
|
+
name: this.name,
|
|
204
|
+
namespace: "pepr-system",
|
|
205
|
+
labels: {
|
|
206
|
+
app: this.name,
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
spec: {
|
|
210
|
+
replicas: 2,
|
|
211
|
+
selector: {
|
|
212
|
+
matchLabels: {
|
|
213
|
+
app: this.name,
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
template: {
|
|
217
|
+
metadata: {
|
|
218
|
+
labels: {
|
|
219
|
+
app: this.name,
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
spec: {
|
|
223
|
+
priorityClassName: "system-node-critical",
|
|
224
|
+
serviceAccountName: this.name,
|
|
225
|
+
containers: [
|
|
226
|
+
{
|
|
227
|
+
name: "server",
|
|
228
|
+
image: this.image,
|
|
229
|
+
imagePullPolicy: "IfNotPresent",
|
|
230
|
+
command: ["node", "/app/node_modules/pepr/dist/src/cli/run.js", hash],
|
|
231
|
+
livenessProbe: {
|
|
232
|
+
httpGet: {
|
|
233
|
+
path: "/healthz",
|
|
234
|
+
port: 3000,
|
|
235
|
+
scheme: "HTTPS",
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
ports: [
|
|
239
|
+
{
|
|
240
|
+
containerPort: 3000,
|
|
241
|
+
},
|
|
242
|
+
],
|
|
243
|
+
resources: {
|
|
244
|
+
requests: {
|
|
245
|
+
memory: "64Mi",
|
|
246
|
+
cpu: "100m",
|
|
247
|
+
},
|
|
248
|
+
limits: {
|
|
249
|
+
memory: "256Mi",
|
|
250
|
+
cpu: "500m",
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
volumeMounts: [
|
|
254
|
+
{
|
|
255
|
+
name: "tls-certs",
|
|
256
|
+
mountPath: "/etc/certs",
|
|
257
|
+
readOnly: true,
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
name: "module",
|
|
261
|
+
mountPath: `/app/load`,
|
|
262
|
+
readOnly: true,
|
|
263
|
+
},
|
|
264
|
+
],
|
|
265
|
+
},
|
|
266
|
+
],
|
|
267
|
+
volumes: [
|
|
268
|
+
{
|
|
269
|
+
name: "tls-certs",
|
|
270
|
+
secret: {
|
|
271
|
+
secretName: `${this.name}-tls`,
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
name: "module",
|
|
276
|
+
secret: {
|
|
277
|
+
secretName: `${this.name}-module`,
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
],
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/** Only permit the kube-system ns ingress access to the controller */
|
|
288
|
+
networkPolicy(): V1NetworkPolicy {
|
|
289
|
+
return {
|
|
290
|
+
apiVersion: "networking.k8s.io/v1",
|
|
291
|
+
kind: "NetworkPolicy",
|
|
292
|
+
metadata: {
|
|
293
|
+
name: this.name,
|
|
294
|
+
namespace: "pepr-system",
|
|
295
|
+
},
|
|
296
|
+
spec: {
|
|
297
|
+
podSelector: {
|
|
298
|
+
matchLabels: {
|
|
299
|
+
app: this.name,
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
policyTypes: ["Ingress"],
|
|
303
|
+
ingress: [
|
|
304
|
+
{
|
|
305
|
+
from: [
|
|
306
|
+
{
|
|
307
|
+
namespaceSelector: {
|
|
308
|
+
matchLabels: {
|
|
309
|
+
"kubernetes.io/metadata.name": "kube-system",
|
|
310
|
+
},
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
],
|
|
314
|
+
ports: [
|
|
315
|
+
{
|
|
316
|
+
protocol: "TCP",
|
|
317
|
+
port: 443,
|
|
318
|
+
},
|
|
319
|
+
],
|
|
320
|
+
},
|
|
321
|
+
],
|
|
322
|
+
},
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
service(): V1Service {
|
|
327
|
+
return {
|
|
328
|
+
apiVersion: "v1",
|
|
329
|
+
kind: "Service",
|
|
330
|
+
metadata: {
|
|
331
|
+
name: this.name,
|
|
332
|
+
namespace: "pepr-system",
|
|
333
|
+
},
|
|
334
|
+
spec: {
|
|
335
|
+
selector: {
|
|
336
|
+
app: this.name,
|
|
337
|
+
},
|
|
338
|
+
ports: [
|
|
339
|
+
{
|
|
340
|
+
port: 443,
|
|
341
|
+
targetPort: 3000,
|
|
342
|
+
},
|
|
343
|
+
],
|
|
344
|
+
},
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
moduleSecret(data: Buffer, hash: string): V1Secret {
|
|
349
|
+
// Compress the data
|
|
350
|
+
const compressed = gzipSync(data);
|
|
351
|
+
const path = `module-${hash}.js.gz`;
|
|
352
|
+
return {
|
|
353
|
+
apiVersion: "v1",
|
|
354
|
+
kind: "Secret",
|
|
355
|
+
metadata: {
|
|
356
|
+
name: `${this.name}-module`,
|
|
357
|
+
namespace: "pepr-system",
|
|
358
|
+
},
|
|
359
|
+
type: "Opaque",
|
|
360
|
+
data: {
|
|
361
|
+
[path]: compressed.toString("base64"),
|
|
362
|
+
},
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
zarfYaml(path: string) {
|
|
367
|
+
const zarfCfg = {
|
|
368
|
+
kind: "ZarfPackageConfig",
|
|
369
|
+
metadata: {
|
|
370
|
+
name: this.name,
|
|
371
|
+
description: `Pepr Module: ${this.config.description}`,
|
|
372
|
+
url: "https://github.com/defenseunicorns/pepr",
|
|
373
|
+
},
|
|
374
|
+
components: [
|
|
375
|
+
{
|
|
376
|
+
name: "module",
|
|
377
|
+
required: true,
|
|
378
|
+
manifests: [
|
|
379
|
+
{
|
|
380
|
+
name: "module",
|
|
381
|
+
namespace: "pepr-system",
|
|
382
|
+
files: [path],
|
|
383
|
+
},
|
|
384
|
+
],
|
|
385
|
+
images: [this.image],
|
|
386
|
+
},
|
|
387
|
+
],
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
return dumpYaml(zarfCfg, { noRefs: true });
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
allYaml(code: Buffer) {
|
|
394
|
+
// Generate a hash of the code
|
|
395
|
+
const hash = crypto.createHash("sha256").update(code).digest("hex");
|
|
396
|
+
|
|
397
|
+
const resources = [
|
|
398
|
+
this.namespace(),
|
|
399
|
+
this.networkPolicy(),
|
|
400
|
+
this.clusterRole(),
|
|
401
|
+
this.clusterRoleBinding(),
|
|
402
|
+
this.serviceAccount(),
|
|
403
|
+
this.tlsSecret(),
|
|
404
|
+
this.mutatingWebhook(),
|
|
405
|
+
this.deployment(hash),
|
|
406
|
+
this.service(),
|
|
407
|
+
this.moduleSecret(code, hash),
|
|
408
|
+
];
|
|
409
|
+
|
|
410
|
+
// Convert the resources to a single YAML string
|
|
411
|
+
return resources.map(r => dumpYaml(r, { noRefs: true })).join("---\n");
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
async deploy(code: Buffer) {
|
|
415
|
+
Log.info("Establishing connection to Kubernetes");
|
|
416
|
+
|
|
417
|
+
const namespace = "pepr-system";
|
|
418
|
+
const hash = crypto.createHash("sha256").update(code).digest("hex");
|
|
419
|
+
|
|
420
|
+
// Deploy the resources using the k8s API
|
|
421
|
+
const kubeConfig = new KubeConfig();
|
|
422
|
+
kubeConfig.loadFromDefault();
|
|
423
|
+
|
|
424
|
+
const coreV1Api = kubeConfig.makeApiClient(CoreV1Api);
|
|
425
|
+
const rbacApi = kubeConfig.makeApiClient(RbacAuthorizationV1Api);
|
|
426
|
+
const appsApi = kubeConfig.makeApiClient(AppsV1Api);
|
|
427
|
+
const admissionApi = kubeConfig.makeApiClient(AdmissionregistrationV1Api);
|
|
428
|
+
const networkApi = kubeConfig.makeApiClient(NetworkingV1Api);
|
|
429
|
+
|
|
430
|
+
const ns = this.namespace();
|
|
431
|
+
try {
|
|
432
|
+
Log.info("Checking for namespace");
|
|
433
|
+
await coreV1Api.readNamespace(namespace);
|
|
434
|
+
} catch (e) {
|
|
435
|
+
Log.debug(e instanceof HttpError ? e.body : e);
|
|
436
|
+
Log.info("Creating namespace");
|
|
437
|
+
await coreV1Api.createNamespace(ns);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const wh = this.mutatingWebhook();
|
|
441
|
+
try {
|
|
442
|
+
Log.info("Creating mutating webhook");
|
|
443
|
+
await admissionApi.createMutatingWebhookConfiguration(wh);
|
|
444
|
+
} catch (e) {
|
|
445
|
+
Log.debug(e instanceof HttpError ? e.body : e);
|
|
446
|
+
Log.info("Removing and re-creating mutating webhook");
|
|
447
|
+
await admissionApi.deleteMutatingWebhookConfiguration(wh.metadata?.name ?? "");
|
|
448
|
+
await admissionApi.createMutatingWebhookConfiguration(wh);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// If a host is specified, we don't need to deploy the rest of the resources
|
|
452
|
+
if (this.host) {
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const netpol = this.networkPolicy();
|
|
457
|
+
try {
|
|
458
|
+
Log.info("Checking for network policy");
|
|
459
|
+
await networkApi.readNamespacedNetworkPolicy(netpol.metadata?.name ?? "", namespace);
|
|
460
|
+
} catch (e) {
|
|
461
|
+
Log.debug(e instanceof HttpError ? e.body : e);
|
|
462
|
+
Log.info("Creating network policy");
|
|
463
|
+
await networkApi.createNamespacedNetworkPolicy(namespace, netpol);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
const crb = this.clusterRoleBinding();
|
|
467
|
+
try {
|
|
468
|
+
Log.info("Creating cluster role binding");
|
|
469
|
+
await rbacApi.createClusterRoleBinding(crb);
|
|
470
|
+
} catch (e) {
|
|
471
|
+
Log.debug(e instanceof HttpError ? e.body : e);
|
|
472
|
+
Log.info("Removing and re-creating cluster role binding");
|
|
473
|
+
await rbacApi.deleteClusterRoleBinding(crb.metadata?.name ?? "");
|
|
474
|
+
await rbacApi.createClusterRoleBinding(crb);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
const cr = this.clusterRole();
|
|
478
|
+
try {
|
|
479
|
+
Log.info("Creating cluster role");
|
|
480
|
+
await rbacApi.createClusterRole(cr);
|
|
481
|
+
} catch (e) {
|
|
482
|
+
Log.debug(e instanceof HttpError ? e.body : e);
|
|
483
|
+
Log.info("Removing and re-creating the cluster role");
|
|
484
|
+
try {
|
|
485
|
+
await rbacApi.deleteClusterRole(cr.metadata?.name ?? "");
|
|
486
|
+
await rbacApi.createClusterRole(cr);
|
|
487
|
+
} catch (e) {
|
|
488
|
+
Log.debug(e instanceof HttpError ? e.body : e);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const sa = this.serviceAccount();
|
|
493
|
+
try {
|
|
494
|
+
Log.info("Creating service account");
|
|
495
|
+
await coreV1Api.createNamespacedServiceAccount(namespace, sa);
|
|
496
|
+
} catch (e) {
|
|
497
|
+
Log.debug(e instanceof HttpError ? e.body : e);
|
|
498
|
+
Log.info("Removing and re-creating service account");
|
|
499
|
+
await coreV1Api.deleteNamespacedServiceAccount(sa.metadata?.name ?? "", namespace);
|
|
500
|
+
await coreV1Api.createNamespacedServiceAccount(namespace, sa);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
const mod = this.moduleSecret(code, hash);
|
|
504
|
+
try {
|
|
505
|
+
Log.info("Creating module secret");
|
|
506
|
+
await coreV1Api.createNamespacedSecret(namespace, mod);
|
|
507
|
+
} catch (e) {
|
|
508
|
+
Log.debug(e instanceof HttpError ? e.body : e);
|
|
509
|
+
Log.info("Removing and re-creating module secret");
|
|
510
|
+
await coreV1Api.deleteNamespacedSecret(mod.metadata?.name ?? "", namespace);
|
|
511
|
+
await coreV1Api.createNamespacedSecret(namespace, mod);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
const svc = this.service();
|
|
515
|
+
try {
|
|
516
|
+
Log.info("Creating service");
|
|
517
|
+
await coreV1Api.createNamespacedService(namespace, svc);
|
|
518
|
+
} catch (e) {
|
|
519
|
+
Log.debug(e instanceof HttpError ? e.body : e);
|
|
520
|
+
Log.info("Removing and re-creating service");
|
|
521
|
+
await coreV1Api.deleteNamespacedService(svc.metadata?.name ?? "", namespace);
|
|
522
|
+
await coreV1Api.createNamespacedService(namespace, svc);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
const tls = this.tlsSecret();
|
|
526
|
+
try {
|
|
527
|
+
Log.info("Creating TLS secret");
|
|
528
|
+
await coreV1Api.createNamespacedSecret(namespace, tls);
|
|
529
|
+
} catch (e) {
|
|
530
|
+
Log.debug(e instanceof HttpError ? e.body : e);
|
|
531
|
+
Log.info("Removing and re-creating TLS secret");
|
|
532
|
+
await coreV1Api.deleteNamespacedSecret(tls.metadata?.name ?? "", namespace);
|
|
533
|
+
await coreV1Api.createNamespacedSecret(namespace, tls);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
const dep = this.deployment(hash);
|
|
537
|
+
try {
|
|
538
|
+
Log.info("Creating deployment");
|
|
539
|
+
await appsApi.createNamespacedDeployment(namespace, dep);
|
|
540
|
+
} catch (e) {
|
|
541
|
+
Log.debug(e instanceof HttpError ? e.body : e);
|
|
542
|
+
Log.info("Removing and re-creating deployment");
|
|
543
|
+
await appsApi.deleteNamespacedDeployment(dep.metadata?.name ?? "", namespace);
|
|
544
|
+
await appsApi.createNamespacedDeployment(namespace, dep);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// SPDX-FileCopyrightText: 2023-Present The Pepr Authors
|
|
3
|
+
|
|
4
|
+
import test from "ava";
|
|
5
|
+
import { LogLevel, Logger } from "./logger";
|
|
6
|
+
|
|
7
|
+
test("Logger debug logs correctly", t => {
|
|
8
|
+
const logger = new Logger(LogLevel.debug); // Create a logger with debug level
|
|
9
|
+
const message = "Debug message";
|
|
10
|
+
const consoleLog = console.log; // Store the original console.log function
|
|
11
|
+
const consoleOutput: string[] = [];
|
|
12
|
+
|
|
13
|
+
// Replace console.log with a mock function to capture the output
|
|
14
|
+
console.log = (output: string) => {
|
|
15
|
+
consoleOutput.push(output);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
logger.debug(message); // Call the debug method
|
|
19
|
+
|
|
20
|
+
// Check that the output matches the expected value
|
|
21
|
+
t.true(consoleOutput[0].includes(LogLevel[LogLevel.debug]));
|
|
22
|
+
t.true(consoleOutput[0].includes(message));
|
|
23
|
+
|
|
24
|
+
// Restore the original console.log function
|
|
25
|
+
console.log = consoleLog;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test("Logger info logs correctly", t => {
|
|
29
|
+
const logger = new Logger(LogLevel.info); // Create a logger with info level
|
|
30
|
+
const message = "Info message";
|
|
31
|
+
const consoleLog = console.log;
|
|
32
|
+
const consoleOutput: string[] = [];
|
|
33
|
+
|
|
34
|
+
console.log = (output: string) => {
|
|
35
|
+
consoleOutput.push(output);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
logger.info(message);
|
|
39
|
+
|
|
40
|
+
t.true(consoleOutput[0].includes(LogLevel[LogLevel.info]));
|
|
41
|
+
t.true(consoleOutput[0].includes(message));
|
|
42
|
+
|
|
43
|
+
console.log = consoleLog;
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("Logger warn logs correctly", t => {
|
|
47
|
+
const logger = new Logger(LogLevel.warn); // Create a logger with warn level
|
|
48
|
+
const message = "Warning message";
|
|
49
|
+
const consoleLog = console.log;
|
|
50
|
+
const consoleOutput: string[] = [];
|
|
51
|
+
|
|
52
|
+
console.log = (output: string) => {
|
|
53
|
+
consoleOutput.push(output);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
logger.warn(message);
|
|
57
|
+
|
|
58
|
+
t.true(consoleOutput[0].includes(LogLevel[LogLevel.warn]));
|
|
59
|
+
t.true(consoleOutput[0].includes(message));
|
|
60
|
+
|
|
61
|
+
console.log = consoleLog;
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("Logger error logs correctly", t => {
|
|
65
|
+
const logger = new Logger(LogLevel.error); // Create a logger with error level
|
|
66
|
+
const message = "Error message";
|
|
67
|
+
const consoleLog = console.log;
|
|
68
|
+
const consoleOutput: string[] = [];
|
|
69
|
+
|
|
70
|
+
console.log = (output: string) => {
|
|
71
|
+
consoleOutput.push(output);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
logger.error(message);
|
|
75
|
+
|
|
76
|
+
t.true(consoleOutput[0].includes(LogLevel[LogLevel.error]));
|
|
77
|
+
t.true(consoleOutput[0].includes(message));
|
|
78
|
+
|
|
79
|
+
console.log = consoleLog;
|
|
80
|
+
});
|