pepr 0.27.0 → 0.28.1

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/lib.js CHANGED
@@ -31,26 +31,26 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var lib_exports = {};
32
32
  __export(lib_exports, {
33
33
  Capability: () => Capability,
34
- K8s: () => import_kubernetes_fluent_client5.K8s,
34
+ K8s: () => import_kubernetes_fluent_client6.K8s,
35
35
  Log: () => logger_default,
36
36
  PeprModule: () => PeprModule,
37
37
  PeprMutateRequest: () => PeprMutateRequest,
38
38
  PeprUtils: () => utils_exports,
39
39
  PeprValidateRequest: () => PeprValidateRequest,
40
40
  R: () => R,
41
- RegisterKind: () => import_kubernetes_fluent_client5.RegisterKind,
42
- a: () => import_kubernetes_fluent_client5.kind,
41
+ RegisterKind: () => import_kubernetes_fluent_client6.RegisterKind,
42
+ a: () => import_kubernetes_fluent_client6.kind,
43
43
  containers: () => containers,
44
- fetch: () => import_kubernetes_fluent_client5.fetch,
45
- fetchStatus: () => import_kubernetes_fluent_client5.fetchStatus,
46
- kind: () => import_kubernetes_fluent_client5.kind
44
+ fetch: () => import_kubernetes_fluent_client6.fetch,
45
+ fetchStatus: () => import_kubernetes_fluent_client6.fetchStatus,
46
+ kind: () => import_kubernetes_fluent_client6.kind
47
47
  });
48
48
  module.exports = __toCommonJS(lib_exports);
49
- var import_kubernetes_fluent_client5 = require("kubernetes-fluent-client");
49
+ var import_kubernetes_fluent_client6 = require("kubernetes-fluent-client");
50
50
  var R = __toESM(require("ramda"));
51
51
 
52
52
  // src/lib/capability.ts
53
- var import_kubernetes_fluent_client4 = require("kubernetes-fluent-client");
53
+ var import_kubernetes_fluent_client5 = require("kubernetes-fluent-client");
54
54
  var import_ramda6 = require("ramda");
55
55
 
56
56
  // src/lib/logger.ts
@@ -187,7 +187,7 @@ var peprStoreGVK = {
187
187
 
188
188
  // src/lib/filter.ts
189
189
  function shouldSkipRequest(binding, req, capabilityNamespaces) {
190
- const { group, kind: kind2, version } = binding.kind || {};
190
+ const { group, kind: kind3, version } = binding.kind || {};
191
191
  const { namespaces, labels, annotations, name } = binding.filters || {};
192
192
  const operation = req.operation.toUpperCase();
193
193
  const srcObject = operation === "DELETE" /* DELETE */ ? req.oldObject : req.object;
@@ -199,7 +199,7 @@ function shouldSkipRequest(binding, req, capabilityNamespaces) {
199
199
  if (name && name !== req.name) {
200
200
  return true;
201
201
  }
202
- if (kind2 !== req.kind.kind) {
202
+ if (kind3 !== req.kind.kind) {
203
203
  return true;
204
204
  }
205
205
  if (group && group !== req.kind.group) {
@@ -668,7 +668,7 @@ var PeprControllerStore = class {
668
668
  }
669
669
  };
670
670
  clearTimeout(this.#sendDebounce);
671
- this.#sendDebounce = setTimeout(debounced, debounceBackoff);
671
+ this.#sendDebounce = setTimeout(debounced, this.#onReady ? 0 : debounceBackoff);
672
672
  };
673
673
  #send = (capabilityName) => {
674
674
  const sendCache = {};
@@ -969,7 +969,7 @@ var Controller = class _Controller {
969
969
 
970
970
  // src/lib/watch-processor.ts
971
971
  var import_crypto = require("crypto");
972
- var import_kubernetes_fluent_client3 = require("kubernetes-fluent-client");
972
+ var import_kubernetes_fluent_client4 = require("kubernetes-fluent-client");
973
973
  var import_types2 = require("kubernetes-fluent-client/dist/fluent/types");
974
974
 
975
975
  // src/lib/queue.ts
@@ -1023,39 +1023,61 @@ var Queue = class {
1023
1023
  }
1024
1024
  };
1025
1025
 
1026
- // src/lib/watch-processor.ts
1027
- var storeUpdates = false;
1028
- var store = {};
1029
- async function setupStore(uuid) {
1030
- const name = `pepr-${uuid}-watch`;
1031
- const namespace2 = "pepr-system";
1032
- try {
1033
- const k8sStore = await (0, import_kubernetes_fluent_client3.K8s)(PeprStore).InNamespace(namespace2).Get(name);
1034
- Object.entries(k8sStore.data).forEach(([key, value]) => {
1035
- store[key] = value;
1036
- });
1037
- } catch (e) {
1038
- logger_default.debug(e, "Watch store does not exist yet");
1026
+ // src/lib/helpers.ts
1027
+ var import_kubernetes_fluent_client3 = require("kubernetes-fluent-client");
1028
+ function checkOverlap(record1, record2) {
1029
+ if (Object.keys(record1).length === 0) {
1030
+ return true;
1039
1031
  }
1040
- setInterval(() => {
1041
- if (storeUpdates) {
1042
- (0, import_kubernetes_fluent_client3.K8s)(PeprStore).Apply({
1043
- metadata: {
1044
- name,
1045
- namespace: namespace2
1046
- },
1047
- data: store
1048
- }).then(() => storeUpdates = false).catch((e) => {
1049
- logger_default.error(e, "Error updating watch store");
1050
- });
1032
+ for (const key in record1) {
1033
+ if (Object.prototype.hasOwnProperty.call(record1, key) && Object.prototype.hasOwnProperty.call(record2, key) && record1[key] === record2[key]) {
1034
+ return true;
1051
1035
  }
1052
- }, 10 * 1e3);
1036
+ }
1037
+ return false;
1053
1038
  }
1054
- async function setupWatch(uuid, capabilities) {
1055
- await setupStore(uuid);
1056
- capabilities.flatMap((c) => c.bindings).filter((binding) => binding.isWatch).forEach(runBinding);
1039
+ var filterMatcher = (binding, obj, capabilityNamespaces) => {
1040
+ if (binding.kind && binding.kind.kind === "Namespace" && binding.filters && binding.filters.namespaces.length !== 0) {
1041
+ return `Ignoring Watch Callback: Cannot use a namespace filter in a namespace object.`;
1042
+ }
1043
+ if (typeof obj === "object" && obj !== null && "metadata" in obj && obj.metadata !== void 0 && binding.filters) {
1044
+ if (obj.metadata.labels && !checkOverlap(binding.filters.labels, obj.metadata.labels)) {
1045
+ return `Ignoring Watch Callback: No overlap between binding and object labels. Binding labels ${JSON.stringify(
1046
+ binding.filters.labels
1047
+ )}, Object Labels ${JSON.stringify(obj.metadata.labels)}.`;
1048
+ }
1049
+ if (obj.metadata.annotations && !checkOverlap(binding.filters.annotations, obj.metadata.annotations)) {
1050
+ return `Ignoring Watch Callback: No overlap between binding and object annotations. Binding annotations ${JSON.stringify(
1051
+ binding.filters.annotations
1052
+ )}, Object annotations ${JSON.stringify(obj.metadata.annotations)}.`;
1053
+ }
1054
+ }
1055
+ if (Array.isArray(capabilityNamespaces) && capabilityNamespaces.length > 0 && obj.metadata && obj.metadata.namespace && !capabilityNamespaces.includes(obj.metadata.namespace)) {
1056
+ return `Ignoring Watch Callback: Object is not in the capability namespace. Capability namespaces: ${capabilityNamespaces.join(
1057
+ ", "
1058
+ )}, Object namespace: ${obj.metadata.namespace}.`;
1059
+ }
1060
+ if (Array.isArray(capabilityNamespaces) && capabilityNamespaces.length > 0 && binding.filters && Array.isArray(binding.filters.namespaces) && binding.filters.namespaces.length > 0 && !binding.filters.namespaces.every((ns) => capabilityNamespaces.includes(ns))) {
1061
+ return `Ignoring Watch Callback: Binding namespace is not part of capability namespaces. Capability namespaces: ${capabilityNamespaces.join(
1062
+ ", "
1063
+ )}, Binding namespaces: ${binding.filters.namespaces.join(", ")}.`;
1064
+ }
1065
+ if (binding.filters && Array.isArray(binding.filters.namespaces) && binding.filters.namespaces.length > 0 && obj.metadata && obj.metadata.namespace && !binding.filters.namespaces.includes(obj.metadata.namespace)) {
1066
+ return `Ignoring Watch Callback: Binding namespace and object namespace are not the same. Binding namespaces: ${binding.filters.namespaces.join(
1067
+ ", "
1068
+ )}, Object namespace: ${obj.metadata.namespace}.`;
1069
+ }
1070
+ return "";
1071
+ };
1072
+
1073
+ // src/lib/watch-processor.ts
1074
+ var store = {};
1075
+ function setupWatch(capabilities) {
1076
+ capabilities.map(
1077
+ (capability) => capability.bindings.filter((binding) => binding.isWatch).forEach((bindingElement) => runBinding(bindingElement, capability.namespaces))
1078
+ );
1057
1079
  }
1058
- async function runBinding(binding) {
1080
+ async function runBinding(binding, capabilityNamespaces) {
1059
1081
  const eventToPhaseMap = {
1060
1082
  ["CREATE" /* Create */]: [import_types2.WatchPhase.Added],
1061
1083
  ["UPDATE" /* Update */]: [import_types2.WatchPhase.Modified],
@@ -1071,23 +1093,33 @@ async function runBinding(binding) {
1071
1093
  let watcher;
1072
1094
  if (binding.isQueue) {
1073
1095
  const queue = new Queue();
1074
- watcher = (0, import_kubernetes_fluent_client3.K8s)(binding.model, binding.filters).Watch(async (obj, type) => {
1096
+ watcher = (0, import_kubernetes_fluent_client4.K8s)(binding.model, binding.filters).Watch(async (obj, type) => {
1075
1097
  logger_default.debug(obj, `Watch event ${type} received`);
1076
1098
  if (phaseMatch.includes(type)) {
1077
1099
  try {
1078
- queue.setReconcile(async () => await binding.watchCallback?.(obj, type));
1079
- await queue.enqueue(obj);
1100
+ const filterMatch = filterMatcher(binding, obj, capabilityNamespaces);
1101
+ if (filterMatch === "") {
1102
+ queue.setReconcile(async () => await binding.watchCallback?.(obj, type));
1103
+ await queue.enqueue(obj);
1104
+ } else {
1105
+ logger_default.debug(filterMatch);
1106
+ }
1080
1107
  } catch (e) {
1081
1108
  logger_default.error(e, "Error executing watch callback");
1082
1109
  }
1083
1110
  }
1084
1111
  }, watchCfg);
1085
1112
  } else {
1086
- watcher = (0, import_kubernetes_fluent_client3.K8s)(binding.model, binding.filters).Watch(async (obj, type) => {
1113
+ watcher = (0, import_kubernetes_fluent_client4.K8s)(binding.model, binding.filters).Watch(async (obj, type) => {
1087
1114
  logger_default.debug(obj, `Watch event ${type} received`);
1088
1115
  if (phaseMatch.includes(type)) {
1089
1116
  try {
1090
- await binding.watchCallback?.(obj, type);
1117
+ const filterMatch = filterMatcher(binding, obj, capabilityNamespaces);
1118
+ if (filterMatch === "") {
1119
+ await binding.watchCallback?.(obj, type);
1120
+ } else {
1121
+ logger_default.debug(filterMatch);
1122
+ }
1091
1123
  } catch (e) {
1092
1124
  logger_default.error(e, "Error executing watch callback");
1093
1125
  }
@@ -1096,15 +1128,7 @@ async function runBinding(binding) {
1096
1128
  }
1097
1129
  const cacheSuffix = (0, import_crypto.createHash)("sha224").update(binding.watchCallback.toString()).digest("hex").substring(0, 5);
1098
1130
  const cacheID = [watcher.getCacheID(), cacheSuffix].join("-");
1099
- watcher.events.on(import_kubernetes_fluent_client3.WatchEvent.RESOURCE_VERSION, (version) => {
1100
- logger_default.debug(`Received watch cache: ${cacheID}:${version}`);
1101
- if (store[cacheID] !== version) {
1102
- logger_default.debug(`Updating watch cache: ${cacheID}: ${store[cacheID]} => ${version}`);
1103
- store[cacheID] = version;
1104
- storeUpdates = true;
1105
- }
1106
- });
1107
- watcher.events.on(import_kubernetes_fluent_client3.WatchEvent.GIVE_UP, (err) => {
1131
+ watcher.events.on(import_kubernetes_fluent_client4.WatchEvent.GIVE_UP, (err) => {
1108
1132
  logger_default.error(err, "Watch failed after 5 attempts, giving up");
1109
1133
  process.exit(1);
1110
1134
  });
@@ -1157,10 +1181,12 @@ var PeprModule = class {
1157
1181
  }
1158
1182
  this.#controller = new Controller(config, capabilities, opts.beforeHook, opts.afterHook, () => {
1159
1183
  if (isWatchMode() || isDevMode()) {
1160
- setupWatch(config.uuid, capabilities).catch((e) => {
1184
+ try {
1185
+ setupWatch(capabilities);
1186
+ } catch (e) {
1161
1187
  logger_default.error(e, "Error setting up watch");
1162
1188
  process.exit(1);
1163
- });
1189
+ }
1164
1190
  }
1165
1191
  });
1166
1192
  if (opts.deferStart) {
@@ -1547,15 +1573,15 @@ var Capability = class {
1547
1573
  * @param kind if using a custom KubernetesObject not available in `a.*`, specify the GroupVersionKind
1548
1574
  * @returns
1549
1575
  */
1550
- When = (model, kind2) => {
1551
- const matchedKind = (0, import_kubernetes_fluent_client4.modelToGroupVersionKind)(model.name);
1552
- if (!matchedKind && !kind2) {
1576
+ When = (model, kind3) => {
1577
+ const matchedKind = (0, import_kubernetes_fluent_client5.modelToGroupVersionKind)(model.name);
1578
+ if (!matchedKind && !kind3) {
1553
1579
  throw new Error(`Kind not specified for ${model.name}`);
1554
1580
  }
1555
1581
  const binding = {
1556
1582
  model,
1557
1583
  // If the kind is not specified, use the matched kind from the model
1558
- kind: kind2 || matchedKind,
1584
+ kind: kind3 || matchedKind,
1559
1585
  event: "*" /* Any */,
1560
1586
  filters: {
1561
1587
  name: "",