kubernetes-fluent-client 2.3.2 → 2.4.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/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>;
@@ -34,6 +34,13 @@ export type GetFunction<K extends KubernetesObject> = {
34
34
  (name: string): Promise<K>;
35
35
  };
36
36
  export type K8sFilteredActions<T extends GenericClass, K extends KubernetesObject> = {
37
+ /**
38
+ * Gets the logs.
39
+ *
40
+ * @param name - the name of the Object to get logs from
41
+ * @returns array of logs
42
+ */
43
+ Logs: (name: string) => Promise<string[]>;
37
44
  /**
38
45
  * Get the resource or resources matching the filters.
39
46
  * If no filters are specified, all resources will be returned.
@@ -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":
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.2",
3
+ "version": "2.4.1",
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",
@@ -41,7 +41,7 @@
41
41
  "http-status-codes": "2.3.0",
42
42
  "node-fetch": "2.7.0",
43
43
  "quicktype-core": "23.0.158",
44
- "type-fest": "4.18.0",
44
+ "type-fest": "4.18.2",
45
45
  "yargs": "17.7.2"
46
46
  },
47
47
  "devDependencies": {
@@ -49,7 +49,7 @@
49
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
54
  "@typescript-eslint/eslint-plugin": "7.8.0",
55
55
  "@typescript-eslint/parser": "7.8.0",
@@ -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;
@@ -51,6 +52,13 @@ export type GetFunction<K extends KubernetesObject> = {
51
52
  };
52
53
 
53
54
  export type K8sFilteredActions<T extends GenericClass, K extends KubernetesObject> = {
55
+ /**
56
+ * Gets the logs.
57
+ *
58
+ * @param name - the name of the Object to get logs from
59
+ * @returns array of logs
60
+ */
61
+ Logs: (name: string) => Promise<string[]>;
54
62
  /**
55
63
  * Get the resource or resources matching the filters.
56
64
  * If no filters are specified, all resources will be returned.
@@ -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
@@ -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
+ }