pepr 0.34.1 → 0.36.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/dist/cli/init/templates.d.ts +1 -0
- package/dist/cli/init/templates.d.ts.map +1 -1
- package/dist/cli.js +48 -23
- package/dist/controller.js +1 -1
- package/dist/lib/assets/helm.d.ts.map +1 -1
- package/dist/lib/assets/pods.d.ts.map +1 -1
- package/dist/lib/assets/yaml.d.ts.map +1 -1
- package/dist/lib/capability.d.ts.map +1 -1
- package/dist/lib/filter.d.ts.map +1 -1
- package/dist/lib/helpers.d.ts.map +1 -1
- package/dist/lib/logger.d.ts +1 -1
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/queue.d.ts +19 -3
- package/dist/lib/queue.d.ts.map +1 -1
- package/dist/lib/types.d.ts +3 -0
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/watch-processor.d.ts +10 -1
- package/dist/lib/watch-processor.d.ts.map +1 -1
- package/dist/lib.js +104 -32
- package/dist/lib.js.map +3 -3
- package/dist/sdk/sdk.d.ts +5 -3
- package/dist/sdk/sdk.d.ts.map +1 -1
- package/package.json +10 -10
- package/src/cli/init/templates.ts +1 -0
- package/src/lib/assets/helm.ts +4 -16
- package/src/lib/assets/pods.ts +4 -0
- package/src/lib/assets/yaml.ts +32 -0
- package/src/lib/capability.ts +9 -1
- package/src/lib/filter.test.ts +85 -1
- package/src/lib/filter.ts +9 -0
- package/src/lib/helpers.test.ts +34 -0
- package/src/lib/helpers.ts +5 -0
- package/src/lib/queue.test.ts +138 -44
- package/src/lib/queue.ts +48 -13
- package/src/lib/types.ts +3 -0
- package/src/lib/watch-processor.test.ts +101 -5
- package/src/lib/watch-processor.ts +49 -16
- package/src/sdk/sdk.test.ts +46 -13
- package/src/sdk/sdk.ts +15 -6
- package/src/templates/capabilities/hello-pepr.ts +9 -0
package/dist/lib.js
CHANGED
|
@@ -244,6 +244,12 @@ function shouldSkipRequest(binding, req, capabilityNamespaces) {
|
|
|
244
244
|
const srcObject = operation === "DELETE" /* DELETE */ ? req.oldObject : req.object;
|
|
245
245
|
const { metadata } = srcObject || {};
|
|
246
246
|
const combinedNamespaces = [...namespaces, ...capabilityNamespaces];
|
|
247
|
+
if (binding.event.includes("DELETE" /* Delete */) && binding.filters?.deletionTimestamp) {
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
if (binding.filters?.deletionTimestamp && !req.object.metadata?.deletionTimestamp) {
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
247
253
|
if (!binding.event.includes(operation) && !binding.event.includes("*" /* Any */)) {
|
|
248
254
|
return true;
|
|
249
255
|
}
|
|
@@ -1154,14 +1160,17 @@ async function writeEvent(cr, event, eventType, eventReason, reportingComponent,
|
|
|
1154
1160
|
reportingInstance
|
|
1155
1161
|
});
|
|
1156
1162
|
}
|
|
1157
|
-
function getOwnerRefFrom(
|
|
1158
|
-
const {
|
|
1163
|
+
function getOwnerRefFrom(customResource, blockOwnerDeletion, controller) {
|
|
1164
|
+
const { apiVersion, kind: kind4, metadata } = customResource;
|
|
1165
|
+
const { name, uid } = metadata;
|
|
1159
1166
|
return [
|
|
1160
1167
|
{
|
|
1161
|
-
apiVersion
|
|
1162
|
-
kind:
|
|
1168
|
+
apiVersion,
|
|
1169
|
+
kind: kind4,
|
|
1163
1170
|
uid,
|
|
1164
|
-
name
|
|
1171
|
+
name,
|
|
1172
|
+
...blockOwnerDeletion !== void 0 && { blockOwnerDeletion },
|
|
1173
|
+
...controller !== void 0 && { controller }
|
|
1165
1174
|
}
|
|
1166
1175
|
];
|
|
1167
1176
|
}
|
|
@@ -1189,6 +1198,9 @@ function checkOverlap(bindingFilters, objectFilters) {
|
|
|
1189
1198
|
return matchCount === Object.keys(bindingFilters).length;
|
|
1190
1199
|
}
|
|
1191
1200
|
function filterNoMatchReason(binding, obj, capabilityNamespaces) {
|
|
1201
|
+
if (binding.filters?.deletionTimestamp && !obj.metadata?.deletionTimestamp) {
|
|
1202
|
+
return `Ignoring Watch Callback: Object does not have a deletion timestamp.`;
|
|
1203
|
+
}
|
|
1192
1204
|
if (binding.kind && binding.kind.kind === "Namespace" && binding.filters && binding.filters.namespaces.length !== 0) {
|
|
1193
1205
|
return `Ignoring Watch Callback: Cannot use a namespace filter in a namespace object.`;
|
|
1194
1206
|
}
|
|
@@ -1223,27 +1235,49 @@ function filterNoMatchReason(binding, obj, capabilityNamespaces) {
|
|
|
1223
1235
|
}
|
|
1224
1236
|
|
|
1225
1237
|
// src/lib/queue.ts
|
|
1238
|
+
var import_node_crypto = require("node:crypto");
|
|
1226
1239
|
var Queue = class {
|
|
1240
|
+
#name;
|
|
1241
|
+
#uid;
|
|
1227
1242
|
#queue = [];
|
|
1228
1243
|
#pendingPromise = false;
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
this.#
|
|
1244
|
+
constructor(name) {
|
|
1245
|
+
this.#name = name;
|
|
1246
|
+
this.#uid = `${Date.now()}-${(0, import_node_crypto.randomBytes)(2).toString("hex")}`;
|
|
1232
1247
|
}
|
|
1233
|
-
|
|
1234
|
-
this.#
|
|
1248
|
+
label() {
|
|
1249
|
+
return { name: this.#name, uid: this.#uid };
|
|
1250
|
+
}
|
|
1251
|
+
stats() {
|
|
1252
|
+
return {
|
|
1253
|
+
queue: this.label(),
|
|
1254
|
+
stats: {
|
|
1255
|
+
length: this.#queue.length
|
|
1256
|
+
}
|
|
1257
|
+
};
|
|
1235
1258
|
}
|
|
1236
1259
|
/**
|
|
1237
1260
|
* Enqueue adds an item to the queue and returns a promise that resolves when the item is
|
|
1238
1261
|
* reconciled.
|
|
1239
1262
|
*
|
|
1240
1263
|
* @param item The object to reconcile
|
|
1264
|
+
* @param type The watch phase requested for reconcile
|
|
1265
|
+
* @param reconcile The callback to enqueue for reconcile
|
|
1241
1266
|
* @returns A promise that resolves when the object is reconciled
|
|
1242
1267
|
*/
|
|
1243
|
-
enqueue(item,
|
|
1244
|
-
|
|
1268
|
+
enqueue(item, phase, reconcile) {
|
|
1269
|
+
const note = {
|
|
1270
|
+
queue: this.label(),
|
|
1271
|
+
item: {
|
|
1272
|
+
name: item.metadata?.name,
|
|
1273
|
+
namespace: item.metadata?.namespace,
|
|
1274
|
+
resourceVersion: item.metadata?.resourceVersion
|
|
1275
|
+
}
|
|
1276
|
+
};
|
|
1277
|
+
logger_default.debug(note, "Enqueueing");
|
|
1245
1278
|
return new Promise((resolve, reject) => {
|
|
1246
|
-
this.#queue.push({ item,
|
|
1279
|
+
this.#queue.push({ item, phase, callback: reconcile, resolve, reject });
|
|
1280
|
+
logger_default.debug(this.stats(), "Queue stats - push");
|
|
1247
1281
|
return this.#dequeue();
|
|
1248
1282
|
});
|
|
1249
1283
|
}
|
|
@@ -1264,15 +1298,23 @@ var Queue = class {
|
|
|
1264
1298
|
}
|
|
1265
1299
|
try {
|
|
1266
1300
|
this.#pendingPromise = true;
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1301
|
+
const note = {
|
|
1302
|
+
queue: this.label(),
|
|
1303
|
+
item: {
|
|
1304
|
+
name: element.item.metadata?.name,
|
|
1305
|
+
namespace: element.item.metadata?.namespace,
|
|
1306
|
+
resourceVersion: element.item.metadata?.resourceVersion
|
|
1307
|
+
}
|
|
1308
|
+
};
|
|
1309
|
+
logger_default.debug(note, "Reconciling");
|
|
1310
|
+
await element.callback(element.item, element.phase);
|
|
1311
|
+
logger_default.debug(note, "Reconciled");
|
|
1271
1312
|
element.resolve();
|
|
1272
1313
|
} catch (e) {
|
|
1273
1314
|
logger_default.debug(`Error reconciling ${element.item.metadata.name}`, { error: e });
|
|
1274
1315
|
element.reject(e);
|
|
1275
1316
|
} finally {
|
|
1317
|
+
logger_default.debug(this.stats(), "Queue stats - shift");
|
|
1276
1318
|
logger_default.debug("Resetting pending promise and dequeuing");
|
|
1277
1319
|
this.#pendingPromise = false;
|
|
1278
1320
|
await this.#dequeue();
|
|
@@ -1281,11 +1323,35 @@ var Queue = class {
|
|
|
1281
1323
|
};
|
|
1282
1324
|
|
|
1283
1325
|
// src/lib/watch-processor.ts
|
|
1326
|
+
var queues = {};
|
|
1327
|
+
function queueKey(obj) {
|
|
1328
|
+
const options = ["kind", "kindNs", "kindNsName", "global"];
|
|
1329
|
+
const d3fault = "kind";
|
|
1330
|
+
let strat = process.env.PEPR_RECONCILE_STRATEGY || d3fault;
|
|
1331
|
+
strat = options.includes(strat) ? strat : d3fault;
|
|
1332
|
+
const ns = obj.metadata?.namespace ?? "cluster-scoped";
|
|
1333
|
+
const kind4 = obj.kind ?? "UnknownKind";
|
|
1334
|
+
const name = obj.metadata?.name ?? "Unnamed";
|
|
1335
|
+
const lookup = {
|
|
1336
|
+
kind: `${kind4}`,
|
|
1337
|
+
kindNs: `${kind4}/${ns}`,
|
|
1338
|
+
kindNsName: `${kind4}/${ns}/${name}`,
|
|
1339
|
+
global: "global"
|
|
1340
|
+
};
|
|
1341
|
+
return lookup[strat];
|
|
1342
|
+
}
|
|
1343
|
+
function getOrCreateQueue(obj) {
|
|
1344
|
+
const key = queueKey(obj);
|
|
1345
|
+
if (!queues[key]) {
|
|
1346
|
+
queues[key] = new Queue(key);
|
|
1347
|
+
}
|
|
1348
|
+
return queues[key];
|
|
1349
|
+
}
|
|
1284
1350
|
var watchCfg = {
|
|
1285
1351
|
resyncFailureMax: process.env.PEPR_RESYNC_FAILURE_MAX ? parseInt(process.env.PEPR_RESYNC_FAILURE_MAX, 10) : 5,
|
|
1286
1352
|
resyncDelaySec: process.env.PEPR_RESYNC_DELAY_SECONDS ? parseInt(process.env.PEPR_RESYNC_DELAY_SECONDS, 10) : 5,
|
|
1287
1353
|
lastSeenLimitSeconds: process.env.PEPR_LAST_SEEN_LIMIT_SECONDS ? parseInt(process.env.PEPR_LAST_SEEN_LIMIT_SECONDS, 10) : 300,
|
|
1288
|
-
relistIntervalSec: process.env.PEPR_RELIST_INTERVAL_SECONDS ? parseInt(process.env.PEPR_RELIST_INTERVAL_SECONDS, 10) :
|
|
1354
|
+
relistIntervalSec: process.env.PEPR_RELIST_INTERVAL_SECONDS ? parseInt(process.env.PEPR_RELIST_INTERVAL_SECONDS, 10) : 600
|
|
1289
1355
|
};
|
|
1290
1356
|
var eventToPhaseMap = {
|
|
1291
1357
|
["CREATE" /* Create */]: [import_types2.WatchPhase.Added],
|
|
@@ -1302,12 +1368,12 @@ function setupWatch(capabilities) {
|
|
|
1302
1368
|
async function runBinding(binding, capabilityNamespaces) {
|
|
1303
1369
|
const phaseMatch = eventToPhaseMap[binding.event] || eventToPhaseMap["*" /* Any */];
|
|
1304
1370
|
logger_default.debug({ watchCfg }, "Effective WatchConfig");
|
|
1305
|
-
const watchCallback = async (obj,
|
|
1306
|
-
if (phaseMatch.includes(
|
|
1371
|
+
const watchCallback = async (obj, phase) => {
|
|
1372
|
+
if (phaseMatch.includes(phase)) {
|
|
1307
1373
|
try {
|
|
1308
1374
|
const filterMatch = filterNoMatchReason(binding, obj, capabilityNamespaces);
|
|
1309
1375
|
if (filterMatch === "") {
|
|
1310
|
-
await binding.watchCallback?.(obj,
|
|
1376
|
+
await binding.watchCallback?.(obj, phase);
|
|
1311
1377
|
} else {
|
|
1312
1378
|
logger_default.debug(filterMatch);
|
|
1313
1379
|
}
|
|
@@ -1316,14 +1382,13 @@ async function runBinding(binding, capabilityNamespaces) {
|
|
|
1316
1382
|
}
|
|
1317
1383
|
}
|
|
1318
1384
|
};
|
|
1319
|
-
const
|
|
1320
|
-
|
|
1321
|
-
const watcher = (0, import_kubernetes_fluent_client5.K8s)(binding.model, binding.filters).Watch(async (obj, type) => {
|
|
1322
|
-
logger_default.debug(obj, `Watch event ${type} received`);
|
|
1385
|
+
const watcher = (0, import_kubernetes_fluent_client5.K8s)(binding.model, binding.filters).Watch(async (obj, phase) => {
|
|
1386
|
+
logger_default.debug(obj, `Watch event ${phase} received`);
|
|
1323
1387
|
if (binding.isQueue) {
|
|
1324
|
-
|
|
1388
|
+
const queue = getOrCreateQueue(obj);
|
|
1389
|
+
await queue.enqueue(obj, phase, watchCallback);
|
|
1325
1390
|
} else {
|
|
1326
|
-
await watchCallback(obj,
|
|
1391
|
+
await watchCallback(obj, phase);
|
|
1327
1392
|
}
|
|
1328
1393
|
}, watchCfg);
|
|
1329
1394
|
watcher.events.on(import_kubernetes_fluent_client5.WatchEvent.GIVE_UP, (err) => {
|
|
@@ -1359,8 +1424,8 @@ async function runBinding(binding, capabilityNamespaces) {
|
|
|
1359
1424
|
process.exit(1);
|
|
1360
1425
|
}
|
|
1361
1426
|
}
|
|
1362
|
-
function logEvent(
|
|
1363
|
-
const logMessage = `Watch event ${
|
|
1427
|
+
function logEvent(event, message = "", obj) {
|
|
1428
|
+
const logMessage = `Watch event ${event} received${message ? `. ${message}.` : "."}`;
|
|
1364
1429
|
if (obj) {
|
|
1365
1430
|
logger_default.debug(obj, logMessage);
|
|
1366
1431
|
} else {
|
|
@@ -1824,12 +1889,13 @@ var Capability = class {
|
|
|
1824
1889
|
name: "",
|
|
1825
1890
|
namespaces: [],
|
|
1826
1891
|
labels: {},
|
|
1827
|
-
annotations: {}
|
|
1892
|
+
annotations: {},
|
|
1893
|
+
deletionTimestamp: false
|
|
1828
1894
|
}
|
|
1829
1895
|
};
|
|
1830
1896
|
const bindings = this.#bindings;
|
|
1831
1897
|
const prefix = `${this.#name}: ${model.name}`;
|
|
1832
|
-
const commonChain = { WithLabel, WithAnnotation, Mutate, Validate, Watch, Reconcile };
|
|
1898
|
+
const commonChain = { WithLabel, WithAnnotation, WithDeletionTimestamp, Mutate, Validate, Watch, Reconcile };
|
|
1833
1899
|
const isNotEmpty = (value) => Object.keys(value).length > 0;
|
|
1834
1900
|
const log = (message, cbString) => {
|
|
1835
1901
|
const filteredObj = (0, import_ramda6.pickBy)(isNotEmpty, binding.filters);
|
|
@@ -1885,6 +1951,11 @@ var Capability = class {
|
|
|
1885
1951
|
binding.filters.namespaces.push(...namespaces);
|
|
1886
1952
|
return { ...commonChain, WithName };
|
|
1887
1953
|
}
|
|
1954
|
+
function WithDeletionTimestamp() {
|
|
1955
|
+
logger_default.debug("Add deletionTimestamp filter");
|
|
1956
|
+
binding.filters.deletionTimestamp = true;
|
|
1957
|
+
return commonChain;
|
|
1958
|
+
}
|
|
1888
1959
|
function WithName(name) {
|
|
1889
1960
|
logger_default.debug(`Add name filter ${name}`, prefix);
|
|
1890
1961
|
binding.filters.name = name;
|
|
@@ -1905,7 +1976,8 @@ var Capability = class {
|
|
|
1905
1976
|
return {
|
|
1906
1977
|
...commonChain,
|
|
1907
1978
|
InNamespace,
|
|
1908
|
-
WithName
|
|
1979
|
+
WithName,
|
|
1980
|
+
WithDeletionTimestamp
|
|
1909
1981
|
};
|
|
1910
1982
|
}
|
|
1911
1983
|
return {
|