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 +4 -0
- package/dist/fluent/index.d.ts.map +1 -1
- package/dist/fluent/index.js +64 -1
- package/dist/fluent/types.d.ts +1 -1
- package/dist/fluent/types.d.ts.map +1 -1
- package/dist/fluent/utils.d.ts.map +1 -1
- package/dist/fluent/utils.js +14 -2
- package/dist/fluent/watch.d.ts +2 -0
- package/dist/fluent/watch.d.ts.map +1 -1
- package/dist/fluent/watch.js +2 -1
- package/dist/helpers.d.ts +7 -0
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +32 -1
- package/dist/helpers.test.js +15 -0
- package/package.json +10 -10
- package/src/fluent/index.ts +79 -2
- package/src/fluent/types.ts +2 -1
- package/src/fluent/utils.ts +15 -2
- package/src/fluent/watch.ts +8 -1
- package/src/helpers.test.ts +18 -1
- package/src/helpers.ts +31 -0
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;
|
|
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"}
|
package/dist/fluent/index.js
CHANGED
|
@@ -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}
|
package/dist/fluent/types.d.ts
CHANGED
|
@@ -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":"AAGA,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AACjF,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAE5C;;GAEG;AACH,oBAAY,UAAU;IACpB,KAAK,UAAU;IACf,QAAQ,aAAa;IACrB,OAAO,YAAY;IACnB,QAAQ,aAAa;IACrB,KAAK,UAAU;CAChB;AAED,MAAM,MAAM,YAAY,GACpB,KAAK,GACL,OAAO,GACP,MAAM,GACN,KAAK,GACL,QAAQ,GACR,OAAO,GACP,OAAO,GACP,cAAc,CAAC;
|
|
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,
|
|
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"}
|
package/dist/fluent/utils.js
CHANGED
|
@@ -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
|
|
109
|
-
|
|
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/fluent/watch.d.ts
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/fluent/watch.js
CHANGED
|
@@ -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
|
package/dist/helpers.d.ts.map
CHANGED
|
@@ -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;
|
package/dist/helpers.test.js
CHANGED
|
@@ -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
|
+
"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.
|
|
44
|
-
"type-fest": "4.
|
|
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.
|
|
49
|
-
"@commitlint/config-conventional": "19.
|
|
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.
|
|
52
|
+
"@types/readable-stream": "4.0.12",
|
|
53
53
|
"@types/yargs": "17.0.32",
|
|
54
|
-
"@typescript-eslint/eslint-plugin": "7.
|
|
55
|
-
"@typescript-eslint/parser": "7.
|
|
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.
|
|
60
|
+
"semantic-release": "23.0.8",
|
|
61
61
|
"ts-jest": "29.1.2",
|
|
62
|
-
"typescript": "5.4.
|
|
62
|
+
"typescript": "5.4.5"
|
|
63
63
|
},
|
|
64
64
|
"release": {
|
|
65
65
|
"branches": [
|
package/src/fluent/index.ts
CHANGED
|
@@ -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
|
/**
|
package/src/fluent/types.ts
CHANGED
package/src/fluent/utils.ts
CHANGED
|
@@ -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
|
|
142
|
-
|
|
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
|
package/src/fluent/watch.ts
CHANGED
|
@@ -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(
|
|
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;
|
package/src/helpers.test.ts
CHANGED
|
@@ -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
|
+
}
|