kubernetes-fluent-client 2.3.1 → 2.4.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 CHANGED
@@ -51,6 +51,10 @@ async function demo() {
51
51
  runningPods.items.forEach(pod => {
52
52
  console.log(`${pod.metadata?.namespace}/${pod.metadata?.name} is running`);
53
53
  });
54
+
55
+ // Get logs from a Deployment named "nginx" in the namespace
56
+ const logs = await K8s(kind.Deployment).InNamespace(namespace).Logs("nginx");
57
+ console.log(logs);
54
58
  }
55
59
 
56
60
  // Create a few resources to work with: Namespace, ConfigMap, and Pod
@@ -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,UAAU,CAAC;AACxC,OAAO,EAA0B,OAAO,EAAE,OAAO,EAAsB,MAAM,SAAS,CAAC;AAIvF;;;;;;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,CA8Kf"}
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,UAAU,CAAC;AACxC,OAAO,EAA0B,OAAO,EAAE,OAAO,EAAsB,MAAM,SAAS,CAAC;AAKvF;;;;;;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,CA0Pf"}
@@ -8,6 +8,8 @@ const fetch_1 = require("../fetch");
8
8
  const kinds_1 = require("../kinds");
9
9
  const utils_1 = require("./utils");
10
10
  const watch_1 = require("./watch");
11
+ const helpers_1 = require("../helpers");
12
+ const upstream_1 = require("../upstream");
11
13
  /**
12
14
  * Kubernetes fluent API inspired by Kubectl. Pass in a model, then call filters and actions on it.
13
15
  *
@@ -16,7 +18,7 @@ const watch_1 = require("./watch");
16
18
  * @returns a fluent API for the model
17
19
  */
18
20
  function K8s(model, filters = {}) {
19
- const withFilters = { WithField, WithLabel, Get, Delete, Watch };
21
+ const withFilters = { WithField, WithLabel, Get, Delete, Watch, Logs };
20
22
  const matchedKind = filters.kindOverride || (0, kinds_1.modelToGroupVersionKind)(model.name);
21
23
  /**
22
24
  * @inheritdoc
@@ -70,6 +72,67 @@ function K8s(model, filters = {}) {
70
72
  payload.kind = matchedKind.kind;
71
73
  }
72
74
  }
75
+ /**
76
+ * @inheritdoc
77
+ * @see {@link K8sInit.Logs}
78
+ */
79
+ async function Logs(name) {
80
+ let labels = {};
81
+ const { kind } = matchedKind;
82
+ const { namespace } = filters;
83
+ const podList = [];
84
+ if (name) {
85
+ if (filters.name) {
86
+ throw new Error(`Name already specified: ${filters.name}`);
87
+ }
88
+ filters.name = name;
89
+ }
90
+ if (!namespace) {
91
+ throw new Error("Namespace must be defined");
92
+ }
93
+ if (!(0, helpers_1.hasLogs)(kind)) {
94
+ throw new Error("Kind must be Pod or have a selector");
95
+ }
96
+ try {
97
+ const object = await (0, utils_1.k8sExec)(model, filters, "GET");
98
+ if (kind !== "Pod") {
99
+ if (kind === "Service") {
100
+ const svc = object;
101
+ labels = svc.spec.selector ?? {};
102
+ }
103
+ else if (kind === "ReplicaSet" ||
104
+ kind === "Deployment" ||
105
+ kind === "StatefulSet" ||
106
+ kind === "DaemonSet") {
107
+ const rs = object;
108
+ labels = rs.spec.selector.matchLabels ?? {};
109
+ }
110
+ const list = await K8s(upstream_1.Pod, { namespace: filters.namespace, labels }).Get();
111
+ list.items.forEach(item => {
112
+ return podList.push(item);
113
+ });
114
+ }
115
+ else {
116
+ podList.push(object);
117
+ }
118
+ }
119
+ catch (e) {
120
+ throw new Error(e);
121
+ }
122
+ const podModel = { ...model, name: "V1Pod" };
123
+ const logPromises = podList.map(po => (0, utils_1.k8sExec)(podModel, { ...filters, name: po.metadata.name }, "LOG"));
124
+ const responses = await Promise.all(logPromises);
125
+ const combinedString = responses.reduce((accumulator, currentString, i) => {
126
+ const prefixedLines = currentString
127
+ .split("\n")
128
+ .map(line => {
129
+ return line !== "" ? `[pod/${podList[i].metadata.name}] ${line}` : "";
130
+ })
131
+ .filter(str => str !== "");
132
+ return [...accumulator, ...prefixedLines];
133
+ }, []);
134
+ return combinedString;
135
+ }
73
136
  /**
74
137
  * @inheritdoc
75
138
  * @see {@link K8sInit.Get}
@@ -13,7 +13,7 @@ export declare enum WatchPhase {
13
13
  Bookmark = "BOOKMARK",
14
14
  Error = "ERROR"
15
15
  }
16
- export type FetchMethods = "GET" | "APPLY" | "POST" | "PUT" | "DELETE" | "PATCH" | "WATCH" | "PATCH_STATUS";
16
+ export type FetchMethods = "GET" | "APPLY" | "POST" | "PUT" | "DELETE" | "PATCH" | "WATCH" | "PATCH_STATUS" | "LOG";
17
17
  export interface Filters {
18
18
  kindOverride?: GroupVersionKind;
19
19
  fields?: Record<string, string>;
@@ -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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"}
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/fluent/utils.ts"],"names":[],"mappings":";AAKA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAI1B,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAI1D;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,YAAY,EAChD,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,OAAO,EAChB,WAAW,UAAQ,OAwDpB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,MAAM,CAAC,MAAM,EAAE,YAAY;;;GAwBhD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,OAAO,CAAC,CAAC,SAAS,YAAY,EAAE,CAAC,EACrD,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,YAAY,EACpB,OAAO,CAAC,EAAE,CAAC,GAAG,OAAO,EACrB,QAAQ,GAAE,QAA2B,cA2CtC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/fluent/utils.ts"],"names":[],"mappings":";AAKA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAI1B,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAI1D;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,YAAY,EAChD,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,OAAO,EAChB,WAAW,UAAQ,OAwDpB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,MAAM,CAAC,MAAM,EAAE,YAAY;;;GAwBhD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,OAAO,CAAC,CAAC,SAAS,YAAY,EAAE,CAAC,EACrD,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,YAAY,EACpB,OAAO,CAAC,EAAE,CAAC,GAAG,OAAO,EACrB,QAAQ,GAAE,QAA2B,cAwDtC"}
@@ -105,8 +105,20 @@ exports.k8sCfg = k8sCfg;
105
105
  * @returns the parsed JSON response
106
106
  */
107
107
  async function k8sExec(model, filters, method, payload, applyCfg = { force: false }) {
108
- const { opts, serverUrl } = await k8sCfg(method);
109
- const url = pathBuilder(serverUrl, model, filters, method === "POST");
108
+ const reconstruct = async (method) => {
109
+ const configMethod = method === "LOG" ? "GET" : method;
110
+ const { opts, serverUrl } = await k8sCfg(configMethod);
111
+ const isPost = method === "POST";
112
+ const baseUrl = pathBuilder(serverUrl, model, filters, isPost);
113
+ if (method === "LOG") {
114
+ baseUrl.pathname = `${baseUrl.pathname}/log`;
115
+ }
116
+ return {
117
+ url: baseUrl,
118
+ opts,
119
+ };
120
+ };
121
+ const { opts, url } = await reconstruct(method);
110
122
  switch (opts.method) {
111
123
  // PATCH_STATUS is a special case that uses the PATCH method on status subresources
112
124
  case "PATCH_STATUS":
@@ -31,6 +31,8 @@ export declare enum WatchEvent {
31
31
  }
32
32
  /** Configuration for the watch function. */
33
33
  export type WatchCfg = {
34
+ /** Whether to allow watch bookmarks. */
35
+ allowWatchBookmarks?: boolean;
34
36
  /** The resource version to start the watch at, this will be updated on each event. */
35
37
  resourceVersion?: string;
36
38
  /** The maximum number of times to retry the watch, the retry count is reset on success. Unlimited retries if not specified. */
@@ -1 +1 @@
1
- {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/fluent/watch.ts"],"names":[],"mappings":";;AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAGtC,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,WAAW,EAAc,MAAM,SAAS,CAAC;AAG3D,oBAAY,UAAU;IACpB,sCAAsC;IACtC,OAAO,YAAY;IACnB,2BAA2B;IAC3B,aAAa,kBAAkB;IAC/B,kDAAkD;IAClD,UAAU,eAAe;IACzB,0BAA0B;IAC1B,SAAS,cAAc;IACvB,8BAA8B;IAC9B,OAAO,YAAY;IACnB,sBAAsB;IACtB,KAAK,UAAU;IACf,uBAAuB;IACvB,MAAM,WAAW;IACjB,mCAAmC;IACnC,IAAI,SAAS;IACb,2BAA2B;IAC3B,QAAQ,aAAa;IACrB,iCAAiC;IACjC,gBAAgB,qBAAqB;IACrC,wCAAwC;IACxC,oBAAoB,yBAAyB;IAC7C,qCAAqC;IACrC,iBAAiB,sBAAsB;CACxC;AAED,4CAA4C;AAC5C,MAAM,MAAM,QAAQ,GAAG;IACrB,sFAAsF;IACtF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+HAA+H;IAC/H,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0GAA0G;IAC1G,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,iDAAiD;AACjD,qBAAa,OAAO,CAAC,CAAC,SAAS,YAAY;;IAyBzC;;;;;;;;;;;OAWG;gBACS,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,QAAQ,GAAE,QAAa;IAiBzF;;;;OAIG;IACU,KAAK,IAAI,OAAO,CAAC,eAAe,CAAC;IAK9C,gGAAgG;IACzF,KAAK;IAMZ;;;;;OAKG;IACI,UAAU;IAWjB;;;;OAIG;IACH,IAAW,eAAe,IASkB,MAAM,GAAG,SAAS,CAP7D;IAED;;;;OAIG;IACH,IAAW,eAAe,CAAC,eAAe,EAAE,MAAM,GAAG,SAAS,EAE7D;IAED;;;;;;OAMG;IACH,IAAW,MAAM,IAAI,YAAY,CAEhC;CAoOF"}
1
+ {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/fluent/watch.ts"],"names":[],"mappings":";;AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAGtC,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,WAAW,EAAc,MAAM,SAAS,CAAC;AAG3D,oBAAY,UAAU;IACpB,sCAAsC;IACtC,OAAO,YAAY;IACnB,2BAA2B;IAC3B,aAAa,kBAAkB;IAC/B,kDAAkD;IAClD,UAAU,eAAe;IACzB,0BAA0B;IAC1B,SAAS,cAAc;IACvB,8BAA8B;IAC9B,OAAO,YAAY;IACnB,sBAAsB;IACtB,KAAK,UAAU;IACf,uBAAuB;IACvB,MAAM,WAAW;IACjB,mCAAmC;IACnC,IAAI,SAAS;IACb,2BAA2B;IAC3B,QAAQ,aAAa;IACrB,iCAAiC;IACjC,gBAAgB,qBAAqB;IACrC,wCAAwC;IACxC,oBAAoB,yBAAyB;IAC7C,qCAAqC;IACrC,iBAAiB,sBAAsB;CACxC;AAED,4CAA4C;AAC5C,MAAM,MAAM,QAAQ,GAAG;IACrB,wCAAwC;IACxC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,sFAAsF;IACtF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+HAA+H;IAC/H,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0GAA0G;IAC1G,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,iDAAiD;AACjD,qBAAa,OAAO,CAAC,CAAC,SAAS,YAAY;;IAyBzC;;;;;;;;;;;OAWG;gBACS,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,QAAQ,GAAE,QAAa;IAiBzF;;;;OAIG;IACU,KAAK,IAAI,OAAO,CAAC,eAAe,CAAC;IAK9C,gGAAgG;IACzF,KAAK;IAMZ;;;;;OAKG;IACI,UAAU;IAWjB;;;;OAIG;IACH,IAAW,eAAe,IASkB,MAAM,GAAG,SAAS,CAP7D;IAED;;;;OAIG;IACH,IAAW,eAAe,CAAC,eAAe,EAAE,MAAM,GAAG,SAAS,EAE7D;IAED;;;;;;OAMG;IACH,IAAW,MAAM,IAAI,YAAY,CAEhC;CAyOF"}
@@ -159,7 +159,7 @@ class Watcher {
159
159
  url.searchParams.set("resourceVersion", this.#watchCfg.resourceVersion);
160
160
  }
161
161
  // Enable watch bookmarks
162
- url.searchParams.set("allowWatchBookmarks", "true");
162
+ url.searchParams.set("allowWatchBookmarks", this.#watchCfg.allowWatchBookmarks ? `${this.#watchCfg.allowWatchBookmarks}` : "true");
163
163
  // Add the abort signal to the request options
164
164
  opts.signal = this.#abortController.signal;
165
165
  return { opts, url };
@@ -281,6 +281,7 @@ class Watcher {
281
281
  this.#retryCount++;
282
282
  this.#events.emit(WatchEvent.RECONNECT, err, this.#retryCount);
283
283
  if (this.#pendingReconnect) {
284
+ // wait for the connection to be re-established
284
285
  this.#events.emit(WatchEvent.RECONNECT_PENDING);
285
286
  }
286
287
  else {
package/dist/helpers.d.ts CHANGED
@@ -23,4 +23,11 @@ export declare function fromEnv(name: string): string;
23
23
  * @returns The current cluster.
24
24
  */
25
25
  export declare function waitForCluster(seconds?: number): Promise<Cluster>;
26
+ /**
27
+ * Determines if object has logs.
28
+ *
29
+ * @param kind The kind of Kubernetes object.
30
+ * @returns boolean.
31
+ */
32
+ export declare function hasLogs(kind: string): boolean;
26
33
  //# sourceMappingURL=helpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAc,MAAM,yBAAyB,CAAC;AAkB9D;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAqB5C;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,OAAO,SAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAenE"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAc,MAAM,yBAAyB,CAAC;AAkB9D;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAqB5C;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,OAAO,SAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAenE;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAuB7C"}
package/dist/helpers.js CHANGED
@@ -2,7 +2,7 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
  // SPDX-FileCopyrightText: 2023-Present The Kubernetes Fluent Client Authors
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
- exports.waitForCluster = exports.fromEnv = void 0;
5
+ exports.hasLogs = exports.waitForCluster = exports.fromEnv = void 0;
6
6
  const client_node_1 = require("@kubernetes/client-node");
7
7
  /**
8
8
  * Sleep for a number of seconds.
@@ -71,3 +71,34 @@ async function waitForCluster(seconds = 30) {
71
71
  return cluster;
72
72
  }
73
73
  exports.waitForCluster = waitForCluster;
74
+ /**
75
+ * Determines if object has logs.
76
+ *
77
+ * @param kind The kind of Kubernetes object.
78
+ * @returns boolean.
79
+ */
80
+ function hasLogs(kind) {
81
+ let hasSelector = false;
82
+ switch (kind) {
83
+ case "Pod":
84
+ hasSelector = true;
85
+ break;
86
+ case "DaemonSet":
87
+ hasSelector = true;
88
+ break;
89
+ case "ReplicaSet":
90
+ hasSelector = true;
91
+ break;
92
+ case "Service":
93
+ hasSelector = true;
94
+ break;
95
+ case "StatefulSet":
96
+ hasSelector = true;
97
+ break;
98
+ case "Deployment":
99
+ hasSelector = true;
100
+ break;
101
+ }
102
+ return hasSelector;
103
+ }
104
+ exports.hasLogs = hasLogs;
@@ -20,3 +20,18 @@ const helpers_1 = require("./helpers");
20
20
  (0, globals_1.expect)(cluster).toEqual({ server: "http://jest-test:8080" });
21
21
  });
22
22
  });
23
+ (0, globals_1.describe)("hasLogs function", () => {
24
+ (0, globals_1.it)("should return true for known kinds", () => {
25
+ (0, globals_1.expect)((0, helpers_1.hasLogs)("Pod")).toBe(true);
26
+ (0, globals_1.expect)((0, helpers_1.hasLogs)("DaemonSet")).toBe(true);
27
+ (0, globals_1.expect)((0, helpers_1.hasLogs)("ReplicaSet")).toBe(true);
28
+ (0, globals_1.expect)((0, helpers_1.hasLogs)("Service")).toBe(true);
29
+ (0, globals_1.expect)((0, helpers_1.hasLogs)("StatefulSet")).toBe(true);
30
+ (0, globals_1.expect)((0, helpers_1.hasLogs)("Deployment")).toBe(true);
31
+ });
32
+ (0, globals_1.it)("should return false for unknown kinds", () => {
33
+ (0, globals_1.expect)((0, helpers_1.hasLogs)("Unknown")).toBe(false);
34
+ (0, globals_1.expect)((0, helpers_1.hasLogs)("")).toBe(false);
35
+ (0, globals_1.expect)((0, helpers_1.hasLogs)("RandomKind")).toBe(false);
36
+ });
37
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kubernetes-fluent-client",
3
- "version": "2.3.1",
3
+ "version": "2.4.0",
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",
@@ -40,26 +40,26 @@
40
40
  "fast-json-patch": "3.1.1",
41
41
  "http-status-codes": "2.3.0",
42
42
  "node-fetch": "2.7.0",
43
- "quicktype-core": "23.0.115",
44
- "type-fest": "4.15.0",
43
+ "quicktype-core": "23.0.158",
44
+ "type-fest": "4.18.1",
45
45
  "yargs": "17.7.2"
46
46
  },
47
47
  "devDependencies": {
48
- "@commitlint/cli": "19.2.1",
49
- "@commitlint/config-conventional": "19.1.0",
48
+ "@commitlint/cli": "19.3.0",
49
+ "@commitlint/config-conventional": "19.2.2",
50
50
  "@jest/globals": "29.7.0",
51
51
  "@types/byline": "4.2.36",
52
- "@types/readable-stream": "4.0.11",
52
+ "@types/readable-stream": "4.0.12",
53
53
  "@types/yargs": "17.0.32",
54
- "@typescript-eslint/eslint-plugin": "7.5.0",
55
- "@typescript-eslint/parser": "7.5.0",
54
+ "@typescript-eslint/eslint-plugin": "7.8.0",
55
+ "@typescript-eslint/parser": "7.8.0",
56
56
  "eslint-plugin-jsdoc": "48.2.3",
57
57
  "jest": "29.7.0",
58
58
  "nock": "13.5.4",
59
59
  "prettier": "3.2.5",
60
- "semantic-release": "23.0.7",
60
+ "semantic-release": "23.0.8",
61
61
  "ts-jest": "29.1.2",
62
- "typescript": "5.4.4"
62
+ "typescript": "5.4.5"
63
63
  },
64
64
  "release": {
65
65
  "branches": [
@@ -12,7 +12,8 @@ import { GenericClass } from "../types";
12
12
  import { ApplyCfg, FetchMethods, Filters, K8sInit, Paths, WatchAction } from "./types";
13
13
  import { k8sCfg, k8sExec } from "./utils";
14
14
  import { WatchCfg, Watcher } from "./watch";
15
-
15
+ import { hasLogs } from "../helpers";
16
+ import { Pod, Service, ReplicaSet } from "../upstream";
16
17
  /**
17
18
  * Kubernetes fluent API inspired by Kubectl. Pass in a model, then call filters and actions on it.
18
19
  *
@@ -24,7 +25,7 @@ export function K8s<T extends GenericClass, K extends KubernetesObject = Instanc
24
25
  model: T,
25
26
  filters: Filters = {},
26
27
  ): K8sInit<T, K> {
27
- const withFilters = { WithField, WithLabel, Get, Delete, Watch };
28
+ const withFilters = { WithField, WithLabel, Get, Delete, Watch, Logs };
28
29
  const matchedKind = filters.kindOverride || modelToGroupVersionKind(model.name);
29
30
 
30
31
  /**
@@ -87,7 +88,83 @@ export function K8s<T extends GenericClass, K extends KubernetesObject = Instanc
87
88
  payload.kind = matchedKind.kind;
88
89
  }
89
90
  }
91
+ async function Logs(name?: string): Promise<string[]>;
92
+ /**
93
+ * @inheritdoc
94
+ * @see {@link K8sInit.Logs}
95
+ */
96
+ async function Logs(name?: string): Promise<string[]> {
97
+ let labels: Record<string, string> = {};
98
+ const { kind } = matchedKind;
99
+ const { namespace } = filters;
100
+ const podList: K[] = [];
101
+
102
+ if (name) {
103
+ if (filters.name) {
104
+ throw new Error(`Name already specified: ${filters.name}`);
105
+ }
106
+ filters.name = name;
107
+ }
108
+
109
+ if (!namespace) {
110
+ throw new Error("Namespace must be defined");
111
+ }
112
+ if (!hasLogs(kind)) {
113
+ throw new Error("Kind must be Pod or have a selector");
114
+ }
90
115
 
116
+ try {
117
+ const object = await k8sExec<T, K>(model, filters, "GET");
118
+
119
+ if (kind !== "Pod") {
120
+ if (kind === "Service") {
121
+ const svc: InstanceType<typeof Service> = object;
122
+ labels = svc.spec!.selector ?? {};
123
+ } else if (
124
+ kind === "ReplicaSet" ||
125
+ kind === "Deployment" ||
126
+ kind === "StatefulSet" ||
127
+ kind === "DaemonSet"
128
+ ) {
129
+ const rs: InstanceType<typeof ReplicaSet> = object;
130
+ labels = rs.spec!.selector.matchLabels ?? {};
131
+ }
132
+
133
+ const list = await K8s(Pod, { namespace: filters.namespace, labels }).Get();
134
+
135
+ list.items.forEach(item => {
136
+ return podList.push(item as unknown as K);
137
+ });
138
+ } else {
139
+ podList.push(object);
140
+ }
141
+ } catch (e) {
142
+ throw new Error(e);
143
+ }
144
+
145
+ const podModel = { ...model, name: "V1Pod" };
146
+ const logPromises = podList.map(po =>
147
+ k8sExec<T, string>(podModel, { ...filters, name: po.metadata!.name! }, "LOG"),
148
+ );
149
+
150
+ const responses = await Promise.all(logPromises);
151
+
152
+ const combinedString = responses.reduce(
153
+ (accumulator: string[], currentString: string, i: number) => {
154
+ const prefixedLines = currentString
155
+ .split("\n")
156
+ .map(line => {
157
+ return line !== "" ? `[pod/${podList[i].metadata!.name!}] ${line}` : "";
158
+ })
159
+ .filter(str => str !== "");
160
+
161
+ return [...accumulator, ...prefixedLines];
162
+ },
163
+ [],
164
+ );
165
+
166
+ return combinedString;
167
+ }
91
168
  async function Get(): Promise<KubernetesListObject<K>>;
92
169
  async function Get(name: string): Promise<K>;
93
170
  /**
@@ -27,7 +27,8 @@ export type FetchMethods =
27
27
  | "DELETE"
28
28
  | "PATCH"
29
29
  | "WATCH"
30
- | "PATCH_STATUS";
30
+ | "PATCH_STATUS"
31
+ | "LOG";
31
32
 
32
33
  export interface Filters {
33
34
  kindOverride?: GroupVersionKind;
@@ -138,8 +138,21 @@ export async function k8sExec<T extends GenericClass, K>(
138
138
  payload?: K | unknown,
139
139
  applyCfg: ApplyCfg = { force: false },
140
140
  ) {
141
- const { opts, serverUrl } = await k8sCfg(method);
142
- const url = pathBuilder(serverUrl, model, filters, method === "POST");
141
+ const reconstruct = async (method: FetchMethods) => {
142
+ const configMethod = method === "LOG" ? "GET" : method;
143
+ const { opts, serverUrl } = await k8sCfg(configMethod);
144
+ const isPost = method === "POST";
145
+ const baseUrl = pathBuilder(serverUrl, model, filters, isPost);
146
+ if (method === "LOG") {
147
+ baseUrl.pathname = `${baseUrl.pathname}/log`;
148
+ }
149
+ return {
150
+ url: baseUrl,
151
+ opts,
152
+ };
153
+ };
154
+
155
+ const { opts, url } = await reconstruct(method);
143
156
 
144
157
  switch (opts.method) {
145
158
  // PATCH_STATUS is a special case that uses the PATCH method on status subresources
@@ -39,6 +39,8 @@ export enum WatchEvent {
39
39
 
40
40
  /** Configuration for the watch function. */
41
41
  export type WatchCfg = {
42
+ /** Whether to allow watch bookmarks. */
43
+ allowWatchBookmarks?: boolean;
42
44
  /** The resource version to start the watch at, this will be updated on each event. */
43
45
  resourceVersion?: string;
44
46
  /** The maximum number of times to retry the watch, the retry count is reset on success. Unlimited retries if not specified. */
@@ -175,6 +177,7 @@ export class Watcher<T extends GenericClass> {
175
177
  #buildURL = async () => {
176
178
  // Build the path and query params for the resource, excluding the name
177
179
  const { opts, serverUrl } = await k8sCfg("GET");
180
+
178
181
  const url = pathBuilder(serverUrl, this.#model, this.#filters, true);
179
182
 
180
183
  // Enable the watch query param
@@ -191,7 +194,10 @@ export class Watcher<T extends GenericClass> {
191
194
  }
192
195
 
193
196
  // Enable watch bookmarks
194
- url.searchParams.set("allowWatchBookmarks", "true");
197
+ url.searchParams.set(
198
+ "allowWatchBookmarks",
199
+ this.#watchCfg.allowWatchBookmarks ? `${this.#watchCfg.allowWatchBookmarks}` : "true",
200
+ );
195
201
 
196
202
  // Add the abort signal to the request options
197
203
  opts.signal = this.#abortController.signal;
@@ -340,6 +346,7 @@ export class Watcher<T extends GenericClass> {
340
346
  this.#events.emit(WatchEvent.RECONNECT, err, this.#retryCount);
341
347
 
342
348
  if (this.#pendingReconnect) {
349
+ // wait for the connection to be re-established
343
350
  this.#events.emit(WatchEvent.RECONNECT_PENDING);
344
351
  } else {
345
352
  this.#pendingReconnect = true;
@@ -3,7 +3,7 @@
3
3
 
4
4
  import { describe, expect, it, test } from "@jest/globals";
5
5
 
6
- import { fromEnv, waitForCluster } from "./helpers";
6
+ import { fromEnv, hasLogs, waitForCluster } from "./helpers";
7
7
 
8
8
  describe("helpers", () => {
9
9
  test("fromEnv for NodeJS", () => {
@@ -23,3 +23,20 @@ describe("Cluster Wait Function", () => {
23
23
  expect(cluster).toEqual({ server: "http://jest-test:8080" });
24
24
  });
25
25
  });
26
+
27
+ describe("hasLogs function", () => {
28
+ it("should return true for known kinds", () => {
29
+ expect(hasLogs("Pod")).toBe(true);
30
+ expect(hasLogs("DaemonSet")).toBe(true);
31
+ expect(hasLogs("ReplicaSet")).toBe(true);
32
+ expect(hasLogs("Service")).toBe(true);
33
+ expect(hasLogs("StatefulSet")).toBe(true);
34
+ expect(hasLogs("Deployment")).toBe(true);
35
+ });
36
+
37
+ it("should return false for unknown kinds", () => {
38
+ expect(hasLogs("Unknown")).toBe(false);
39
+ expect(hasLogs("")).toBe(false);
40
+ expect(hasLogs("RandomKind")).toBe(false);
41
+ });
42
+ });
package/src/helpers.ts CHANGED
@@ -80,3 +80,34 @@ export async function waitForCluster(seconds = 30): Promise<Cluster> {
80
80
 
81
81
  return cluster;
82
82
  }
83
+
84
+ /**
85
+ * Determines if object has logs.
86
+ *
87
+ * @param kind The kind of Kubernetes object.
88
+ * @returns boolean.
89
+ */
90
+ export function hasLogs(kind: string): boolean {
91
+ let hasSelector: boolean = false;
92
+ switch (kind) {
93
+ case "Pod":
94
+ hasSelector = true;
95
+ break;
96
+ case "DaemonSet":
97
+ hasSelector = true;
98
+ break;
99
+ case "ReplicaSet":
100
+ hasSelector = true;
101
+ break;
102
+ case "Service":
103
+ hasSelector = true;
104
+ break;
105
+ case "StatefulSet":
106
+ hasSelector = true;
107
+ break;
108
+ case "Deployment":
109
+ hasSelector = true;
110
+ break;
111
+ }
112
+ return hasSelector;
113
+ }