pepr 0.40.1 → 0.42.0
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 +11 -5
- package/dist/cli/build.d.ts.map +1 -1
- package/dist/cli/deploy.d.ts.map +1 -1
- package/dist/cli/init/templates.d.ts +2 -2
- package/dist/cli.js +228 -179
- package/dist/controller.js +52 -27
- package/dist/lib/assets/index.d.ts.map +1 -1
- package/dist/lib/capability.d.ts.map +1 -1
- package/dist/lib/controller/index.d.ts.map +1 -1
- package/dist/lib/controller/index.util.d.ts +10 -0
- package/dist/lib/controller/index.util.d.ts.map +1 -0
- package/dist/lib/controller/store.d.ts +1 -1
- package/dist/lib/deploymentChecks.d.ts +3 -0
- package/dist/lib/deploymentChecks.d.ts.map +1 -0
- package/dist/lib/enums.d.ts +5 -5
- package/dist/lib/enums.d.ts.map +1 -1
- package/dist/lib/filesystemService.d.ts +2 -0
- package/dist/lib/filesystemService.d.ts.map +1 -0
- package/dist/lib/filter/adjudicators/adjudicators.d.ts +73 -0
- package/dist/lib/filter/adjudicators/adjudicators.d.ts.map +1 -0
- package/dist/lib/filter/adjudicators/defaultTestObjects.d.ts +7 -0
- package/dist/lib/filter/adjudicators/defaultTestObjects.d.ts.map +1 -0
- package/dist/lib/helpers.d.ts +1 -4
- package/dist/lib/helpers.d.ts.map +1 -1
- package/dist/lib/schedule.d.ts.map +1 -1
- package/dist/lib/storage.d.ts +1 -1
- package/dist/lib/storage.d.ts.map +1 -1
- package/dist/lib/{logger.d.ts → telemetry/logger.d.ts} +1 -1
- package/dist/lib/telemetry/logger.d.ts.map +1 -0
- package/dist/lib/{metrics.d.ts → telemetry/metrics.d.ts} +3 -1
- package/dist/lib/telemetry/metrics.d.ts.map +1 -0
- package/dist/lib/types.d.ts +10 -9
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib.d.ts +1 -1
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +151 -126
- package/dist/lib.js.map +4 -4
- package/dist/sdk/sdk.d.ts +3 -4
- package/dist/sdk/sdk.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/cli/build.ts +2 -1
- package/src/cli/deploy.ts +2 -1
- package/src/cli/init/templates.ts +1 -1
- package/src/lib/assets/deploy.ts +1 -1
- package/src/lib/assets/destroy.ts +1 -1
- package/src/lib/assets/index.ts +102 -81
- package/src/lib/assets/webhooks.ts +2 -2
- package/src/lib/capability.ts +8 -9
- package/src/lib/controller/index.ts +32 -62
- package/src/lib/controller/index.util.ts +47 -0
- package/src/lib/controller/store.ts +2 -2
- package/src/lib/controller/storeCache.ts +1 -1
- package/src/lib/deploymentChecks.ts +43 -0
- package/src/lib/enums.ts +5 -5
- package/src/lib/filesystemService.ts +16 -0
- package/src/lib/filter/{adjudicators.ts → adjudicators/adjudicators.ts} +67 -35
- package/src/lib/filter/adjudicators/defaultTestObjects.ts +46 -0
- package/src/lib/filter/filter.ts +1 -1
- package/src/lib/finalizer.ts +1 -1
- package/src/lib/helpers.ts +31 -88
- package/src/lib/mutate-processor.ts +1 -1
- package/src/lib/queue.ts +1 -1
- package/src/lib/schedule.ts +8 -8
- package/src/lib/storage.ts +17 -17
- package/src/lib/{logger.ts → telemetry/logger.ts} +1 -1
- package/src/lib/{metrics.ts → telemetry/metrics.ts} +18 -17
- package/src/lib/types.ts +12 -9
- package/src/lib/utils.ts +1 -1
- package/src/lib/validate-processor.ts +1 -1
- package/src/lib/watch-processor.ts +8 -8
- package/src/lib.ts +1 -1
- package/src/runtime/controller.ts +1 -1
- package/src/sdk/sdk.ts +6 -9
- package/src/templates/capabilities/hello-pepr.ts +19 -9
- package/dist/lib/filter/adjudicators.d.ts +0 -69
- package/dist/lib/filter/adjudicators.d.ts.map +0 -1
- package/dist/lib/logger.d.ts.map +0 -1
- package/dist/lib/metrics.d.ts.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -170,10 +170,10 @@ function genCert(key, name2, issuer) {
|
|
|
170
170
|
|
|
171
171
|
// src/lib/assets/deploy.ts
|
|
172
172
|
var import_crypto = __toESM(require("crypto"));
|
|
173
|
-
var
|
|
174
|
-
var
|
|
173
|
+
var import_fs2 = require("fs");
|
|
174
|
+
var import_kubernetes_fluent_client3 = require("kubernetes-fluent-client");
|
|
175
175
|
|
|
176
|
-
// src/lib/logger.ts
|
|
176
|
+
// src/lib/telemetry/logger.ts
|
|
177
177
|
var import_pino = require("pino");
|
|
178
178
|
var isPrettyLog = true;
|
|
179
179
|
var pretty = {
|
|
@@ -277,17 +277,13 @@ function watcherService(name2) {
|
|
|
277
277
|
// src/lib/assets/pods.ts
|
|
278
278
|
var import_zlib = require("zlib");
|
|
279
279
|
|
|
280
|
-
// src/lib/helpers.ts
|
|
281
|
-
var import_fs2 = require("fs");
|
|
282
|
-
var import_kubernetes_fluent_client2 = require("kubernetes-fluent-client");
|
|
283
|
-
|
|
284
280
|
// src/sdk/sdk.ts
|
|
285
281
|
var import_kubernetes_fluent_client = require("kubernetes-fluent-client");
|
|
286
282
|
function sanitizeResourceName(name2) {
|
|
287
283
|
return name2.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 250).replace(/^[^a-z]+|[^a-z]+$/g, "");
|
|
288
284
|
}
|
|
289
285
|
|
|
290
|
-
// src/lib/filter/adjudicators.ts
|
|
286
|
+
// src/lib/filter/adjudicators/adjudicators.ts
|
|
291
287
|
var import_ramda = require("ramda");
|
|
292
288
|
var declaredOperation = (0, import_ramda.pipe)(
|
|
293
289
|
(request) => request?.operation,
|
|
@@ -311,23 +307,49 @@ var carriesDeletionTimestamp = (0, import_ramda.pipe)(
|
|
|
311
307
|
(0, import_ramda.defaultTo)(false)
|
|
312
308
|
);
|
|
313
309
|
var missingDeletionTimestamp = (0, import_ramda.complement)(carriesDeletionTimestamp);
|
|
314
|
-
var carriedKind = (0, import_ramda.pipe)(
|
|
315
|
-
|
|
316
|
-
|
|
310
|
+
var carriedKind = (0, import_ramda.pipe)(
|
|
311
|
+
(kubernetesObject) => kubernetesObject?.kind,
|
|
312
|
+
(0, import_ramda.defaultTo)("not set")
|
|
313
|
+
);
|
|
314
|
+
var carriedVersion = (0, import_ramda.pipe)(
|
|
315
|
+
(kubernetesObject) => kubernetesObject?.metadata?.resourceVersion,
|
|
316
|
+
(0, import_ramda.defaultTo)("not set")
|
|
317
|
+
);
|
|
318
|
+
var carriedName = (0, import_ramda.pipe)(
|
|
319
|
+
(kubernetesObject) => kubernetesObject?.metadata?.name,
|
|
320
|
+
(0, import_ramda.defaultTo)("")
|
|
321
|
+
);
|
|
317
322
|
var carriesName = (0, import_ramda.pipe)(carriedName, (0, import_ramda.equals)(""), import_ramda.not);
|
|
318
323
|
var missingName = (0, import_ramda.complement)(carriesName);
|
|
319
|
-
var carriedNamespace = (0, import_ramda.pipe)(
|
|
324
|
+
var carriedNamespace = (0, import_ramda.pipe)(
|
|
325
|
+
(kubernetesObject) => kubernetesObject?.metadata?.namespace,
|
|
326
|
+
(0, import_ramda.defaultTo)("")
|
|
327
|
+
);
|
|
320
328
|
var carriesNamespace = (0, import_ramda.pipe)(carriedNamespace, (0, import_ramda.equals)(""), import_ramda.not);
|
|
321
|
-
var carriedAnnotations = (0, import_ramda.pipe)(
|
|
329
|
+
var carriedAnnotations = (0, import_ramda.pipe)(
|
|
330
|
+
(kubernetesObject) => kubernetesObject?.metadata?.annotations,
|
|
331
|
+
(0, import_ramda.defaultTo)({})
|
|
332
|
+
);
|
|
322
333
|
var carriesAnnotations = (0, import_ramda.pipe)(carriedAnnotations, (0, import_ramda.equals)({}), import_ramda.not);
|
|
323
|
-
var carriedLabels = (0, import_ramda.pipe)(
|
|
334
|
+
var carriedLabels = (0, import_ramda.pipe)(
|
|
335
|
+
(kubernetesObject) => kubernetesObject?.metadata?.labels,
|
|
336
|
+
(0, import_ramda.defaultTo)({})
|
|
337
|
+
);
|
|
324
338
|
var carriesLabels = (0, import_ramda.pipe)(carriedLabels, (0, import_ramda.equals)({}), import_ramda.not);
|
|
325
|
-
var definesDeletionTimestamp = (0, import_ramda.pipe)(
|
|
339
|
+
var definesDeletionTimestamp = (0, import_ramda.pipe)(
|
|
340
|
+
(binding) => binding?.filters?.deletionTimestamp ?? false,
|
|
341
|
+
(0, import_ramda.defaultTo)(false)
|
|
342
|
+
);
|
|
326
343
|
var ignoresDeletionTimestamp = (0, import_ramda.complement)(definesDeletionTimestamp);
|
|
327
|
-
var definedName = (0, import_ramda.pipe)((binding) =>
|
|
344
|
+
var definedName = (0, import_ramda.pipe)((binding) => {
|
|
345
|
+
return binding.filters.name;
|
|
346
|
+
}, (0, import_ramda.defaultTo)(""));
|
|
328
347
|
var definesName = (0, import_ramda.pipe)(definedName, (0, import_ramda.equals)(""), import_ramda.not);
|
|
329
348
|
var ignoresName = (0, import_ramda.complement)(definesName);
|
|
330
|
-
var definedNameRegex = (0, import_ramda.pipe)(
|
|
349
|
+
var definedNameRegex = (0, import_ramda.pipe)(
|
|
350
|
+
(binding) => binding.filters?.regexName,
|
|
351
|
+
(0, import_ramda.defaultTo)("")
|
|
352
|
+
);
|
|
331
353
|
var definesNameRegex = (0, import_ramda.pipe)(definedNameRegex, (0, import_ramda.equals)(""), import_ramda.not);
|
|
332
354
|
var definedNamespaces = (0, import_ramda.pipe)((binding) => binding?.filters?.namespaces, (0, import_ramda.defaultTo)([]));
|
|
333
355
|
var definesNamespaces = (0, import_ramda.pipe)(definedNamespaces, (0, import_ramda.equals)([]), import_ramda.not);
|
|
@@ -337,20 +359,22 @@ var definedAnnotations = (0, import_ramda.pipe)((binding) => binding?.filters?.a
|
|
|
337
359
|
var definesAnnotations = (0, import_ramda.pipe)(definedAnnotations, (0, import_ramda.equals)({}), import_ramda.not);
|
|
338
360
|
var definedLabels = (0, import_ramda.pipe)((binding) => binding?.filters?.labels, (0, import_ramda.defaultTo)({}));
|
|
339
361
|
var definesLabels = (0, import_ramda.pipe)(definedLabels, (0, import_ramda.equals)({}), import_ramda.not);
|
|
340
|
-
var definedEvent = (
|
|
362
|
+
var definedEvent = (binding) => {
|
|
363
|
+
return binding.event;
|
|
364
|
+
};
|
|
341
365
|
var definesDelete = (0, import_ramda.pipe)(definedEvent, (0, import_ramda.equals)("DELETE" /* DELETE */));
|
|
342
366
|
var definedGroup = (0, import_ramda.pipe)((binding) => binding?.kind?.group, (0, import_ramda.defaultTo)(""));
|
|
343
367
|
var definesGroup = (0, import_ramda.pipe)(definedGroup, (0, import_ramda.equals)(""), import_ramda.not);
|
|
344
|
-
var definedVersion = (0, import_ramda.pipe)(
|
|
368
|
+
var definedVersion = (0, import_ramda.pipe)(
|
|
369
|
+
(binding) => binding?.kind?.version,
|
|
370
|
+
(0, import_ramda.defaultTo)("")
|
|
371
|
+
);
|
|
345
372
|
var definesVersion = (0, import_ramda.pipe)(definedVersion, (0, import_ramda.equals)(""), import_ramda.not);
|
|
346
373
|
var definedKind = (0, import_ramda.pipe)((binding) => binding?.kind?.kind, (0, import_ramda.defaultTo)(""));
|
|
347
374
|
var definesKind = (0, import_ramda.pipe)(definedKind, (0, import_ramda.equals)(""), import_ramda.not);
|
|
348
|
-
var
|
|
349
|
-
return binding.isFinalize ? "Finalize" : binding.isWatch ? "Watch" : binding.isMutate ? "Mutate" : binding.isValidate ? "Validate" : "";
|
|
350
|
-
});
|
|
351
|
-
var definedCallback = (0, import_ramda.pipe)((binding) => {
|
|
375
|
+
var definedCallback = (binding) => {
|
|
352
376
|
return binding.isFinalize ? binding.finalizeCallback : binding.isWatch ? binding.watchCallback : binding.isMutate ? binding.mutateCallback : binding.isValidate ? binding.validateCallback : null;
|
|
353
|
-
}
|
|
377
|
+
};
|
|
354
378
|
var definedCallbackName = (0, import_ramda.pipe)(definedCallback, (0, import_ramda.defaultTo)({ name: "" }), (callback) => callback.name);
|
|
355
379
|
var mismatchedDeletionTimestamp = (0, import_ramda.allPass)([
|
|
356
380
|
(0, import_ramda.pipe)((0, import_ramda.nthArg)(0), definesDeletionTimestamp),
|
|
@@ -432,8 +456,8 @@ var unbindableNamespaces = (0, import_ramda.allPass)([
|
|
|
432
456
|
]);
|
|
433
457
|
var misboundDeleteWithDeletionTimestamp = (0, import_ramda.allPass)([definesDelete, definesDeletionTimestamp]);
|
|
434
458
|
var operationMatchesEvent = (0, import_ramda.anyPass)([
|
|
435
|
-
(0, import_ramda.pipe)((0, import_ramda.nthArg)(1), (0, import_ramda.equals)("*" /*
|
|
436
|
-
(0, import_ramda.pipe)((operation, event) => operation === event),
|
|
459
|
+
(0, import_ramda.pipe)((0, import_ramda.nthArg)(1), (0, import_ramda.equals)("*" /* ANY */)),
|
|
460
|
+
(0, import_ramda.pipe)((operation, event) => operation.valueOf() === event.valueOf()),
|
|
437
461
|
(0, import_ramda.pipe)((operation, event) => operation ? event.includes(operation) : false)
|
|
438
462
|
]);
|
|
439
463
|
var mismatchedEvent = (0, import_ramda.pipe)(
|
|
@@ -455,11 +479,7 @@ var mismatchedKind = (0, import_ramda.allPass)([
|
|
|
455
479
|
|
|
456
480
|
// src/lib/helpers.ts
|
|
457
481
|
function matchesRegex(pattern, testString) {
|
|
458
|
-
|
|
459
|
-
return false;
|
|
460
|
-
}
|
|
461
|
-
const regex = new RegExp(pattern);
|
|
462
|
-
return regex.test(testString);
|
|
482
|
+
return new RegExp(pattern).test(testString);
|
|
463
483
|
}
|
|
464
484
|
var ValidationError = class extends Error {
|
|
465
485
|
};
|
|
@@ -500,17 +520,6 @@ function createRBACMap(capabilities) {
|
|
|
500
520
|
return acc;
|
|
501
521
|
}, {});
|
|
502
522
|
}
|
|
503
|
-
async function createDirectoryIfNotExists(path) {
|
|
504
|
-
try {
|
|
505
|
-
await import_fs2.promises.access(path);
|
|
506
|
-
} catch (error) {
|
|
507
|
-
if (error.code === "ENOENT") {
|
|
508
|
-
await import_fs2.promises.mkdir(path, { recursive: true });
|
|
509
|
-
} else {
|
|
510
|
-
throw error;
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
523
|
function hasEveryOverlap(array1, array2) {
|
|
515
524
|
if (!Array.isArray(array1) || !Array.isArray(array2)) {
|
|
516
525
|
return false;
|
|
@@ -549,7 +558,9 @@ function generateWatchNamespaceError(ignoredNamespaces, bindingNamespaces, capab
|
|
|
549
558
|
function namespaceComplianceValidator(capability, ignoredNamespaces) {
|
|
550
559
|
const { namespaces: capabilityNamespaces, bindings, name: name2 } = capability;
|
|
551
560
|
const bindingNamespaces = bindings.flatMap((binding) => binding.filters.namespaces);
|
|
552
|
-
const bindingRegexNamespaces = bindings.flatMap(
|
|
561
|
+
const bindingRegexNamespaces = bindings.flatMap(
|
|
562
|
+
(binding) => binding.filters.regexNamespaces || []
|
|
563
|
+
);
|
|
553
564
|
const namespaceError = generateWatchNamespaceError(
|
|
554
565
|
ignoredNamespaces ? ignoredNamespaces : [],
|
|
555
566
|
bindingNamespaces,
|
|
@@ -582,40 +593,6 @@ function namespaceComplianceValidator(capability, ignoredNamespaces) {
|
|
|
582
593
|
}
|
|
583
594
|
}
|
|
584
595
|
}
|
|
585
|
-
async function checkDeploymentStatus(namespace2) {
|
|
586
|
-
const deployments = await (0, import_kubernetes_fluent_client2.K8s)(import_kubernetes_fluent_client2.kind.Deployment).InNamespace(namespace2).Get();
|
|
587
|
-
let status = false;
|
|
588
|
-
let readyCount = 0;
|
|
589
|
-
for (const deployment2 of deployments.items) {
|
|
590
|
-
const readyReplicas = deployment2.status?.readyReplicas ? deployment2.status?.readyReplicas : 0;
|
|
591
|
-
if (deployment2.status?.readyReplicas !== deployment2.spec?.replicas) {
|
|
592
|
-
logger_default.info(
|
|
593
|
-
`Waiting for deployment ${deployment2.metadata?.name} rollout to finish: ${readyReplicas} of ${deployment2.spec?.replicas} replicas are available`
|
|
594
|
-
);
|
|
595
|
-
} else {
|
|
596
|
-
logger_default.info(
|
|
597
|
-
`Deployment ${deployment2.metadata?.name} rolled out: ${readyReplicas} of ${deployment2.spec?.replicas} replicas are available`
|
|
598
|
-
);
|
|
599
|
-
readyCount++;
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
if (readyCount === deployments.items.length) {
|
|
603
|
-
status = true;
|
|
604
|
-
}
|
|
605
|
-
return status;
|
|
606
|
-
}
|
|
607
|
-
async function namespaceDeploymentsReady(namespace2 = "pepr-system") {
|
|
608
|
-
logger_default.info(`Checking ${namespace2} deployments status...`);
|
|
609
|
-
let ready = false;
|
|
610
|
-
while (!ready) {
|
|
611
|
-
ready = await checkDeploymentStatus(namespace2);
|
|
612
|
-
if (ready) {
|
|
613
|
-
return ready;
|
|
614
|
-
}
|
|
615
|
-
await new Promise((resolve5) => setTimeout(resolve5, 1e3));
|
|
616
|
-
}
|
|
617
|
-
logger_default.info(`All ${namespace2} deployments are ready`);
|
|
618
|
-
}
|
|
619
596
|
function secretOverLimit(str) {
|
|
620
597
|
const encoder = new TextEncoder();
|
|
621
598
|
const encoded = encoder.encode(str);
|
|
@@ -1103,19 +1080,19 @@ function storeRoleBinding(name2) {
|
|
|
1103
1080
|
}
|
|
1104
1081
|
|
|
1105
1082
|
// src/lib/k8s.ts
|
|
1106
|
-
var
|
|
1107
|
-
var Store = class extends
|
|
1083
|
+
var import_kubernetes_fluent_client2 = require("kubernetes-fluent-client");
|
|
1084
|
+
var Store = class extends import_kubernetes_fluent_client2.GenericKind {
|
|
1108
1085
|
};
|
|
1109
1086
|
var peprStoreGVK = {
|
|
1110
1087
|
kind: "PeprStore",
|
|
1111
1088
|
version: "v1",
|
|
1112
1089
|
group: "pepr.dev"
|
|
1113
1090
|
};
|
|
1114
|
-
(0,
|
|
1091
|
+
(0, import_kubernetes_fluent_client2.RegisterKind)(Store, peprStoreGVK);
|
|
1115
1092
|
|
|
1116
1093
|
// src/lib/assets/store.ts
|
|
1117
|
-
var { group, version, kind:
|
|
1118
|
-
var singular =
|
|
1094
|
+
var { group, version, kind: kind2 } = peprStoreGVK;
|
|
1095
|
+
var singular = kind2.toLocaleLowerCase();
|
|
1119
1096
|
var plural = `${singular}s`;
|
|
1120
1097
|
var name = `${plural}.${group}`;
|
|
1121
1098
|
var peprStoreCRD = {
|
|
@@ -1151,7 +1128,7 @@ var peprStoreCRD = {
|
|
|
1151
1128
|
names: {
|
|
1152
1129
|
plural,
|
|
1153
1130
|
singular,
|
|
1154
|
-
kind:
|
|
1131
|
+
kind: kind2
|
|
1155
1132
|
}
|
|
1156
1133
|
}
|
|
1157
1134
|
};
|
|
@@ -1178,8 +1155,8 @@ async function generateWebhookRules(assets, isMutateWebhook) {
|
|
|
1178
1155
|
continue;
|
|
1179
1156
|
}
|
|
1180
1157
|
const operations = [];
|
|
1181
|
-
if (event === "CREATEORUPDATE" /*
|
|
1182
|
-
operations.push("CREATE" /*
|
|
1158
|
+
if (event === "CREATEORUPDATE" /* CREATE_OR_UPDATE */) {
|
|
1159
|
+
operations.push("CREATE" /* CREATE */, "UPDATE" /* UPDATE */);
|
|
1183
1160
|
} else {
|
|
1184
1161
|
operations.push(event);
|
|
1185
1162
|
}
|
|
@@ -1256,12 +1233,12 @@ async function webhookConfig(assets, mutateOrValidate, timeoutSeconds = 10) {
|
|
|
1256
1233
|
// src/lib/assets/deploy.ts
|
|
1257
1234
|
async function deployImagePullSecret(imagePullSecret, name2) {
|
|
1258
1235
|
try {
|
|
1259
|
-
await (0,
|
|
1236
|
+
await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.Namespace).Get("pepr-system");
|
|
1260
1237
|
} catch {
|
|
1261
|
-
await (0,
|
|
1238
|
+
await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.Namespace).Apply(namespace());
|
|
1262
1239
|
}
|
|
1263
1240
|
try {
|
|
1264
|
-
await (0,
|
|
1241
|
+
await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.Secret).Apply(
|
|
1265
1242
|
{
|
|
1266
1243
|
apiVersion: "v1",
|
|
1267
1244
|
kind: "Secret",
|
|
@@ -1284,29 +1261,29 @@ async function deploy(assets, force, webhookTimeout) {
|
|
|
1284
1261
|
logger_default.info("Establishing connection to Kubernetes");
|
|
1285
1262
|
const { name: name2, host, path } = assets;
|
|
1286
1263
|
logger_default.info("Applying pepr-system namespace");
|
|
1287
|
-
await (0,
|
|
1264
|
+
await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.Namespace).Apply(namespace(assets.config.customLabels?.namespace));
|
|
1288
1265
|
const mutateWebhook = await webhookConfig(assets, "mutate", webhookTimeout);
|
|
1289
1266
|
if (mutateWebhook) {
|
|
1290
1267
|
logger_default.info("Applying mutating webhook");
|
|
1291
|
-
await (0,
|
|
1268
|
+
await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.MutatingWebhookConfiguration).Apply(mutateWebhook, { force });
|
|
1292
1269
|
} else {
|
|
1293
1270
|
logger_default.info("Mutating webhook not needed, removing if it exists");
|
|
1294
|
-
await (0,
|
|
1271
|
+
await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.MutatingWebhookConfiguration).Delete(name2);
|
|
1295
1272
|
}
|
|
1296
1273
|
const validateWebhook = await webhookConfig(assets, "validate", webhookTimeout);
|
|
1297
1274
|
if (validateWebhook) {
|
|
1298
1275
|
logger_default.info("Applying validating webhook");
|
|
1299
|
-
await (0,
|
|
1276
|
+
await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.ValidatingWebhookConfiguration).Apply(validateWebhook, { force });
|
|
1300
1277
|
} else {
|
|
1301
1278
|
logger_default.info("Validating webhook not needed, removing if it exists");
|
|
1302
|
-
await (0,
|
|
1279
|
+
await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.ValidatingWebhookConfiguration).Delete(name2);
|
|
1303
1280
|
}
|
|
1304
1281
|
logger_default.info("Applying the Pepr Store CRD if it doesn't exist");
|
|
1305
|
-
await (0,
|
|
1282
|
+
await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.CustomResourceDefinition).Apply(peprStoreCRD, { force });
|
|
1306
1283
|
if (host) {
|
|
1307
1284
|
return;
|
|
1308
1285
|
}
|
|
1309
|
-
const code = await
|
|
1286
|
+
const code = await import_fs2.promises.readFile(path);
|
|
1310
1287
|
const hash = import_crypto.default.createHash("sha256").update(code).digest("hex");
|
|
1311
1288
|
if (code.length < 1) {
|
|
1312
1289
|
throw new Error("No code provided");
|
|
@@ -1319,46 +1296,46 @@ async function setupRBAC(name2, capabilities, force, config) {
|
|
|
1319
1296
|
const { rbacMode, rbac } = config;
|
|
1320
1297
|
logger_default.info("Applying cluster role binding");
|
|
1321
1298
|
const crb = clusterRoleBinding(name2);
|
|
1322
|
-
await (0,
|
|
1299
|
+
await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.ClusterRoleBinding).Apply(crb, { force });
|
|
1323
1300
|
logger_default.info("Applying cluster role");
|
|
1324
1301
|
const cr = clusterRole(name2, capabilities, rbacMode, rbac);
|
|
1325
|
-
await (0,
|
|
1302
|
+
await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.ClusterRole).Apply(cr, { force });
|
|
1326
1303
|
logger_default.info("Applying service account");
|
|
1327
1304
|
const sa = serviceAccount(name2);
|
|
1328
|
-
await (0,
|
|
1305
|
+
await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.ServiceAccount).Apply(sa, { force });
|
|
1329
1306
|
logger_default.info("Applying store role");
|
|
1330
1307
|
const role = storeRole(name2);
|
|
1331
|
-
await (0,
|
|
1308
|
+
await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.Role).Apply(role, { force });
|
|
1332
1309
|
logger_default.info("Applying store role binding");
|
|
1333
1310
|
const roleBinding = storeRoleBinding(name2);
|
|
1334
|
-
await (0,
|
|
1311
|
+
await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.RoleBinding).Apply(roleBinding, { force });
|
|
1335
1312
|
}
|
|
1336
1313
|
async function setupController(assets, code, hash, force) {
|
|
1337
1314
|
const { name: name2 } = assets;
|
|
1338
1315
|
logger_default.info("Applying module secret");
|
|
1339
1316
|
const mod = moduleSecret(name2, code, hash);
|
|
1340
|
-
await (0,
|
|
1317
|
+
await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.Secret).Apply(mod, { force });
|
|
1341
1318
|
logger_default.info("Applying controller service");
|
|
1342
1319
|
const svc = service(name2);
|
|
1343
|
-
await (0,
|
|
1320
|
+
await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.Service).Apply(svc, { force });
|
|
1344
1321
|
logger_default.info("Applying TLS secret");
|
|
1345
1322
|
const tls = tlsSecret(name2, assets.tls);
|
|
1346
|
-
await (0,
|
|
1323
|
+
await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.Secret).Apply(tls, { force });
|
|
1347
1324
|
logger_default.info("Applying API token secret");
|
|
1348
1325
|
const apiToken = apiTokenSecret(name2, assets.apiToken);
|
|
1349
|
-
await (0,
|
|
1326
|
+
await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.Secret).Apply(apiToken, { force });
|
|
1350
1327
|
logger_default.info("Applying deployment");
|
|
1351
1328
|
const dep = deployment(assets, hash, assets.buildTimestamp);
|
|
1352
|
-
await (0,
|
|
1329
|
+
await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.Deployment).Apply(dep, { force });
|
|
1353
1330
|
}
|
|
1354
1331
|
async function setupWatcher(assets, hash, force) {
|
|
1355
1332
|
const watchDeployment = watcher(assets, hash, assets.buildTimestamp);
|
|
1356
1333
|
if (watchDeployment) {
|
|
1357
1334
|
logger_default.info("Applying watcher deployment");
|
|
1358
|
-
await (0,
|
|
1335
|
+
await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.Deployment).Apply(watchDeployment, { force });
|
|
1359
1336
|
logger_default.info("Applying watcher service");
|
|
1360
1337
|
const watchSvc = watcherService(assets.name);
|
|
1361
|
-
await (0,
|
|
1338
|
+
await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.Service).Apply(watchSvc, { force });
|
|
1362
1339
|
}
|
|
1363
1340
|
}
|
|
1364
1341
|
|
|
@@ -1390,7 +1367,7 @@ function loadCapabilities(path) {
|
|
|
1390
1367
|
// src/lib/assets/yaml.ts
|
|
1391
1368
|
var import_client_node = require("@kubernetes/client-node");
|
|
1392
1369
|
var import_crypto2 = __toESM(require("crypto"));
|
|
1393
|
-
var
|
|
1370
|
+
var import_fs3 = require("fs");
|
|
1394
1371
|
async function overridesFile({ hash, name: name2, image, config, apiToken, capabilities }, path) {
|
|
1395
1372
|
const rbacOverrides = clusterRole(name2, capabilities, config.rbacMode, config.rbac).rules;
|
|
1396
1373
|
const overrides = {
|
|
@@ -1541,7 +1518,7 @@ async function overridesFile({ hash, name: name2, image, config, apiToken, capab
|
|
|
1541
1518
|
}
|
|
1542
1519
|
}
|
|
1543
1520
|
};
|
|
1544
|
-
await
|
|
1521
|
+
await import_fs3.promises.writeFile(path, (0, import_client_node.dumpYaml)(overrides, { noRefs: true, forceQuotes: true }));
|
|
1545
1522
|
}
|
|
1546
1523
|
function zarfYaml({ name: name2, image, config }, path) {
|
|
1547
1524
|
const zarfCfg = {
|
|
@@ -1598,7 +1575,7 @@ function zarfYamlChart({ name: name2, image, config }, path) {
|
|
|
1598
1575
|
}
|
|
1599
1576
|
async function allYaml(assets, imagePullSecret) {
|
|
1600
1577
|
const { name: name2, tls, apiToken, path, config } = assets;
|
|
1601
|
-
const code = await
|
|
1578
|
+
const code = await import_fs3.promises.readFile(path);
|
|
1602
1579
|
assets.hash = import_crypto2.default.createHash("sha256").update(code).digest("hex");
|
|
1603
1580
|
const mutateWebhook = await webhookConfig(assets, "mutate", assets.config.webhookTimeout);
|
|
1604
1581
|
const validateWebhook = await webhookConfig(assets, "validate", assets.config.webhookTimeout);
|
|
@@ -1884,6 +1861,73 @@ function serviceMonitorTemplate(name2) {
|
|
|
1884
1861
|
|
|
1885
1862
|
// src/lib/assets/index.ts
|
|
1886
1863
|
var import_fs5 = require("fs");
|
|
1864
|
+
|
|
1865
|
+
// src/lib/filesystemService.ts
|
|
1866
|
+
var import_fs4 = require("fs");
|
|
1867
|
+
async function createDirectoryIfNotExists(path) {
|
|
1868
|
+
try {
|
|
1869
|
+
await import_fs4.promises.access(path);
|
|
1870
|
+
} catch (error) {
|
|
1871
|
+
if (error.code === "ENOENT") {
|
|
1872
|
+
await import_fs4.promises.mkdir(path, { recursive: true });
|
|
1873
|
+
} else {
|
|
1874
|
+
throw error;
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
// src/lib/assets/index.ts
|
|
1880
|
+
function toYaml(obj) {
|
|
1881
|
+
return (0, import_client_node2.dumpYaml)(obj, { noRefs: true });
|
|
1882
|
+
}
|
|
1883
|
+
function createWebhookYaml(assets, webhookConfiguration) {
|
|
1884
|
+
const yaml = toYaml(webhookConfiguration);
|
|
1885
|
+
return replaceString(
|
|
1886
|
+
replaceString(
|
|
1887
|
+
replaceString(yaml, assets.name, "{{ .Values.uuid }}"),
|
|
1888
|
+
assets.config.onError === "reject" ? "Fail" : "Ignore",
|
|
1889
|
+
"{{ .Values.admission.failurePolicy }}"
|
|
1890
|
+
),
|
|
1891
|
+
`${assets.config.webhookTimeout}` || "10",
|
|
1892
|
+
"{{ .Values.admission.webhookTimeout }}"
|
|
1893
|
+
);
|
|
1894
|
+
}
|
|
1895
|
+
function helmLayout(basePath, unique) {
|
|
1896
|
+
const helm = {
|
|
1897
|
+
dirs: {
|
|
1898
|
+
chart: (0, import_path.resolve)(`${basePath}/${unique}-chart`)
|
|
1899
|
+
},
|
|
1900
|
+
files: {}
|
|
1901
|
+
};
|
|
1902
|
+
helm.dirs = {
|
|
1903
|
+
...helm.dirs,
|
|
1904
|
+
charts: `${helm.dirs.chart}/charts`,
|
|
1905
|
+
tmpls: `${helm.dirs.chart}/templates`
|
|
1906
|
+
};
|
|
1907
|
+
helm.files = {
|
|
1908
|
+
...helm.files,
|
|
1909
|
+
valuesYaml: `${helm.dirs.chart}/values.yaml`,
|
|
1910
|
+
chartYaml: `${helm.dirs.chart}/Chart.yaml`,
|
|
1911
|
+
namespaceYaml: `${helm.dirs.tmpls}/namespace.yaml`,
|
|
1912
|
+
watcherServiceYaml: `${helm.dirs.tmpls}/watcher-service.yaml`,
|
|
1913
|
+
admissionServiceYaml: `${helm.dirs.tmpls}/admission-service.yaml`,
|
|
1914
|
+
mutationWebhookYaml: `${helm.dirs.tmpls}/mutation-webhook.yaml`,
|
|
1915
|
+
validationWebhookYaml: `${helm.dirs.tmpls}/validation-webhook.yaml`,
|
|
1916
|
+
admissionDeploymentYaml: `${helm.dirs.tmpls}/admission-deployment.yaml`,
|
|
1917
|
+
admissionServiceMonitorYaml: `${helm.dirs.tmpls}/admission-service-monitor.yaml`,
|
|
1918
|
+
watcherDeploymentYaml: `${helm.dirs.tmpls}/watcher-deployment.yaml`,
|
|
1919
|
+
watcherServiceMonitorYaml: `${helm.dirs.tmpls}/watcher-service-monitor.yaml`,
|
|
1920
|
+
tlsSecretYaml: `${helm.dirs.tmpls}/tls-secret.yaml`,
|
|
1921
|
+
apiTokenSecretYaml: `${helm.dirs.tmpls}/api-token-secret.yaml`,
|
|
1922
|
+
moduleSecretYaml: `${helm.dirs.tmpls}/module-secret.yaml`,
|
|
1923
|
+
storeRoleYaml: `${helm.dirs.tmpls}/store-role.yaml`,
|
|
1924
|
+
storeRoleBindingYaml: `${helm.dirs.tmpls}/store-role-binding.yaml`,
|
|
1925
|
+
clusterRoleYaml: `${helm.dirs.tmpls}/cluster-role.yaml`,
|
|
1926
|
+
clusterRoleBindingYaml: `${helm.dirs.tmpls}/cluster-role-binding.yaml`,
|
|
1927
|
+
serviceAccountYaml: `${helm.dirs.tmpls}/service-account.yaml`
|
|
1928
|
+
};
|
|
1929
|
+
return helm;
|
|
1930
|
+
}
|
|
1887
1931
|
var Assets = class {
|
|
1888
1932
|
constructor(config, path, host) {
|
|
1889
1933
|
this.config = config;
|
|
@@ -1921,82 +1965,48 @@ var Assets = class {
|
|
|
1921
1965
|
}
|
|
1922
1966
|
return allYaml(this, imagePullSecret);
|
|
1923
1967
|
};
|
|
1968
|
+
/* eslint max-statements: ["warn", 21] */
|
|
1924
1969
|
generateHelmChart = async (basePath) => {
|
|
1925
|
-
const
|
|
1926
|
-
const CHAR_TEMPLATES_DIR = `${CHART_DIR}/templates`;
|
|
1927
|
-
const valuesPath = (0, import_path.resolve)(CHART_DIR, `values.yaml`);
|
|
1928
|
-
const chartPath = (0, import_path.resolve)(CHART_DIR, `Chart.yaml`);
|
|
1929
|
-
const nsPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `namespace.yaml`);
|
|
1930
|
-
const watcherSVCPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `watcher-service.yaml`);
|
|
1931
|
-
const admissionSVCPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `admission-service.yaml`);
|
|
1932
|
-
const mutationWebhookPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `mutation-webhook.yaml`);
|
|
1933
|
-
const validationWebhookPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `validation-webhook.yaml`);
|
|
1934
|
-
const admissionDeployPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `admission-deployment.yaml`);
|
|
1935
|
-
const admissionServiceMonitorPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `admission-service-monitor.yaml`);
|
|
1936
|
-
const watcherDeployPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `watcher-deployment.yaml`);
|
|
1937
|
-
const watcherServiceMonitorPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `watcher-service-monitor.yaml`);
|
|
1938
|
-
const tlsSecretPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `tls-secret.yaml`);
|
|
1939
|
-
const apiTokenSecretPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `api-token-secret.yaml`);
|
|
1940
|
-
const moduleSecretPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `module-secret.yaml`);
|
|
1941
|
-
const storeRolePath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `store-role.yaml`);
|
|
1942
|
-
const storeRoleBindingPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `store-role-binding.yaml`);
|
|
1943
|
-
const clusterRolePath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `cluster-role.yaml`);
|
|
1944
|
-
const clusterRoleBindingPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `cluster-role-binding.yaml`);
|
|
1945
|
-
const serviceAccountPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `service-account.yaml`);
|
|
1970
|
+
const helm = helmLayout(basePath, this.config.uuid);
|
|
1946
1971
|
try {
|
|
1947
|
-
await
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
await overridesFile(this, valuesPath);
|
|
1951
|
-
await import_fs5.promises.writeFile(chartPath, dedent(chartYaml(this.config.uuid, this.config.description || "")));
|
|
1952
|
-
await import_fs5.promises.writeFile(nsPath, dedent(nsTemplate()));
|
|
1972
|
+
await Promise.all(
|
|
1973
|
+
Object.values(helm.dirs).sort((l, r) => l.split("/").length - r.split("/").length).map(async (dir) => await createDirectoryIfNotExists(dir))
|
|
1974
|
+
);
|
|
1953
1975
|
const code = await import_fs5.promises.readFile(this.path);
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1976
|
+
const pairs = [
|
|
1977
|
+
[helm.files.chartYaml, () => dedent(chartYaml(this.config.uuid, this.config.description || ""))],
|
|
1978
|
+
[helm.files.namespaceYaml, () => dedent(nsTemplate())],
|
|
1979
|
+
[helm.files.watcherServiceYaml, () => toYaml(watcherService(this.name))],
|
|
1980
|
+
[helm.files.admissionServiceYaml, () => toYaml(service(this.name))],
|
|
1981
|
+
[helm.files.tlsSecretYaml, () => toYaml(tlsSecret(this.name, this.tls))],
|
|
1982
|
+
[helm.files.apiTokenSecretYaml, () => toYaml(apiTokenSecret(this.name, this.apiToken))],
|
|
1983
|
+
[helm.files.storeRoleYaml, () => toYaml(storeRole(this.name))],
|
|
1984
|
+
[helm.files.storeRoleBindingYaml, () => toYaml(storeRoleBinding(this.name))],
|
|
1985
|
+
[helm.files.clusterRoleYaml, () => dedent(clusterRoleTemplate())],
|
|
1986
|
+
[helm.files.clusterRoleBindingYaml, () => toYaml(clusterRoleBinding(this.name))],
|
|
1987
|
+
[helm.files.serviceAccountYaml, () => toYaml(serviceAccount(this.name))],
|
|
1988
|
+
[helm.files.moduleSecretYaml, () => toYaml(moduleSecret(this.name, code, this.hash))]
|
|
1989
|
+
];
|
|
1990
|
+
await Promise.all(pairs.map(async ([file, content]) => await import_fs5.promises.writeFile(file, content())));
|
|
1991
|
+
await overridesFile(this, helm.files.valuesYaml);
|
|
1992
|
+
const [mutateWebhook, validateWebhook] = await Promise.all([
|
|
1993
|
+
webhookConfig(this, "mutate", this.config.webhookTimeout),
|
|
1994
|
+
webhookConfig(this, "validate", this.config.webhookTimeout)
|
|
1995
|
+
]);
|
|
1967
1996
|
if (validateWebhook || mutateWebhook) {
|
|
1968
|
-
await import_fs5.promises.writeFile(
|
|
1969
|
-
await import_fs5.promises.writeFile(
|
|
1997
|
+
await import_fs5.promises.writeFile(helm.files.admissionDeploymentYaml, dedent(admissionDeployTemplate(this.buildTimestamp)));
|
|
1998
|
+
await import_fs5.promises.writeFile(helm.files.admissionServiceMonitorYaml, dedent(serviceMonitorTemplate("admission")));
|
|
1970
1999
|
}
|
|
1971
2000
|
if (mutateWebhook) {
|
|
1972
|
-
|
|
1973
|
-
const mutateWebhookTemplate = replaceString(
|
|
1974
|
-
replaceString(
|
|
1975
|
-
replaceString(yamlMutateWebhook, this.name, "{{ .Values.uuid }}"),
|
|
1976
|
-
this.config.onError === "reject" ? "Fail" : "Ignore",
|
|
1977
|
-
"{{ .Values.admission.failurePolicy }}"
|
|
1978
|
-
),
|
|
1979
|
-
`${this.config.webhookTimeout}` || "10",
|
|
1980
|
-
"{{ .Values.admission.webhookTimeout }}"
|
|
1981
|
-
);
|
|
1982
|
-
await import_fs5.promises.writeFile(mutationWebhookPath, mutateWebhookTemplate);
|
|
2001
|
+
await import_fs5.promises.writeFile(helm.files.mutationWebhookYaml, createWebhookYaml(this, mutateWebhook));
|
|
1983
2002
|
}
|
|
1984
2003
|
if (validateWebhook) {
|
|
1985
|
-
|
|
1986
|
-
const validateWebhookTemplate = replaceString(
|
|
1987
|
-
replaceString(
|
|
1988
|
-
replaceString(yamlValidateWebhook, this.name, "{{ .Values.uuid }}"),
|
|
1989
|
-
this.config.onError === "reject" ? "Fail" : "Ignore",
|
|
1990
|
-
"{{ .Values.admission.failurePolicy }}"
|
|
1991
|
-
),
|
|
1992
|
-
`${this.config.webhookTimeout}` || "10",
|
|
1993
|
-
"{{ .Values.admission.webhookTimeout }}"
|
|
1994
|
-
);
|
|
1995
|
-
await import_fs5.promises.writeFile(validationWebhookPath, validateWebhookTemplate);
|
|
2004
|
+
await import_fs5.promises.writeFile(helm.files.validationWebhookYaml, createWebhookYaml(this, validateWebhook));
|
|
1996
2005
|
}
|
|
2006
|
+
const watchDeployment = watcher(this, this.hash, this.buildTimestamp);
|
|
1997
2007
|
if (watchDeployment) {
|
|
1998
|
-
await import_fs5.promises.writeFile(
|
|
1999
|
-
await import_fs5.promises.writeFile(
|
|
2008
|
+
await import_fs5.promises.writeFile(helm.files.watcherDeploymentYaml, dedent(watcherDeployTemplate(this.buildTimestamp)));
|
|
2009
|
+
await import_fs5.promises.writeFile(helm.files.watcherServiceMonitorYaml, dedent(serviceMonitorTemplate("watcher")));
|
|
2000
2010
|
}
|
|
2001
2011
|
} catch (err) {
|
|
2002
2012
|
console.error(`Error generating helm chart: ${err.message}`);
|
|
@@ -2211,8 +2221,8 @@ var hello_pepr_samples_default = [
|
|
|
2211
2221
|
var gitIgnore = "# Ignore node_modules and Pepr build artifacts\nnode_modules\ndist\ninsecure*\n";
|
|
2212
2222
|
var readmeMd = '# Pepr Module\n\nThis is a Pepr Module. [Pepr](https://github.com/defenseunicorns/pepr) is a type-safe Kubernetes middleware system.\n\nThe `capabilities` directory contains all the capabilities for this module. By default,\na capability is a single typescript file in the format of `capability-name.ts` that is\nimported in the root `pepr.ts` file as `import { HelloPepr } from "./capabilities/hello-pepr";`.\nBecause this is typescript, you can organize this however you choose, e.g. creating a sub-folder\nper-capability or common logic in shared files or folders.\n\nExample Structure:\n\n```\nModule Root\n\u251C\u2500\u2500 package.json\n\u251C\u2500\u2500 pepr.ts\n\u2514\u2500\u2500 capabilities\n \u251C\u2500\u2500 example-one.ts\n \u251C\u2500\u2500 example-three.ts\n \u2514\u2500\u2500 example-two.ts\n```\n';
|
|
2213
2223
|
var peprTS = 'import { PeprModule } from "pepr";\n// cfg loads your pepr configuration from package.json\nimport cfg from "./package.json";\n\n// HelloPepr is a demo capability that is included with Pepr. Comment or delete the line below to remove it.\nimport { HelloPepr } from "./capabilities/hello-pepr";\n\n/**\n * This is the main entrypoint for this Pepr module. It is run when the module is started.\n * This is where you register your Pepr configurations and capabilities.\n */\nnew PeprModule(cfg, [\n // "HelloPepr" is a demo capability that is included with Pepr. Comment or delete the line below to remove it.\n HelloPepr,\n\n // Your additional capabilities go here\n]);\n';
|
|
2214
|
-
var helloPeprTS = 'import {\n Capability,\n K8s,\n Log,\n PeprMutateRequest,\n RegisterKind,\n a,\n fetch,\n fetchStatus,\n kind,\n} from "pepr";\nimport nock from "nock";\n\n/**\n * The HelloPepr Capability is an example capability to demonstrate some general concepts of Pepr.\n * To test this capability you run `pepr dev`and then run the following command:\n * `kubectl apply -f capabilities/hello-pepr.samples.yaml`\n */\nexport const HelloPepr = new Capability({\n name: "hello-pepr",\n description: "A simple example capability to show how things work.",\n namespaces: ["pepr-demo", "pepr-demo-2"],\n});\n\n// Use the \'When\' function to create a new action, use \'Store\' to persist data\nconst { When, Store } = HelloPepr;\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (Namespace) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action removes the label `remove-me` when a Namespace is created.\n * Note we don\'t need to specify the namespace here, because we\'ve already specified\n * it in the Capability definition above.\n */\nWhen(a.Namespace)\n .IsCreated()\n .Mutate(ns => ns.RemoveLabel("remove-me"));\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Watch Action with K8s SSA (Namespace) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action watches for the `pepr-demo-2` namespace to be created, then creates a ConfigMap with\n * the name `pepr-ssa-demo` and adds the namespace UID to the ConfigMap data. Because Pepr uses\n * server-side apply for this operation, the ConfigMap will be created or updated if it already exists.\n */\nWhen(a.Namespace)\n .IsCreated()\n .WithName("pepr-demo-2")\n .Watch(async ns => {\n Log.info("Namespace pepr-demo-2 was created.");\n\n try {\n // Apply the ConfigMap using K8s server-side apply\n await K8s(kind.ConfigMap).Apply({\n metadata: {\n name: "pepr-ssa-demo",\n namespace: "pepr-demo-2",\n },\n data: {\n "ns-uid": ns.metadata.uid,\n },\n });\n } catch (error) {\n // You can use the Log object to log messages to the Pepr controller pod\n Log.error(error, "Failed to apply ConfigMap using server-side apply.");\n }\n\n // You can share data between actions using the Store, including between different types of actions\n Store.setItem("watch-data", "This data was stored by a Watch Action.");\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 1) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This is a single action. They can be in the same file or put imported from other files.\n * In this example, when a ConfigMap is created with the name `example-1`, then add a label and annotation.\n *\n * Equivalent to manually running:\n * `kubectl label configmap example-1 pepr=was-here`\n * `kubectl annotate configmap example-1 pepr.dev=annotations-work-too`\n */\nWhen(a.ConfigMap)\n .IsCreated()\n .WithName("example-1")\n .Mutate(request => {\n request\n .SetLabel("pepr", "was-here")\n .SetAnnotation("pepr.dev", "annotations-work-too");\n\n // Use the Store to persist data between requests and Pepr controller pods\n Store.setItem("example-1", "was-here");\n\n // This data is written asynchronously and can be read back via `Store.getItem()` or `Store.subscribe()`\n Store.setItem("example-1-data", JSON.stringify(request.Raw.data));\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate & Validate Actions (CM Example 2) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This combines 3 different types of actions: \'Mutate\', \'Validate\', and \'Watch\'. The order\n * of the actions is required, but each action is optional. In this example, when a ConfigMap is created\n * with the name `example-2`, then add a label and annotation, validate that the ConfigMap has the label\n * `pepr`, and log the request.\n */\nWhen(a.ConfigMap)\n .IsCreated()\n .WithName("example-2")\n .Mutate(request => {\n // This Mutate Action will mutate the request before it is persisted to the cluster\n\n // Use `request.Merge()` to merge the new data with the existing data\n request.Merge({\n metadata: {\n labels: {\n pepr: "was-here",\n },\n annotations: {\n "pepr.dev": "annotations-work-too",\n },\n },\n });\n })\n .Validate(request => {\n // This Validate Action will validate the request before it is persisted to the cluster\n\n // Approve the request if the ConfigMap has the label \'pepr\'\n if (request.HasLabel("pepr")) {\n return request.Approve();\n }\n\n // Otherwise, deny the request with an error message (optional)\n return request.Deny("ConfigMap must have label \'pepr\'");\n })\n .Watch((cm, phase) => {\n // This Watch Action will watch the ConfigMap after it has been persisted to the cluster\n Log.info(cm, `ConfigMap was ${phase} with the name example-2`);\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 2a) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action shows a simple validation that will deny any ConfigMap that has the\n * annotation `evil`. Note that the `Deny()` function takes an optional second parameter that is a\n * user-defined status code to return.\n */\nWhen(a.ConfigMap)\n .IsCreated()\n .Validate(request => {\n if (request.HasAnnotation("evil")) {\n return request.Deny("No evil CM annotations allowed.", 400);\n }\n\n return request.Approve();\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 3) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action combines different styles. Unlike the previous actions, this one will look\n * for any ConfigMap in the `pepr-demo` namespace that has the label `change=by-label` during either\n * CREATE or UPDATE. Note that all conditions added such as `WithName()`, `WithLabel()`, `InNamespace()`,\n * are ANDs so all conditions must be true for the request to be processed.\n */\nWhen(a.ConfigMap)\n .IsCreatedOrUpdated()\n .WithLabel("change", "by-label")\n .Mutate(request => {\n // The K8s object e are going to mutate\n const cm = request.Raw;\n\n // Get the username and uid of the K8s request\n const { username, uid } = request.Request.userInfo;\n\n // Store some data about the request in the configmap\n cm.data["username"] = username;\n cm.data["uid"] = uid;\n\n // You can still mix other ways of making changes too\n request.SetAnnotation("pepr.dev", "making-waves");\n });\n\n// This action validates the label `change=by-label` is deleted\nWhen(a.ConfigMap)\n .IsDeleted()\n .WithLabel("change", "by-label")\n .Validate(request => {\n // Log and then always approve the request\n Log.info("CM with label \'change=by-label\' was deleted.");\n return request.Approve();\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 4) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action show how you can use the `Mutate()` function without an inline function.\n * This is useful if you want to keep your actions small and focused on a single task,\n * or if you want to reuse the same function in multiple actions.\n */\nWhen(a.ConfigMap).IsCreated().WithName("example-4").Mutate(example4Cb);\n\n// This function uses the complete type definition, but is not required.\nfunction example4Cb(cm: PeprMutateRequest<a.ConfigMap>) {\n cm.SetLabel("pepr.dev/first", "true");\n cm.SetLabel("pepr.dev/second", "true");\n cm.SetLabel("pepr.dev/third", "true");\n}\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 4a) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This is the same as Example 4, except this only operates on a CM in the `pepr-demo-2` namespace.\n * Note because the Capability defines namespaces, the namespace specified here must be one of those.\n * Alternatively, you can remove the namespace from the Capability definition and specify it here.\n */\nWhen(a.ConfigMap)\n .IsCreated()\n .InNamespace("pepr-demo-2")\n .WithName("example-4a")\n .Mutate(example4Cb);\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 5) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action is a bit more complex. It will look for any ConfigMap in the `pepr-demo`\n * namespace that has the label `chuck-norris` during CREATE. When it finds one, it will fetch a\n * random Chuck Norris joke from the API and add it to the ConfigMap. This is a great example of how\n * you can use Pepr to make changes to your K8s objects based on external data.\n *\n * Note the use of the `async` keyword. This is required for any action that uses `await` or `fetch()`.\n *\n * Also note we are passing a type to the `fetch()` function. This is optional, but it will help you\n * avoid mistakes when working with the data returned from the API. You can also use the `as` keyword to\n * cast the data returned from the API.\n *\n * These are equivalent:\n * ```ts\n * const joke = await fetch<TheChuckNorrisJoke>("https://icanhazdadjoke.com/");\n * const joke = await fetch("https://icanhazdadjoke.com/") as TheChuckNorrisJoke;\n * ```\n *\n * Alternatively, you can drop the type completely:\n *\n * ```ts\n * fetch("https://icanhazdadjoke.com")\n * ```\n */\ninterface TheChuckNorrisJoke {\n id: string;\n joke: string;\n status: number;\n}\n\nWhen(a.ConfigMap)\n .IsCreatedOrUpdated()\n .WithLabel("chuck-norris")\n .Mutate(cm => cm.SetLabel("got-jokes", "true"))\n .Watch(async cm => {\n const jokeURL = "https://icanhazdadjoke.com/";\n\n // Set up Nock to mock the API calls globally with header matching\n nock(jokeURL).get("/").reply(200, {\n id: "R7UfaahVfFd",\n joke: "Funny joke goes here.",\n status: 200,\n });\n\n // Try/catch is not needed as a response object will always be returned\n const response = await fetch<TheChuckNorrisJoke>(jokeURL, {\n headers: {\n Accept: "application/json",\n },\n });\n\n // Instead, check the `response.ok` field\n if (response.ok) {\n const { joke } = response.data;\n // Add Joke to the Store\n await Store.setItemAndWait(jokeURL, joke);\n // Add the Chuck Norris joke to the configmap\n try {\n await K8s(kind.ConfigMap).Apply({\n metadata: {\n name: cm.metadata.name,\n namespace: cm.metadata.namespace,\n },\n data: {\n "chuck-says": Store.getItem(jokeURL),\n },\n });\n } catch (error) {\n Log.error(error, "Failed to apply ConfigMap using server-side apply.", {\n cm,\n });\n }\n }\n\n // You can also assert on different HTTP response codes\n if (response.status === fetchStatus.NOT_FOUND) {\n // Do something else\n return;\n }\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (Secret Base64 Handling) *\n * ---------------------------------------------------------------------------------------------------\n *\n * The K8s JS client provides incomplete support for base64 encoding/decoding handling for secrets,\n * unlike the GO client. To make this less painful, Pepr automatically handles base64 encoding/decoding\n * secret data before and after the action is executed.\n */\nWhen(a.Secret)\n .IsCreated()\n .WithName("secret-1")\n .Mutate(request => {\n const secret = request.Raw;\n\n // This will be encoded at the end of all processing back to base64: "Y2hhbmdlLXdpdGhvdXQtZW5jb2Rpbmc="\n secret.data.magic = "change-without-encoding";\n\n // You can modify the data directly, and it will be encoded at the end of all processing\n secret.data.example += " - modified by Pepr";\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (Untyped Custom Resource) *\n * ---------------------------------------------------------------------------------------------------\n *\n * Out of the box, Pepr supports all the standard Kubernetes objects. However, you can also create\n * your own types. This is useful if you are working with an Operator that creates custom resources.\n * There are two ways to do this, the first is to use the `When()` function with a `GenericKind`,\n * the second is to create a new class that extends `GenericKind` and use the `RegisterKind()` function.\n *\n * This example shows how to use the `When()` function with a `GenericKind`. Note that you\n * must specify the `group`, `version`, and `kind` of the object (if applicable). This is how Pepr knows\n * if the action should be triggered or not. Since we are using a `GenericKind`,\n * Pepr will not be able to provide any intellisense for the object, so you will need to refer to the\n * Kubernetes API documentation for the object you are working with.\n *\n * You will need to wait for the CRD in `hello-pepr.samples.yaml` to be created, then you can apply\n *\n * ```yaml\n * apiVersion: pepr.dev/v1\n * kind: Unicorn\n * metadata:\n * name: example-1\n * namespace: pepr-demo\n * spec:\n * message: replace-me\n * counter: 0\n * ```\n */\nWhen(a.GenericKind, {\n group: "pepr.dev",\n version: "v1",\n kind: "Unicorn",\n})\n .IsCreated()\n .WithName("example-1")\n .Mutate(request => {\n request.Merge({\n spec: {\n message: "Hello Pepr without type data!",\n counter: Math.random(),\n },\n });\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (Typed Custom Resource) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This example shows how to use the `RegisterKind()` function to create a new type. This is useful\n * if you are working with an Operator that creates custom resources and you want to have intellisense\n * for the object. Note that you must specify the `group`, `version`, and `kind` of the object (if applicable)\n * as this is how Pepr knows if the action should be triggered or not.\n *\n * Once you register a new Kind with Pepr, you can use the `When()` function with the new Kind. Ideally,\n * you should register custom Kinds at the top of your Capability file or Pepr Module so they are available\n * to all actions, but we are putting it here for demonstration purposes.\n *\n * You will need to wait for the CRD in `hello-pepr.samples.yaml` to be created, then you can apply\n *\n * ```yaml\n * apiVersion: pepr.dev/v1\n * kind: Unicorn\n * metadata:\n * name: example-2\n * namespace: pepr-demo\n * spec:\n * message: replace-me\n * counter: 0\n * ```*\n */\nclass UnicornKind extends a.GenericKind {\n spec: {\n /**\n * JSDoc comments can be added to explain more details about the field.\n *\n * @example\n * ```ts\n * request.Raw.spec.message = "Hello Pepr!";\n * ```\n * */\n message: string;\n counter: number;\n };\n}\n\nRegisterKind(UnicornKind, {\n group: "pepr.dev",\n version: "v1",\n kind: "Unicorn",\n});\n\nWhen(UnicornKind)\n .IsCreated()\n .WithName("example-2")\n .Mutate(request => {\n request.Merge({\n spec: {\n message: "Hello Pepr with type data!",\n counter: Math.random(),\n },\n });\n });\n\n/**\n * A callback function that is called once the Pepr Store is fully loaded.\n */\nStore.onReady(data => {\n Log.info(data, "Pepr Store Ready");\n});\n';
|
|
2215
|
-
var packageJSON = { name: "pepr", description: "Kubernetes application engine", author: "Defense Unicorns", homepage: "https://github.com/defenseunicorns/pepr", license: "Apache-2.0", bin: "dist/cli.js", repository: "defenseunicorns/pepr", engines: { node: ">=18.0.0" }, files: ["/dist", "/src", "!src/**/*.test.ts", "!dist/**/*.test.d.ts*"], version: "0.
|
|
2224
|
+
var helloPeprTS = 'import {\n Capability,\n K8s,\n Log,\n PeprMutateRequest,\n RegisterKind,\n a,\n fetch,\n fetchStatus,\n kind,\n} from "pepr";\nimport { MockAgent, setGlobalDispatcher } from "undici";\n\n/**\n * The HelloPepr Capability is an example capability to demonstrate some general concepts of Pepr.\n * To test this capability you run `pepr dev`and then run the following command:\n * `kubectl apply -f capabilities/hello-pepr.samples.yaml`\n */\nexport const HelloPepr = new Capability({\n name: "hello-pepr",\n description: "A simple example capability to show how things work.",\n namespaces: ["pepr-demo", "pepr-demo-2"],\n});\n\n// Use the \'When\' function to create a new action, use \'Store\' to persist data\nconst { When, Store } = HelloPepr;\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (Namespace) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action removes the label `remove-me` when a Namespace is created.\n * Note we don\'t need to specify the namespace here, because we\'ve already specified\n * it in the Capability definition above.\n */\nWhen(a.Namespace)\n .IsCreated()\n .Mutate(ns => ns.RemoveLabel("remove-me"));\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Watch Action with K8s SSA (Namespace) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action watches for the `pepr-demo-2` namespace to be created, then creates a ConfigMap with\n * the name `pepr-ssa-demo` and adds the namespace UID to the ConfigMap data. Because Pepr uses\n * server-side apply for this operation, the ConfigMap will be created or updated if it already exists.\n */\nWhen(a.Namespace)\n .IsCreated()\n .WithName("pepr-demo-2")\n .Watch(async ns => {\n Log.info("Namespace pepr-demo-2 was created.");\n\n try {\n // Apply the ConfigMap using K8s server-side apply\n await K8s(kind.ConfigMap).Apply({\n metadata: {\n name: "pepr-ssa-demo",\n namespace: "pepr-demo-2",\n },\n data: {\n "ns-uid": ns.metadata.uid,\n },\n });\n } catch (error) {\n // You can use the Log object to log messages to the Pepr controller pod\n Log.error(error, "Failed to apply ConfigMap using server-side apply.");\n }\n\n // You can share data between actions using the Store, including between different types of actions\n Store.setItem("watch-data", "This data was stored by a Watch Action.");\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 1) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This is a single action. They can be in the same file or put imported from other files.\n * In this example, when a ConfigMap is created with the name `example-1`, then add a label and annotation.\n *\n * Equivalent to manually running:\n * `kubectl label configmap example-1 pepr=was-here`\n * `kubectl annotate configmap example-1 pepr.dev=annotations-work-too`\n */\nWhen(a.ConfigMap)\n .IsCreated()\n .WithName("example-1")\n .Mutate(request => {\n request\n .SetLabel("pepr", "was-here")\n .SetAnnotation("pepr.dev", "annotations-work-too");\n\n // Use the Store to persist data between requests and Pepr controller pods\n Store.setItem("example-1", "was-here");\n\n // This data is written asynchronously and can be read back via `Store.getItem()` or `Store.subscribe()`\n Store.setItem("example-1-data", JSON.stringify(request.Raw.data));\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate & Validate Actions (CM Example 2) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This combines 3 different types of actions: \'Mutate\', \'Validate\', and \'Watch\'. The order\n * of the actions is required, but each action is optional. In this example, when a ConfigMap is created\n * with the name `example-2`, then add a label and annotation, validate that the ConfigMap has the label\n * `pepr`, and log the request.\n */\nWhen(a.ConfigMap)\n .IsCreated()\n .WithName("example-2")\n .Mutate(request => {\n // This Mutate Action will mutate the request before it is persisted to the cluster\n\n // Use `request.Merge()` to merge the new data with the existing data\n request.Merge({\n metadata: {\n labels: {\n pepr: "was-here",\n },\n annotations: {\n "pepr.dev": "annotations-work-too",\n },\n },\n });\n })\n .Validate(request => {\n // This Validate Action will validate the request before it is persisted to the cluster\n\n // Approve the request if the ConfigMap has the label \'pepr\'\n if (request.HasLabel("pepr")) {\n return request.Approve();\n }\n\n // Otherwise, deny the request with an error message (optional)\n return request.Deny("ConfigMap must have label \'pepr\'");\n })\n .Watch((cm, phase) => {\n // This Watch Action will watch the ConfigMap after it has been persisted to the cluster\n Log.info(cm, `ConfigMap was ${phase} with the name example-2`);\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 2a) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action shows a simple validation that will deny any ConfigMap that has the\n * annotation `evil`. Note that the `Deny()` function takes an optional second parameter that is a\n * user-defined status code to return.\n */\nWhen(a.ConfigMap)\n .IsCreated()\n .Validate(request => {\n if (request.HasAnnotation("evil")) {\n return request.Deny("No evil CM annotations allowed.", 400);\n }\n\n return request.Approve();\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 3) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action combines different styles. Unlike the previous actions, this one will look\n * for any ConfigMap in the `pepr-demo` namespace that has the label `change=by-label` during either\n * CREATE or UPDATE. Note that all conditions added such as `WithName()`, `WithLabel()`, `InNamespace()`,\n * are ANDs so all conditions must be true for the request to be processed.\n */\nWhen(a.ConfigMap)\n .IsCreatedOrUpdated()\n .WithLabel("change", "by-label")\n .Mutate(request => {\n // The K8s object e are going to mutate\n const cm = request.Raw;\n\n // Get the username and uid of the K8s request\n const { username, uid } = request.Request.userInfo;\n\n // Store some data about the request in the configmap\n cm.data["username"] = username;\n cm.data["uid"] = uid;\n\n // You can still mix other ways of making changes too\n request.SetAnnotation("pepr.dev", "making-waves");\n });\n\n// This action validates the label `change=by-label` is deleted\nWhen(a.ConfigMap)\n .IsDeleted()\n .WithLabel("change", "by-label")\n .Validate(request => {\n // Log and then always approve the request\n Log.info("CM with label \'change=by-label\' was deleted.");\n return request.Approve();\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 4) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action show how you can use the `Mutate()` function without an inline function.\n * This is useful if you want to keep your actions small and focused on a single task,\n * or if you want to reuse the same function in multiple actions.\n */\nWhen(a.ConfigMap).IsCreated().WithName("example-4").Mutate(example4Cb);\n\n// This function uses the complete type definition, but is not required.\nfunction example4Cb(cm: PeprMutateRequest<a.ConfigMap>) {\n cm.SetLabel("pepr.dev/first", "true");\n cm.SetLabel("pepr.dev/second", "true");\n cm.SetLabel("pepr.dev/third", "true");\n}\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 4a) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This is the same as Example 4, except this only operates on a CM in the `pepr-demo-2` namespace.\n * Note because the Capability defines namespaces, the namespace specified here must be one of those.\n * Alternatively, you can remove the namespace from the Capability definition and specify it here.\n */\nWhen(a.ConfigMap)\n .IsCreated()\n .InNamespace("pepr-demo-2")\n .WithName("example-4a")\n .Mutate(example4Cb);\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 5) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action is a bit more complex. It will look for any ConfigMap in the `pepr-demo`\n * namespace that has the label `chuck-norris` during CREATE. When it finds one, it will fetch a\n * random Chuck Norris joke from the API and add it to the ConfigMap. This is a great example of how\n * you can use Pepr to make changes to your K8s objects based on external data.\n *\n * Note the use of the `async` keyword. This is required for any action that uses `await` or `fetch()`.\n *\n * Also note we are passing a type to the `fetch()` function. This is optional, but it will help you\n * avoid mistakes when working with the data returned from the API. You can also use the `as` keyword to\n * cast the data returned from the API.\n *\n * These are equivalent:\n * ```ts\n * const joke = await fetch<TheChuckNorrisJoke>("https://icanhazdadjoke.com/");\n * const joke = await fetch("https://icanhazdadjoke.com/") as TheChuckNorrisJoke;\n * ```\n *\n * Alternatively, you can drop the type completely:\n *\n * ```ts\n * fetch("https://icanhazdadjoke.com")\n * ```\n */\ninterface TheChuckNorrisJoke {\n id: string;\n joke: string;\n status: number;\n}\n\nWhen(a.ConfigMap)\n .IsCreatedOrUpdated()\n .WithLabel("chuck-norris")\n .Mutate(cm => cm.SetLabel("got-jokes", "true"))\n .Watch(async cm => {\n const jokeURL = "https://icanhazdadjoke.com";\n\n const mockAgent: MockAgent = new MockAgent();\n setGlobalDispatcher(mockAgent);\n const mockClient = mockAgent.get(jokeURL);\n mockClient.intercept({ path: "/", method: "GET" }).reply(\n 200,\n {\n id: "R7UfaahVfFd",\n joke: "Funny joke goes here.",\n status: 200,\n },\n {\n headers: {\n "Content-Type": "application/json; charset=utf-8",\n },\n },\n );\n\n // Try/catch is not needed as a response object will always be returned\n const response = await fetch<TheChuckNorrisJoke>(jokeURL, {\n headers: {\n Accept: "application/json",\n },\n });\n\n // Instead, check the `response.ok` field\n if (response.ok) {\n const { joke } = response.data;\n // Add Joke to the Store\n await Store.setItemAndWait(jokeURL, joke);\n // Add the Chuck Norris joke to the configmap\n try {\n await K8s(kind.ConfigMap).Apply({\n metadata: {\n name: cm.metadata.name,\n namespace: cm.metadata.namespace,\n },\n data: {\n "chuck-says": Store.getItem(jokeURL),\n },\n });\n } catch (error) {\n Log.error(error, "Failed to apply ConfigMap using server-side apply.", {\n cm,\n });\n }\n }\n\n // You can also assert on different HTTP response codes\n if (response.status === fetchStatus.NOT_FOUND) {\n // Do something else\n return;\n }\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (Secret Base64 Handling) *\n * ---------------------------------------------------------------------------------------------------\n *\n * The K8s JS client provides incomplete support for base64 encoding/decoding handling for secrets,\n * unlike the GO client. To make this less painful, Pepr automatically handles base64 encoding/decoding\n * secret data before and after the action is executed.\n */\nWhen(a.Secret)\n .IsCreated()\n .WithName("secret-1")\n .Mutate(request => {\n const secret = request.Raw;\n\n // This will be encoded at the end of all processing back to base64: "Y2hhbmdlLXdpdGhvdXQtZW5jb2Rpbmc="\n secret.data.magic = "change-without-encoding";\n\n // You can modify the data directly, and it will be encoded at the end of all processing\n secret.data.example += " - modified by Pepr";\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (Untyped Custom Resource) *\n * ---------------------------------------------------------------------------------------------------\n *\n * Out of the box, Pepr supports all the standard Kubernetes objects. However, you can also create\n * your own types. This is useful if you are working with an Operator that creates custom resources.\n * There are two ways to do this, the first is to use the `When()` function with a `GenericKind`,\n * the second is to create a new class that extends `GenericKind` and use the `RegisterKind()` function.\n *\n * This example shows how to use the `When()` function with a `GenericKind`. Note that you\n * must specify the `group`, `version`, and `kind` of the object (if applicable). This is how Pepr knows\n * if the action should be triggered or not. Since we are using a `GenericKind`,\n * Pepr will not be able to provide any intellisense for the object, so you will need to refer to the\n * Kubernetes API documentation for the object you are working with.\n *\n * You will need to wait for the CRD in `hello-pepr.samples.yaml` to be created, then you can apply\n *\n * ```yaml\n * apiVersion: pepr.dev/v1\n * kind: Unicorn\n * metadata:\n * name: example-1\n * namespace: pepr-demo\n * spec:\n * message: replace-me\n * counter: 0\n * ```\n */\nWhen(a.GenericKind, {\n group: "pepr.dev",\n version: "v1",\n kind: "Unicorn",\n})\n .IsCreated()\n .WithName("example-1")\n .Mutate(request => {\n request.Merge({\n spec: {\n message: "Hello Pepr without type data!",\n counter: Math.random(),\n },\n });\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (Typed Custom Resource) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This example shows how to use the `RegisterKind()` function to create a new type. This is useful\n * if you are working with an Operator that creates custom resources and you want to have intellisense\n * for the object. Note that you must specify the `group`, `version`, and `kind` of the object (if applicable)\n * as this is how Pepr knows if the action should be triggered or not.\n *\n * Once you register a new Kind with Pepr, you can use the `When()` function with the new Kind. Ideally,\n * you should register custom Kinds at the top of your Capability file or Pepr Module so they are available\n * to all actions, but we are putting it here for demonstration purposes.\n *\n * You will need to wait for the CRD in `hello-pepr.samples.yaml` to be created, then you can apply\n *\n * ```yaml\n * apiVersion: pepr.dev/v1\n * kind: Unicorn\n * metadata:\n * name: example-2\n * namespace: pepr-demo\n * spec:\n * message: replace-me\n * counter: 0\n * ```*\n */\nclass UnicornKind extends a.GenericKind {\n spec: {\n /**\n * JSDoc comments can be added to explain more details about the field.\n *\n * @example\n * ```ts\n * request.Raw.spec.message = "Hello Pepr!";\n * ```\n * */\n message: string;\n counter: number;\n };\n}\n\nRegisterKind(UnicornKind, {\n group: "pepr.dev",\n version: "v1",\n kind: "Unicorn",\n});\n\nWhen(UnicornKind)\n .IsCreated()\n .WithName("example-2")\n .Mutate(request => {\n request.Merge({\n spec: {\n message: "Hello Pepr with type data!",\n counter: Math.random(),\n },\n });\n });\n\n/**\n * A callback function that is called once the Pepr Store is fully loaded.\n */\nStore.onReady(data => {\n Log.info(data, "Pepr Store Ready");\n});\n';
|
|
2225
|
+
var packageJSON = { name: "pepr", description: "Kubernetes application engine", author: "Defense Unicorns", homepage: "https://github.com/defenseunicorns/pepr", license: "Apache-2.0", bin: "dist/cli.js", repository: "defenseunicorns/pepr", engines: { node: ">=18.0.0" }, files: ["/dist", "/src", "!src/**/*.test.ts", "!dist/**/*.test.d.ts*"], version: "0.42.0", main: "dist/lib.js", types: "dist/lib.d.ts", scripts: { ci: "npm ci", "gen-data-json": "node hack/build-template-data.js", prebuild: "rm -fr dist/* && npm run gen-data-json", version: "node scripts/set-version.js", build: "tsc && node build.mjs && npm pack", "build:image": "npm run build && docker buildx build --output type=docker --tag pepr:dev .", test: "npm run test:unit && npm run test:journey", "test:unit": "npm run gen-data-json && jest src --coverage --detectOpenHandles --coverageDirectory=./coverage --testPathIgnorePatterns='cosign.e2e.test.ts'", "test:journey": "npm run test:journey:k3d && npm run build && npm run test:journey:image && npm run test:journey:run", "test:journey:prep": "if [ ! -d ./pepr-upgrade-test ]; then git clone https://github.com/defenseunicorns/pepr-upgrade-test.git ; fi", "test:journey-wasm": "npm run test:journey:k3d && npm run build && npm run test:journey:image && npm run test:journey:run-wasm", "test:journey:k3d": "k3d cluster delete pepr-dev && k3d cluster create pepr-dev --k3s-arg '--debug@server:0' --wait && kubectl rollout status deployment -n kube-system", "test:journey:image": "docker buildx build --output type=docker --tag pepr:dev . && k3d image import pepr:dev -c pepr-dev", "test:journey:run": "jest --detectOpenHandles journey/entrypoint.test.ts && npm run test:journey:prep && npm run test:journey:upgrade", "test:journey:run-wasm": "jest --detectOpenHandles journey/entrypoint-wasm.test.ts", "test:journey:upgrade": "npm run test:journey:k3d && npm run test:journey:image && jest --detectOpenHandles journey/pepr-upgrade.test.ts", "format:check": "eslint src && prettier src --check", "format:fix": "eslint src --fix && prettier src --write", prepare: `if [ "$NODE_ENV" != 'production' ]; then husky; fi` }, dependencies: { "@types/ramda": "0.30.2", express: "4.21.2", "fast-json-patch": "3.1.1", "follow-redirects": "1.15.9", "http-status-codes": "^2.3.0", "json-pointer": "^0.6.2", "kubernetes-fluent-client": "3.3.7", pino: "9.5.0", "pino-pretty": "13.0.0", "prom-client": "15.1.3", ramda: "0.30.1", sigstore: "3.0.0" }, devDependencies: { "@commitlint/cli": "19.6.0", "@commitlint/config-conventional": "19.6.0", "@fast-check/jest": "^2.0.1", "@jest/globals": "29.7.0", "@types/eslint": "9.6.1", "@types/express": "5.0.0", "@types/follow-redirects": "1.14.4", "@types/json-pointer": "^1.0.34", "@types/node": "22.x.x", "@types/node-forge": "1.3.11", "@types/uuid": "10.0.0", "fast-check": "^3.19.0", husky: "^9.1.6", jest: "29.7.0", "js-yaml": "^4.1.0", "ts-jest": "29.2.5", undici: "^7.0.1" }, peerDependencies: { "@types/prompts": "2.4.9", "@typescript-eslint/eslint-plugin": "7.18.0", "@typescript-eslint/parser": "7.18.0", commander: "12.1.0", esbuild: "0.23.0", eslint: "8.57.0", "node-forge": "1.3.1", prettier: "3.3.3", prompts: "2.4.2", typescript: "5.3.3", uuid: "10.0.0" } };
|
|
2216
2226
|
|
|
2217
2227
|
// src/templates/pepr.code-snippets.json
|
|
2218
2228
|
var pepr_code_snippets_default = {
|
|
@@ -2339,7 +2349,7 @@ function genPkgJSON(opts, pgkVerOverride) {
|
|
|
2339
2349
|
},
|
|
2340
2350
|
dependencies: {
|
|
2341
2351
|
pepr: pgkVerOverride || version2,
|
|
2342
|
-
|
|
2352
|
+
undici: "^7.0.1"
|
|
2343
2353
|
},
|
|
2344
2354
|
devDependencies: {
|
|
2345
2355
|
typescript
|
|
@@ -2717,6 +2727,45 @@ async function buildModule(reloader, entryPoint = peprTS2, embed = true) {
|
|
|
2717
2727
|
|
|
2718
2728
|
// src/cli/deploy.ts
|
|
2719
2729
|
var import_prompts = __toESM(require("prompts"));
|
|
2730
|
+
|
|
2731
|
+
// src/lib/deploymentChecks.ts
|
|
2732
|
+
var import_kubernetes_fluent_client4 = require("kubernetes-fluent-client");
|
|
2733
|
+
async function checkDeploymentStatus(namespace2) {
|
|
2734
|
+
const deployments = await (0, import_kubernetes_fluent_client4.K8s)(import_kubernetes_fluent_client4.kind.Deployment).InNamespace(namespace2).Get();
|
|
2735
|
+
let status = false;
|
|
2736
|
+
let readyCount = 0;
|
|
2737
|
+
for (const deployment2 of deployments.items) {
|
|
2738
|
+
const readyReplicas = deployment2.status?.readyReplicas ? deployment2.status?.readyReplicas : 0;
|
|
2739
|
+
if (deployment2.status?.readyReplicas !== deployment2.spec?.replicas) {
|
|
2740
|
+
logger_default.info(
|
|
2741
|
+
`Waiting for deployment ${deployment2.metadata?.name} rollout to finish: ${readyReplicas} of ${deployment2.spec?.replicas} replicas are available`
|
|
2742
|
+
);
|
|
2743
|
+
} else {
|
|
2744
|
+
logger_default.info(
|
|
2745
|
+
`Deployment ${deployment2.metadata?.name} rolled out: ${readyReplicas} of ${deployment2.spec?.replicas} replicas are available`
|
|
2746
|
+
);
|
|
2747
|
+
readyCount++;
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2750
|
+
if (readyCount === deployments.items.length) {
|
|
2751
|
+
status = true;
|
|
2752
|
+
}
|
|
2753
|
+
return status;
|
|
2754
|
+
}
|
|
2755
|
+
async function namespaceDeploymentsReady(namespace2 = "pepr-system") {
|
|
2756
|
+
logger_default.info(`Checking ${namespace2} deployments status...`);
|
|
2757
|
+
let ready = false;
|
|
2758
|
+
while (!ready) {
|
|
2759
|
+
ready = await checkDeploymentStatus(namespace2);
|
|
2760
|
+
if (ready) {
|
|
2761
|
+
return ready;
|
|
2762
|
+
}
|
|
2763
|
+
await new Promise((resolve5) => setTimeout(resolve5, 1e3));
|
|
2764
|
+
}
|
|
2765
|
+
logger_default.info(`All ${namespace2} deployments are ready`);
|
|
2766
|
+
}
|
|
2767
|
+
|
|
2768
|
+
// src/cli/deploy.ts
|
|
2720
2769
|
function deploy_default(program2) {
|
|
2721
2770
|
program2.command("deploy").description("Deploy a Pepr Module").option("-i, --image [image]", "Override the image tag").option("--confirm", "Skip confirmation prompt").option("--pullSecret <name>", "Deploy imagePullSecret for Controller private registry").option("--docker-server <server>", "Docker server address").option("--docker-username <username>", "Docker registry username").option("--docker-email <email>", "Email for Docker registry").option("--docker-password <password>", "Password for Docker registry").option("--force", "Force deploy the module, override manager field").action(async (opts) => {
|
|
2722
2771
|
let imagePullSecret;
|