kubernetes-fluent-client 3.9.0 → 3.10.0-nightly.5

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.
@@ -2,6 +2,7 @@ import { KubernetesObject } from "@kubernetes/client-node";
2
2
  import { GenericClass } from "../types.js";
3
3
  import { K8sInit } from "./types.js";
4
4
  import { Filters } from "./shared-types.js";
5
+ type FinalizeOperation = "add" | "remove";
5
6
  /**
6
7
  * Kubernetes fluent API inspired by Kubectl. Pass in a model, then call filters and actions on it.
7
8
  *
@@ -10,4 +11,23 @@ import { Filters } from "./shared-types.js";
10
11
  * @returns a fluent API for the model
11
12
  */
12
13
  export declare function K8s<T extends GenericClass, K extends KubernetesObject = InstanceType<T>>(model: T, filters?: Filters): K8sInit<T, K>;
14
+ /**
15
+ *
16
+ * Remove controller fields from the Kubernetes object.
17
+ * This is necessary for ensuring that the object can be applied without conflicts.
18
+ *
19
+ * @param object - the Kubernetes object to remove controller fields from
20
+ */
21
+ export declare function removeControllerFields(object: KubernetesObject): void;
22
+ /**
23
+ * Mutates the finalizers list based on the operation.
24
+ * Throws or returns early if no update is necessary.
25
+ *
26
+ * @param operation - "add" or "remove"
27
+ * @param finalizer - The finalizer to add/remove
28
+ * @param object - The Kubernetes resource object
29
+ * @returns The updated finalizers list or `null` if no update is needed
30
+ */
31
+ export declare function updateFinalizersOrSkip(operation: FinalizeOperation, finalizer: string, object: KubernetesObject): string[] | null;
32
+ export {};
13
33
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fluent/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAwB,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAOjF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAS,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAuC,MAAM,mBAAmB,CAAC;AAMjF;;;;;;GAMG;AACH,wBAAgB,GAAG,CAAC,CAAC,SAAS,YAAY,EAAE,CAAC,SAAS,gBAAgB,GAAG,YAAY,CAAC,CAAC,CAAC,EACtF,KAAK,EAAE,CAAC,EACR,OAAO,GAAE,OAAY,GACpB,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAkVf"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fluent/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAwB,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAOjF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAS,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAuC,MAAM,mBAAmB,CAAC;AAMjF,KAAK,iBAAiB,GAAG,KAAK,GAAG,QAAQ,CAAC;AAE1C;;;;;;GAMG;AACH,wBAAgB,GAAG,CAAC,CAAC,SAAS,YAAY,EAAE,CAAC,SAAS,gBAAgB,GAAG,YAAY,CAAC,CAAC,CAAC,EACtF,KAAK,EAAE,CAAC,EACR,OAAO,GAAE,OAAY,GACpB,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CA8Yf;AACD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAOrE;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,iBAAiB,EAC5B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,gBAAgB,GACvB,MAAM,EAAE,GAAG,IAAI,CAgBjB"}
@@ -16,7 +16,18 @@ import { Pod } from "../upstream.js";
16
16
  * @returns a fluent API for the model
17
17
  */
18
18
  export function K8s(model, filters = {}) {
19
- const withFilters = { WithField, WithLabel, Get, Delete, Evict, Watch, Logs, Proxy, Scale };
19
+ const withFilters = {
20
+ WithField,
21
+ WithLabel,
22
+ Get,
23
+ Delete,
24
+ Evict,
25
+ Watch,
26
+ Logs,
27
+ Proxy,
28
+ Scale,
29
+ Finalize,
30
+ };
20
31
  const matchedKind = filters.kindOverride || modelToGroupVersionKind(model.name);
21
32
  /**
22
33
  * @inheritdoc
@@ -256,6 +267,41 @@ export function K8s(model, filters = {}) {
256
267
  }
257
268
  throw resp;
258
269
  }
270
+ /**
271
+ *
272
+ * @param operation - The operation to perform, either "add" or "remove"
273
+ * @param finalizer - The finalizer to add or remove
274
+ * @param name - (optional) the name of the resource to finalize, if not provided, uses filters
275
+ * @inheritdoc
276
+ * @see {@link K8sInit.Finalize}
277
+ */
278
+ async function Finalize(operation, finalizer, name) {
279
+ if (name) {
280
+ if (filters.name) {
281
+ throw new Error(`Name already specified: ${filters.name}`);
282
+ }
283
+ filters.name = name;
284
+ }
285
+ // need to do a GET to get the array index of the finalizer
286
+ const object = await k8sExec(model, filters, { method: FetchMethods.GET });
287
+ if (!object) {
288
+ throw new Error("Resource not found");
289
+ }
290
+ const finalizers = updateFinalizersOrSkip(operation, finalizer, object);
291
+ if (!finalizers)
292
+ return;
293
+ removeControllerFields(object);
294
+ await k8sExec(model, filters, {
295
+ method: FetchMethods.APPLY,
296
+ payload: {
297
+ ...object,
298
+ metadata: {
299
+ ...object.metadata,
300
+ finalizers,
301
+ },
302
+ },
303
+ }, { force: true });
304
+ }
259
305
  /**
260
306
  *
261
307
  * @param replicas - the number of replicas to scale to
@@ -299,3 +345,42 @@ export function K8s(model, filters = {}) {
299
345
  }
300
346
  return { InNamespace, Apply, Create, Patch, PatchStatus, Raw, ...withFilters };
301
347
  }
348
+ /**
349
+ *
350
+ * Remove controller fields from the Kubernetes object.
351
+ * This is necessary for ensuring that the object can be applied without conflicts.
352
+ *
353
+ * @param object - the Kubernetes object to remove controller fields from
354
+ */
355
+ export function removeControllerFields(object) {
356
+ delete object.metadata?.managedFields;
357
+ delete object.metadata?.resourceVersion;
358
+ delete object.metadata?.uid;
359
+ delete object.metadata?.creationTimestamp;
360
+ delete object.metadata?.generation;
361
+ delete object.metadata?.finalizers;
362
+ }
363
+ /**
364
+ * Mutates the finalizers list based on the operation.
365
+ * Throws or returns early if no update is necessary.
366
+ *
367
+ * @param operation - "add" or "remove"
368
+ * @param finalizer - The finalizer to add/remove
369
+ * @param object - The Kubernetes resource object
370
+ * @returns The updated finalizers list or `null` if no update is needed
371
+ */
372
+ export function updateFinalizersOrSkip(operation, finalizer, object) {
373
+ const current = object.metadata?.finalizers ?? [];
374
+ const isPresent = current.includes(finalizer);
375
+ if ((operation === "remove" && !isPresent) || (operation === "add" && isPresent)) {
376
+ return null; // no-op
377
+ }
378
+ switch (operation) {
379
+ case "remove":
380
+ return current.filter(f => f !== finalizer);
381
+ case "add":
382
+ return [...current, finalizer];
383
+ default:
384
+ throw new Error(`Unsupported operation: ${operation}`);
385
+ }
386
+ }
@@ -32,6 +32,15 @@ export type GetFunction<K extends KubernetesObject> = {
32
32
  (name: string): Promise<K>;
33
33
  };
34
34
  export type K8sFilteredActions<T extends GenericClass, K extends KubernetesObject> = {
35
+ /**
36
+ * Perform a server-side apply to add or remove a finalizer from the resource.
37
+ *
38
+ * @param operation - the operation to perform, either "add" or "remove"
39
+ * @param finalizer - the finalizer to add or remove
40
+ * @param name - the name of the resource to perform the operation
41
+ * @returns a promise that resolves when the operation is complete
42
+ */
43
+ Finalize: (operation: "add" | "remove", finalizer: string, name?: string) => Promise<void>;
35
44
  /**
36
45
  * Proxy request to the Kubernetes API for the given resource.
37
46
  * This uses the `/proxy` subresource, usually for pods or services.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/fluent/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/fluent/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kubernetes-fluent-client",
3
- "version": "3.9.0",
3
+ "version": "3.10.0-nightly.5",
4
4
  "description": "A @kubernetes/client-node fluent API wrapper that leverages K8s Server Side Apply.",
5
5
  "bin": "./dist/cli.js",
6
6
  "main": "dist/index.js",
@@ -74,7 +74,7 @@
74
74
  "@typescript-eslint/parser": "8.38.0",
75
75
  "@vitest/coverage-v8": "^3.2.1",
76
76
  "command-line-args": "^6.0.1",
77
- "eslint-plugin-jsdoc": "51.4.1",
77
+ "eslint-plugin-jsdoc": "52.0.0",
78
78
  "globals": "^16.0.0",
79
79
  "husky": "^9.1.6",
80
80
  "lint-staged": "^16.0.0",
@@ -16,6 +16,8 @@ import { WatchCfg, Watcher } from "./watch.js";
16
16
  import { hasLogs } from "../helpers.js";
17
17
  import { Pod, type Service, type ReplicaSet } from "../upstream.js";
18
18
 
19
+ type FinalizeOperation = "add" | "remove";
20
+
19
21
  /**
20
22
  * Kubernetes fluent API inspired by Kubectl. Pass in a model, then call filters and actions on it.
21
23
  *
@@ -27,7 +29,18 @@ export function K8s<T extends GenericClass, K extends KubernetesObject = Instanc
27
29
  model: T,
28
30
  filters: Filters = {},
29
31
  ): K8sInit<T, K> {
30
- const withFilters = { WithField, WithLabel, Get, Delete, Evict, Watch, Logs, Proxy, Scale };
32
+ const withFilters = {
33
+ WithField,
34
+ WithLabel,
35
+ Get,
36
+ Delete,
37
+ Evict,
38
+ Watch,
39
+ Logs,
40
+ Proxy,
41
+ Scale,
42
+ Finalize,
43
+ };
31
44
  const matchedKind = filters.kindOverride || modelToGroupVersionKind(model.name);
32
45
 
33
46
  /**
@@ -313,6 +326,55 @@ export function K8s<T extends GenericClass, K extends KubernetesObject = Instanc
313
326
  throw resp;
314
327
  }
315
328
 
329
+ async function Finalize(
330
+ operation: FinalizeOperation,
331
+ finalizer: string,
332
+ name?: string,
333
+ ): Promise<void>;
334
+ /**
335
+ *
336
+ * @param operation - The operation to perform, either "add" or "remove"
337
+ * @param finalizer - The finalizer to add or remove
338
+ * @param name - (optional) the name of the resource to finalize, if not provided, uses filters
339
+ * @inheritdoc
340
+ * @see {@link K8sInit.Finalize}
341
+ */
342
+ async function Finalize(
343
+ operation: FinalizeOperation,
344
+ finalizer: string,
345
+ name?: string,
346
+ ): Promise<void> {
347
+ if (name) {
348
+ if (filters.name) {
349
+ throw new Error(`Name already specified: ${filters.name}`);
350
+ }
351
+ filters.name = name;
352
+ }
353
+ // need to do a GET to get the array index of the finalizer
354
+ const object = await k8sExec<T, K>(model, filters, { method: FetchMethods.GET });
355
+ if (!object) {
356
+ throw new Error("Resource not found");
357
+ }
358
+ const finalizers = updateFinalizersOrSkip(operation, finalizer, object);
359
+ if (!finalizers) return;
360
+ removeControllerFields(object);
361
+
362
+ await k8sExec<T, K>(
363
+ model,
364
+ filters,
365
+ {
366
+ method: FetchMethods.APPLY,
367
+ payload: {
368
+ ...object,
369
+ metadata: {
370
+ ...object.metadata,
371
+ finalizers,
372
+ },
373
+ },
374
+ },
375
+ { force: true },
376
+ );
377
+ }
316
378
  async function Scale(replicas: number, name?: string): Promise<void>;
317
379
  /**
318
380
  *
@@ -365,3 +427,49 @@ export function K8s<T extends GenericClass, K extends KubernetesObject = Instanc
365
427
 
366
428
  return { InNamespace, Apply, Create, Patch, PatchStatus, Raw, ...withFilters };
367
429
  }
430
+ /**
431
+ *
432
+ * Remove controller fields from the Kubernetes object.
433
+ * This is necessary for ensuring that the object can be applied without conflicts.
434
+ *
435
+ * @param object - the Kubernetes object to remove controller fields from
436
+ */
437
+ export function removeControllerFields(object: KubernetesObject): void {
438
+ delete object.metadata?.managedFields;
439
+ delete object.metadata?.resourceVersion;
440
+ delete object.metadata?.uid;
441
+ delete object.metadata?.creationTimestamp;
442
+ delete object.metadata?.generation;
443
+ delete object.metadata?.finalizers;
444
+ }
445
+
446
+ /**
447
+ * Mutates the finalizers list based on the operation.
448
+ * Throws or returns early if no update is necessary.
449
+ *
450
+ * @param operation - "add" or "remove"
451
+ * @param finalizer - The finalizer to add/remove
452
+ * @param object - The Kubernetes resource object
453
+ * @returns The updated finalizers list or `null` if no update is needed
454
+ */
455
+ export function updateFinalizersOrSkip(
456
+ operation: FinalizeOperation,
457
+ finalizer: string,
458
+ object: KubernetesObject,
459
+ ): string[] | null {
460
+ const current = object.metadata?.finalizers ?? [];
461
+ const isPresent = current.includes(finalizer);
462
+
463
+ if ((operation === "remove" && !isPresent) || (operation === "add" && isPresent)) {
464
+ return null; // no-op
465
+ }
466
+
467
+ switch (operation) {
468
+ case "remove":
469
+ return current.filter(f => f !== finalizer);
470
+ case "add":
471
+ return [...current, finalizer];
472
+ default:
473
+ throw new Error(`Unsupported operation: ${operation}`);
474
+ }
475
+ }
@@ -43,6 +43,15 @@ export type GetFunction<K extends KubernetesObject> = {
43
43
  };
44
44
 
45
45
  export type K8sFilteredActions<T extends GenericClass, K extends KubernetesObject> = {
46
+ /**
47
+ * Perform a server-side apply to add or remove a finalizer from the resource.
48
+ *
49
+ * @param operation - the operation to perform, either "add" or "remove"
50
+ * @param finalizer - the finalizer to add or remove
51
+ * @param name - the name of the resource to perform the operation
52
+ * @returns a promise that resolves when the operation is complete
53
+ */
54
+ Finalize: (operation: "add" | "remove", finalizer: string, name?: string) => Promise<void>;
46
55
  /**
47
56
  * Proxy request to the Kubernetes API for the given resource.
48
57
  * This uses the `/proxy` subresource, usually for pods or services.