pepr 0.47.0-nightly.0 → 0.47.0-nightly.10

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/package.json CHANGED
@@ -16,7 +16,7 @@
16
16
  "!src/fixtures/**",
17
17
  "!dist/**/*.test.d.ts*"
18
18
  ],
19
- "version": "0.47.0-nightly.0",
19
+ "version": "0.47.0-nightly.10",
20
20
  "main": "dist/lib.js",
21
21
  "types": "dist/lib.d.ts",
22
22
  "scripts": {
@@ -36,11 +36,11 @@
36
36
  "test:journey-wasm": "npm run test:journey:k3d && npm run build && npm run test:journey:image && npm run test:journey:run-wasm",
37
37
  "test:journey-wasm:unicorn": "npm run test:journey:k3d && npm run build && npm run test:journey:image:unicorn && npm run test:journey:run-wasm",
38
38
  "test:journey:image": "docker buildx build --output type=docker --tag pepr:dev . && k3d image import pepr:dev -c pepr-dev",
39
- "test:journey:image:unicorn": "docker buildx build --output type=docker --tag pepr:dev $(node scripts/read-unicorn-build-args.mjs) . && k3d image import pepr:dev -c pepr-dev",
39
+ "test:journey:image:unicorn": "npm run build && docker buildx build --output type=docker --tag pepr:dev $(node scripts/read-unicorn-build-args.mjs) . && k3d image import pepr:dev -c pepr-dev",
40
40
  "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",
41
41
  "test:journey:run": "jest --detectOpenHandles journey/entrypoint.test.ts && npm run test:journey:upgrade",
42
42
  "test:journey:run-wasm": "jest --detectOpenHandles journey/entrypoint-wasm.test.ts",
43
- "test:journey:unicorn": "npm run test:journey:k3d && npm run build && npm run test:journey:image:unicorn && npm run test:journey:run",
43
+ "test:journey:unicorn": "npm run test:journey:k3d && npm run test:journey:image:unicorn && npm run test:journey:run",
44
44
  "test:journey:upgrade": "npm run test:journey:k3d && npm run test:journey:image && jest --detectOpenHandles journey/pepr-upgrade.test.ts",
45
45
  "test:unit": "npm run gen-data-json && jest src --coverage --detectOpenHandles --coverageDirectory=./coverage --testPathIgnorePatterns='build-artifact.test.ts'",
46
46
  "format:check": "eslint src && prettier --config .prettierrc src --check",
@@ -54,7 +54,7 @@
54
54
  "heredoc": "^1.3.1",
55
55
  "http-status-codes": "^2.3.0",
56
56
  "json-pointer": "^0.6.2",
57
- "kubernetes-fluent-client": "3.4.6",
57
+ "kubernetes-fluent-client": "3.4.10",
58
58
  "pino": "9.6.0",
59
59
  "pino-pretty": "13.0.0",
60
60
  "prom-client": "15.1.3",
@@ -0,0 +1,56 @@
1
+ import { DataStore, Storage } from "../core/storage";
2
+ import { startsWith } from "ramda";
3
+ import Log, { redactedStore } from "../telemetry/logger";
4
+ import { K8s } from "kubernetes-fluent-client";
5
+ import { Store } from "../k8s";
6
+ import { Operation } from "fast-json-patch";
7
+ import { fillStoreCache, sendUpdatesAndFlushCache } from "./storeCache";
8
+
9
+ export interface StoreMigration {
10
+ name: string;
11
+ namespace: string;
12
+ store: Store;
13
+ stores: Record<string, Storage>;
14
+ setupWatch: () => void;
15
+ }
16
+
17
+ export async function migrateAndSetupWatch(storeData: StoreMigration): Promise<void> {
18
+ const { store, namespace, name, stores, setupWatch } = storeData;
19
+
20
+ Log.debug(redactedStore(store), "Pepr Store migration");
21
+ // Add cacheID label to store
22
+ await K8s(Store, { namespace, name }).Patch([
23
+ {
24
+ op: "add",
25
+ path: "/metadata/labels/pepr.dev-cacheID",
26
+ value: `${Date.now()}`,
27
+ },
28
+ ]);
29
+
30
+ const data: DataStore = store.data;
31
+ let storeCache: Record<string, Operation> = {};
32
+
33
+ for (const name of Object.keys(stores)) {
34
+ // Get the prefix offset for the keys
35
+ const offset = `${name}-`.length;
36
+
37
+ // Loop over each key in the store
38
+ for (const key of Object.keys(data)) {
39
+ // Match on the capability name as a prefix for non v2 keys
40
+ if (startsWith(name, key) && !startsWith(`${name}-v2`, key)) {
41
+ // populate migrate cache
42
+ storeCache = fillStoreCache(storeCache, name, "remove", {
43
+ key: [key.slice(offset)],
44
+ value: data[key],
45
+ });
46
+ storeCache = fillStoreCache(storeCache, name, "add", {
47
+ key: [key.slice(offset)],
48
+ value: data[key],
49
+ version: "v2",
50
+ });
51
+ }
52
+ }
53
+ }
54
+ storeCache = await sendUpdatesAndFlushCache(storeCache, namespace, name);
55
+ setupWatch();
56
+ }
@@ -10,6 +10,7 @@ import { Store } from "../k8s";
10
10
  import Log, { redactedPatch, redactedStore } from "../telemetry/logger";
11
11
  import { DataOp, DataSender, DataStore, Storage } from "../core/storage";
12
12
  import { fillStoreCache, sendUpdatesAndFlushCache } from "./storeCache";
13
+ import { migrateAndSetupWatch } from "./migrateStore";
13
14
 
14
15
  const namespace = "pepr-system";
15
16
  const debounceBackoffReceive = 1000;
@@ -56,7 +57,16 @@ export class StoreController {
56
57
  K8s(Store)
57
58
  .InNamespace(namespace)
58
59
  .Get(this.#name)
59
- .then(async (store: Store) => await this.#migrateAndSetupWatch(store))
60
+ .then(
61
+ async (store: Store) =>
62
+ await migrateAndSetupWatch({
63
+ name,
64
+ namespace,
65
+ store,
66
+ stores: this.#stores,
67
+ setupWatch: this.#setupWatch,
68
+ }),
69
+ )
60
70
  .catch(this.#createStoreResource),
61
71
  Math.random() * 3000, // Add a jitter to the Store creation to avoid collisions
62
72
  );
@@ -67,45 +77,6 @@ export class StoreController {
67
77
  watcher.start().catch(e => Log.error(e, "Error starting Pepr store watch"));
68
78
  };
69
79
 
70
- #migrateAndSetupWatch = async (store: Store): Promise<void> => {
71
- Log.debug(redactedStore(store), "Pepr Store migration");
72
- // Add cacheID label to store
73
- await K8s(Store, { namespace, name: this.#name }).Patch([
74
- {
75
- op: "add",
76
- path: "/metadata/labels/pepr.dev-cacheID",
77
- value: `${Date.now()}`,
78
- },
79
- ]);
80
-
81
- const data: DataStore = store.data || {};
82
- let storeCache: Record<string, Operation> = {};
83
-
84
- for (const name of Object.keys(this.#stores)) {
85
- // Get the prefix offset for the keys
86
- const offset = `${name}-`.length;
87
-
88
- // Loop over each key in the store
89
- for (const key of Object.keys(data)) {
90
- // Match on the capability name as a prefix for non v2 keys
91
- if (startsWith(name, key) && !startsWith(`${name}-v2`, key)) {
92
- // populate migrate cache
93
- storeCache = fillStoreCache(storeCache, name, "remove", {
94
- key: [key.slice(offset)],
95
- value: data[key],
96
- });
97
- storeCache = fillStoreCache(storeCache, name, "add", {
98
- key: [key.slice(offset)],
99
- value: data[key],
100
- version: "v2",
101
- });
102
- }
103
- }
104
- }
105
- storeCache = await sendUpdatesAndFlushCache(storeCache, namespace, this.#name);
106
- this.#setupWatch();
107
- };
108
-
109
80
  #receive = (store: Store): void => {
110
81
  Log.debug(redactedStore(store), "Pepr Store update");
111
82
 
@@ -62,7 +62,7 @@ export class PeprModule {
62
62
  const controllerHooks: ControllerHooks = {
63
63
  beforeHook: opts.beforeHook,
64
64
  afterHook: opts.afterHook,
65
- onReady: (): void => {
65
+ onReady: async (): Promise<void> => {
66
66
  // Wait for the controller to be ready before setting up watches
67
67
  if (isWatchMode() || isDevMode()) {
68
68
  try {
@@ -86,13 +86,11 @@ const eventToPhaseMap = {
86
86
  * @param capabilities The capabilities to load watches for
87
87
  */
88
88
  export function setupWatch(capabilities: Capability[], ignoredNamespaces?: string[]): void {
89
- capabilities.map(capability =>
90
- capability.bindings
91
- .filter(binding => binding.isWatch)
92
- .forEach(bindingElement =>
93
- runBinding(bindingElement, capability.namespaces, ignoredNamespaces),
94
- ),
95
- );
89
+ for (const capability of capabilities) {
90
+ for (const binding of capability.bindings.filter(b => b.isWatch)) {
91
+ runBinding(binding, capability.namespaces, ignoredNamespaces);
92
+ }
93
+ }
96
94
  }
97
95
 
98
96
  /**
@@ -101,7 +99,7 @@ export function setupWatch(capabilities: Capability[], ignoredNamespaces?: strin
101
99
  * @param binding the binding to watch
102
100
  * @param capabilityNamespaces list of namespaces to filter on
103
101
  */
104
- async function runBinding(
102
+ export async function runBinding(
105
103
  binding: Binding,
106
104
  capabilityNamespaces: string[],
107
105
  ignoredNamespaces?: string[],
@@ -185,14 +183,20 @@ async function runBinding(
185
183
  );
186
184
 
187
185
  // Register event handlers
188
- registerWatchEventHandlers(watcher, logEvent, metricsCollector);
186
+ try {
187
+ registerWatchEventHandlers(watcher, logEvent, metricsCollector);
188
+ } catch (err) {
189
+ throw new Error(
190
+ "WatchEventHandler Registration Error: Unable to register event watch handler.",
191
+ { cause: err },
192
+ );
193
+ }
189
194
 
190
195
  // Start the watch
191
196
  try {
192
197
  await watcher.start();
193
198
  } catch (err) {
194
- Log.error(err, "Error starting watch");
195
- process.exit(1);
199
+ throw new Error("WatchStart Error: Unable to start watch.", { cause: err });
196
200
  }
197
201
  }
198
202
 
@@ -235,7 +239,10 @@ export function registerWatchEventHandlers(
235
239
  [WatchEvent.GIVE_UP]: err => {
236
240
  // If failure continues, log and exit
237
241
  logEvent(WatchEvent.GIVE_UP, err.message);
238
- process.exit(1);
242
+ throw new Error(
243
+ "WatchEvent GiveUp Error: The watch has failed to start after several attempts.",
244
+ { cause: err },
245
+ );
239
246
  },
240
247
  [WatchEvent.CONNECT]: url => logEvent(WatchEvent.CONNECT, url),
241
248
  [WatchEvent.DATA_ERROR]: err => logEvent(WatchEvent.DATA_ERROR, err.message),