kubernetes-fluent-client 2.0.1 → 2.1.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/dist/fluent/index.d.ts.map +1 -1
- package/dist/fluent/index.js +11 -3
- package/dist/fluent/index.test.js +29 -0
- package/dist/fluent/types.d.ts +24 -3
- package/dist/fluent/types.d.ts.map +1 -1
- package/dist/fluent/utils.d.ts +1 -2
- package/dist/fluent/utils.d.ts.map +1 -1
- package/dist/fluent/utils.js +11 -0
- package/dist/fluent/utils.test.js +86 -4
- package/package.json +1 -1
- package/src/fluent/index.test.ts +36 -0
- package/src/fluent/index.ts +13 -5
- package/src/fluent/types.ts +34 -3
- package/src/fluent/utils.test.ts +115 -4
- package/src/fluent/utils.ts +15 -3
- package/dist/fluent/apply.d.ts +0 -10
- package/dist/fluent/apply.d.ts.map +0 -1
- package/dist/fluent/apply.js +0 -4
- package/src/fluent/apply.ts +0 -12
|
@@ -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;
|
|
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,CA4Kf"}
|
package/dist/fluent/index.js
CHANGED
|
@@ -131,6 +131,14 @@ function K8s(model, filters = {}) {
|
|
|
131
131
|
}
|
|
132
132
|
return (0, utils_1.k8sExec)(model, filters, "PATCH", payload);
|
|
133
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* @inheritdoc
|
|
136
|
+
* @see {@link K8sInit.PatchStatus}
|
|
137
|
+
*/
|
|
138
|
+
async function PatchStatus(resource) {
|
|
139
|
+
syncFilters(resource);
|
|
140
|
+
return (0, utils_1.k8sExec)(model, filters, "PATCH_STATUS", resource);
|
|
141
|
+
}
|
|
134
142
|
/**
|
|
135
143
|
* @inheritdoc
|
|
136
144
|
* @see {@link K8sInit.Watch}
|
|
@@ -142,8 +150,8 @@ function K8s(model, filters = {}) {
|
|
|
142
150
|
* @inheritdoc
|
|
143
151
|
* @see {@link K8sInit.Raw}
|
|
144
152
|
*/
|
|
145
|
-
async function Raw(url) {
|
|
146
|
-
const thing = await (0, utils_1.k8sCfg)(
|
|
153
|
+
async function Raw(url, method = "GET") {
|
|
154
|
+
const thing = await (0, utils_1.k8sCfg)(method);
|
|
147
155
|
const { opts, serverUrl } = thing;
|
|
148
156
|
const resp = await (0, fetch_1.fetch)(`${serverUrl}${url}`, opts);
|
|
149
157
|
if (resp.ok) {
|
|
@@ -151,6 +159,6 @@ function K8s(model, filters = {}) {
|
|
|
151
159
|
}
|
|
152
160
|
throw resp;
|
|
153
161
|
}
|
|
154
|
-
return { InNamespace, Apply, Create, Patch, Raw, ...withFilters };
|
|
162
|
+
return { InNamespace, Apply, Create, Patch, PatchStatus, Raw, ...withFilters };
|
|
155
163
|
}
|
|
156
164
|
exports.K8s = K8s;
|
|
@@ -81,6 +81,35 @@ const generateFakePodManagedFields = (manager) => {
|
|
|
81
81
|
(0, globals_1.expect)(result).toEqual(fakeResource);
|
|
82
82
|
(0, globals_1.expect)(mockedKubeExec).toHaveBeenCalledWith(upstream_1.Pod, {}, "PATCH", patchOperations);
|
|
83
83
|
});
|
|
84
|
+
(0, globals_1.it)("should patch the status of a resource", async () => {
|
|
85
|
+
await (0, _1.K8s)(upstream_1.Pod).PatchStatus({
|
|
86
|
+
metadata: {
|
|
87
|
+
name: "fake",
|
|
88
|
+
namespace: "default",
|
|
89
|
+
managedFields: generateFakePodManagedFields("pepr"),
|
|
90
|
+
},
|
|
91
|
+
spec: { priority: 3 },
|
|
92
|
+
status: {
|
|
93
|
+
phase: "Ready",
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
(0, globals_1.expect)(utils_1.k8sExec).toBeCalledWith(upstream_1.Pod, globals_1.expect.objectContaining({
|
|
97
|
+
name: "fake",
|
|
98
|
+
namespace: "default",
|
|
99
|
+
}), "PATCH_STATUS", {
|
|
100
|
+
apiVersion: "v1",
|
|
101
|
+
kind: "Pod",
|
|
102
|
+
metadata: {
|
|
103
|
+
name: "fake",
|
|
104
|
+
namespace: "default",
|
|
105
|
+
managedFields: generateFakePodManagedFields("pepr"),
|
|
106
|
+
},
|
|
107
|
+
spec: { priority: 3 },
|
|
108
|
+
status: {
|
|
109
|
+
phase: "Ready",
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
});
|
|
84
113
|
(0, globals_1.it)("should filter with WithField", async () => {
|
|
85
114
|
await (0, _1.K8s)(upstream_1.Pod).WithField("metadata.name", "fake").Get();
|
|
86
115
|
(0, globals_1.expect)(mockedKubeExec).toHaveBeenCalledWith(upstream_1.Pod, globals_1.expect.objectContaining({
|
package/dist/fluent/types.d.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { KubernetesListObject, KubernetesObject } from "@kubernetes/client-node"
|
|
|
2
2
|
import { Operation } from "fast-json-patch";
|
|
3
3
|
import type { PartialDeep } from "type-fest";
|
|
4
4
|
import { GenericClass, GroupVersionKind } from "../types";
|
|
5
|
-
import { ApplyCfg } from "./apply";
|
|
6
5
|
import { WatchCfg, Watcher } from "./watch";
|
|
7
6
|
/**
|
|
8
7
|
* The Phase matched when using the K8s Watch API.
|
|
@@ -14,7 +13,7 @@ export declare enum WatchPhase {
|
|
|
14
13
|
Bookmark = "BOOKMARK",
|
|
15
14
|
Error = "ERROR"
|
|
16
15
|
}
|
|
17
|
-
export type FetchMethods = "GET" | "APPLY" | "POST" | "PUT" | "DELETE" | "PATCH" | "WATCH";
|
|
16
|
+
export type FetchMethods = "GET" | "APPLY" | "POST" | "PUT" | "DELETE" | "PATCH" | "WATCH" | "PATCH_STATUS";
|
|
18
17
|
export interface Filters {
|
|
19
18
|
kindOverride?: GroupVersionKind;
|
|
20
19
|
fields?: Record<string, string>;
|
|
@@ -81,6 +80,19 @@ export type K8sUnfilteredActions<K extends KubernetesObject> = {
|
|
|
81
80
|
* @returns The patched resource
|
|
82
81
|
*/
|
|
83
82
|
Patch: (payload: Operation[]) => Promise<K>;
|
|
83
|
+
/**
|
|
84
|
+
* Patch the status of the provided K8s resource. Note this is a special case of the Patch method that
|
|
85
|
+
* only allows patching the status subresource. This can be used in Operator reconciliation loops to
|
|
86
|
+
* update the status of a resource without triggering a new Generation of the resource.
|
|
87
|
+
*
|
|
88
|
+
* See https://stackoverflow.com/q/47100389/467373 for more details.
|
|
89
|
+
*
|
|
90
|
+
* IMPORTANT: This method will throw a 404 error if the resource does not have a status subresource defined.
|
|
91
|
+
*
|
|
92
|
+
* @param resource - the resource to patch
|
|
93
|
+
* @returns the patched resource
|
|
94
|
+
*/
|
|
95
|
+
PatchStatus: (resource: PartialDeep<K>) => Promise<K>;
|
|
84
96
|
/**
|
|
85
97
|
* Perform a raw GET request to the Kubernetes API. This is useful for calling endpoints that are not supported by the fluent API.
|
|
86
98
|
* This command mirrors the `kubectl get --raw` command.
|
|
@@ -98,7 +110,7 @@ export type K8sUnfilteredActions<K extends KubernetesObject> = {
|
|
|
98
110
|
* @param url the URL to call (e.g. /api)
|
|
99
111
|
* @returns
|
|
100
112
|
*/
|
|
101
|
-
Raw: (url: string) => Promise<K>;
|
|
113
|
+
Raw: (url: string, method?: FetchMethods) => Promise<K>;
|
|
102
114
|
};
|
|
103
115
|
export type K8sWithFilters<T extends GenericClass, K extends KubernetesObject> = K8sFilteredActions<T, K> & {
|
|
104
116
|
/**
|
|
@@ -141,6 +153,15 @@ export type K8sWithFilters<T extends GenericClass, K extends KubernetesObject> =
|
|
|
141
153
|
*/
|
|
142
154
|
WithLabel: (key: string, value?: string) => K8sWithFilters<T, K>;
|
|
143
155
|
};
|
|
156
|
+
/**
|
|
157
|
+
* Configuration for the apply function.
|
|
158
|
+
*/
|
|
159
|
+
export type ApplyCfg = {
|
|
160
|
+
/**
|
|
161
|
+
* Force the apply to be a create.
|
|
162
|
+
*/
|
|
163
|
+
force?: boolean;
|
|
164
|
+
};
|
|
144
165
|
export type K8sInit<T extends GenericClass, K extends KubernetesObject> = K8sWithFilters<T, K> & K8sUnfilteredActions<K> & {
|
|
145
166
|
/**
|
|
146
167
|
* Set the namespace filter.
|
|
@@ -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,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/fluent/types.ts"],"names":[],"mappings":"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"}
|
package/dist/fluent/utils.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { URL } from "url";
|
|
3
3
|
import { GenericClass } from "../types";
|
|
4
|
-
import { FetchMethods, Filters } from "./types";
|
|
5
|
-
import { ApplyCfg } from "./apply";
|
|
4
|
+
import { ApplyCfg, FetchMethods, Filters } from "./types";
|
|
6
5
|
/**
|
|
7
6
|
* Generate a path to a Kubernetes resource
|
|
8
7
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/fluent/utils.ts"],"names":[],"mappings":";
|
|
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"}
|
package/dist/fluent/utils.js
CHANGED
|
@@ -108,6 +108,13 @@ async function k8sExec(model, filters, method, payload, applyCfg = { force: fals
|
|
|
108
108
|
const { opts, serverUrl } = await k8sCfg(method);
|
|
109
109
|
const url = pathBuilder(serverUrl, model, filters, method === "POST");
|
|
110
110
|
switch (opts.method) {
|
|
111
|
+
// PATCH_STATUS is a special case that uses the PATCH method on status subresources
|
|
112
|
+
case "PATCH_STATUS":
|
|
113
|
+
opts.method = "PATCH";
|
|
114
|
+
url.pathname = `${url.pathname}/status`;
|
|
115
|
+
opts.headers.set("Content-Type", client_node_1.PatchStrategy.MergePatch);
|
|
116
|
+
payload = { status: payload.status };
|
|
117
|
+
break;
|
|
111
118
|
case "PATCH":
|
|
112
119
|
opts.headers.set("Content-Type", client_node_1.PatchStrategy.JsonPatch);
|
|
113
120
|
break;
|
|
@@ -126,6 +133,10 @@ async function k8sExec(model, filters, method, payload, applyCfg = { force: fals
|
|
|
126
133
|
if (resp.ok) {
|
|
127
134
|
return resp.data;
|
|
128
135
|
}
|
|
136
|
+
if (resp.status === 404 && method === "PATCH_STATUS") {
|
|
137
|
+
resp.statusText =
|
|
138
|
+
"Not Found" + " (NOTE: This error is expected if the resource has no status subresource)";
|
|
139
|
+
}
|
|
129
140
|
throw resp;
|
|
130
141
|
}
|
|
131
142
|
exports.k8sExec = k8sExec;
|
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
// SPDX-FileCopyrightText: 2023-Present The Kubernetes Fluent Client Authors
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
5
|
const globals_1 = require("@jest/globals");
|
|
6
|
+
const node_fetch_1 = require("node-fetch");
|
|
6
7
|
const fetch_1 = require("../fetch");
|
|
8
|
+
const kinds_1 = require("../kinds");
|
|
7
9
|
const upstream_1 = require("../upstream");
|
|
8
10
|
const utils_1 = require("./utils");
|
|
9
|
-
const kinds_1 = require("../kinds");
|
|
10
11
|
globals_1.jest.mock("https");
|
|
11
12
|
globals_1.jest.mock("../fetch");
|
|
12
13
|
(0, globals_1.describe)("pathBuilder Function", () => {
|
|
@@ -92,14 +93,18 @@ globals_1.jest.mock("../fetch");
|
|
|
92
93
|
const mockedFetch = globals_1.jest.mocked(fetch_1.fetch);
|
|
93
94
|
const fakeFilters = { name: "fake", namespace: "default" };
|
|
94
95
|
const fakeMethod = "GET";
|
|
95
|
-
const fakePayload = {
|
|
96
|
+
const fakePayload = {
|
|
97
|
+
metadata: { name: "fake", namespace: "default" },
|
|
98
|
+
status: { phase: "Ready" },
|
|
99
|
+
};
|
|
96
100
|
const fakeUrl = new URL("http://jest-test:8080/api/v1/namespaces/default/pods/fake");
|
|
97
101
|
const fakeOpts = {
|
|
98
102
|
body: JSON.stringify(fakePayload),
|
|
99
|
-
|
|
103
|
+
compress: true,
|
|
104
|
+
headers: new node_fetch_1.Headers({
|
|
100
105
|
"Content-Type": "application/json",
|
|
101
106
|
"User-Agent": `kubernetes-fluent-client`,
|
|
102
|
-
},
|
|
107
|
+
}),
|
|
103
108
|
method: fakeMethod,
|
|
104
109
|
};
|
|
105
110
|
(0, globals_1.beforeEach)(() => {
|
|
@@ -116,6 +121,83 @@ globals_1.jest.mock("../fetch");
|
|
|
116
121
|
(0, globals_1.expect)(result).toEqual(fakePayload);
|
|
117
122
|
(0, globals_1.expect)(mockedFetch).toHaveBeenCalledWith(fakeUrl, globals_1.expect.objectContaining(fakeOpts));
|
|
118
123
|
});
|
|
124
|
+
(0, globals_1.it)("should handle PATCH_STATUS", async () => {
|
|
125
|
+
mockedFetch.mockResolvedValueOnce({
|
|
126
|
+
ok: true,
|
|
127
|
+
data: fakePayload,
|
|
128
|
+
status: 200,
|
|
129
|
+
statusText: "OK",
|
|
130
|
+
});
|
|
131
|
+
const result = await (0, utils_1.k8sExec)(upstream_1.Pod, fakeFilters, "PATCH_STATUS", fakePayload);
|
|
132
|
+
(0, globals_1.expect)(result).toEqual(fakePayload);
|
|
133
|
+
(0, globals_1.expect)(mockedFetch).toHaveBeenCalledWith(new URL("http://jest-test:8080/api/v1/namespaces/default/pods/fake/status"), globals_1.expect.objectContaining({
|
|
134
|
+
method: "PATCH",
|
|
135
|
+
compress: true,
|
|
136
|
+
headers: new node_fetch_1.Headers({
|
|
137
|
+
"Content-Type": "application/merge-patch+json",
|
|
138
|
+
"User-Agent": `kubernetes-fluent-client`,
|
|
139
|
+
}),
|
|
140
|
+
body: JSON.stringify({ status: fakePayload.status }),
|
|
141
|
+
}));
|
|
142
|
+
});
|
|
143
|
+
(0, globals_1.it)("should handle PATCH", async () => {
|
|
144
|
+
mockedFetch.mockResolvedValueOnce({
|
|
145
|
+
ok: true,
|
|
146
|
+
data: fakePayload,
|
|
147
|
+
status: 200,
|
|
148
|
+
statusText: "OK",
|
|
149
|
+
});
|
|
150
|
+
const patchPayload = [{ op: "replace", path: "/status/phase", value: "Ready" }];
|
|
151
|
+
const result = await (0, utils_1.k8sExec)(upstream_1.Pod, fakeFilters, "PATCH", patchPayload);
|
|
152
|
+
(0, globals_1.expect)(result).toEqual(fakePayload);
|
|
153
|
+
(0, globals_1.expect)(mockedFetch).toHaveBeenCalledWith(new URL("http://jest-test:8080/api/v1/namespaces/default/pods/fake"), globals_1.expect.objectContaining({
|
|
154
|
+
method: "PATCH",
|
|
155
|
+
compress: true,
|
|
156
|
+
headers: new node_fetch_1.Headers({
|
|
157
|
+
"Content-Type": "application/json-patch+json",
|
|
158
|
+
"User-Agent": `kubernetes-fluent-client`,
|
|
159
|
+
}),
|
|
160
|
+
body: JSON.stringify(patchPayload),
|
|
161
|
+
}));
|
|
162
|
+
});
|
|
163
|
+
(0, globals_1.it)("should handle APPLY", async () => {
|
|
164
|
+
mockedFetch.mockResolvedValueOnce({
|
|
165
|
+
ok: true,
|
|
166
|
+
data: fakePayload,
|
|
167
|
+
status: 200,
|
|
168
|
+
statusText: "OK",
|
|
169
|
+
});
|
|
170
|
+
const result = await (0, utils_1.k8sExec)(upstream_1.Pod, fakeFilters, "APPLY", fakePayload);
|
|
171
|
+
(0, globals_1.expect)(result).toEqual(fakePayload);
|
|
172
|
+
(0, globals_1.expect)(mockedFetch).toHaveBeenCalledWith(new URL("http://jest-test:8080/api/v1/namespaces/default/pods/fake?fieldManager=pepr&fieldValidation=Strict&force=false"), globals_1.expect.objectContaining({
|
|
173
|
+
method: "PATCH",
|
|
174
|
+
compress: true,
|
|
175
|
+
headers: new node_fetch_1.Headers({
|
|
176
|
+
"Content-Type": "application/apply-patch+yaml",
|
|
177
|
+
"User-Agent": `kubernetes-fluent-client`,
|
|
178
|
+
}),
|
|
179
|
+
body: JSON.stringify(fakePayload),
|
|
180
|
+
}));
|
|
181
|
+
});
|
|
182
|
+
(0, globals_1.it)("should handle APPLY with force", async () => {
|
|
183
|
+
mockedFetch.mockResolvedValueOnce({
|
|
184
|
+
ok: true,
|
|
185
|
+
data: fakePayload,
|
|
186
|
+
status: 200,
|
|
187
|
+
statusText: "OK",
|
|
188
|
+
});
|
|
189
|
+
const result = await (0, utils_1.k8sExec)(upstream_1.Pod, fakeFilters, "APPLY", fakePayload, { force: true });
|
|
190
|
+
(0, globals_1.expect)(result).toEqual(fakePayload);
|
|
191
|
+
(0, globals_1.expect)(mockedFetch).toHaveBeenCalledWith(new URL("http://jest-test:8080/api/v1/namespaces/default/pods/fake?fieldManager=pepr&fieldValidation=Strict&force=true"), globals_1.expect.objectContaining({
|
|
192
|
+
method: "PATCH",
|
|
193
|
+
compress: true,
|
|
194
|
+
headers: new node_fetch_1.Headers({
|
|
195
|
+
"Content-Type": "application/apply-patch+yaml",
|
|
196
|
+
"User-Agent": `kubernetes-fluent-client`,
|
|
197
|
+
}),
|
|
198
|
+
body: JSON.stringify(fakePayload),
|
|
199
|
+
}));
|
|
200
|
+
});
|
|
119
201
|
(0, globals_1.it)("should handle fetch call failure", async () => {
|
|
120
202
|
const fakeStatus = 404;
|
|
121
203
|
const fakeStatusText = "Not Found";
|
package/package.json
CHANGED
package/src/fluent/index.test.ts
CHANGED
|
@@ -102,6 +102,42 @@ describe("Kube", () => {
|
|
|
102
102
|
expect(mockedKubeExec).toHaveBeenCalledWith(Pod, {}, "PATCH", patchOperations);
|
|
103
103
|
});
|
|
104
104
|
|
|
105
|
+
it("should patch the status of a resource", async () => {
|
|
106
|
+
await K8s(Pod).PatchStatus({
|
|
107
|
+
metadata: {
|
|
108
|
+
name: "fake",
|
|
109
|
+
namespace: "default",
|
|
110
|
+
managedFields: generateFakePodManagedFields("pepr"),
|
|
111
|
+
},
|
|
112
|
+
spec: { priority: 3 },
|
|
113
|
+
status: {
|
|
114
|
+
phase: "Ready",
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
expect(k8sExec).toBeCalledWith(
|
|
119
|
+
Pod,
|
|
120
|
+
expect.objectContaining({
|
|
121
|
+
name: "fake",
|
|
122
|
+
namespace: "default",
|
|
123
|
+
}),
|
|
124
|
+
"PATCH_STATUS",
|
|
125
|
+
{
|
|
126
|
+
apiVersion: "v1",
|
|
127
|
+
kind: "Pod",
|
|
128
|
+
metadata: {
|
|
129
|
+
name: "fake",
|
|
130
|
+
namespace: "default",
|
|
131
|
+
managedFields: generateFakePodManagedFields("pepr"),
|
|
132
|
+
},
|
|
133
|
+
spec: { priority: 3 },
|
|
134
|
+
status: {
|
|
135
|
+
phase: "Ready",
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
);
|
|
139
|
+
});
|
|
140
|
+
|
|
105
141
|
it("should filter with WithField", async () => {
|
|
106
142
|
await K8s(Pod).WithField("metadata.name", "fake").Get();
|
|
107
143
|
|
package/src/fluent/index.ts
CHANGED
|
@@ -9,8 +9,7 @@ import type { PartialDeep } from "type-fest";
|
|
|
9
9
|
import { fetch } from "../fetch";
|
|
10
10
|
import { modelToGroupVersionKind } from "../kinds";
|
|
11
11
|
import { GenericClass } from "../types";
|
|
12
|
-
import { ApplyCfg } from "./
|
|
13
|
-
import { Filters, K8sInit, Paths, WatchAction } from "./types";
|
|
12
|
+
import { ApplyCfg, FetchMethods, Filters, K8sInit, Paths, WatchAction } from "./types";
|
|
14
13
|
import { k8sCfg, k8sExec } from "./utils";
|
|
15
14
|
import { WatchCfg, Watcher } from "./watch";
|
|
16
15
|
|
|
@@ -162,6 +161,15 @@ export function K8s<T extends GenericClass, K extends KubernetesObject = Instanc
|
|
|
162
161
|
return k8sExec(model, filters, "PATCH", payload);
|
|
163
162
|
}
|
|
164
163
|
|
|
164
|
+
/**
|
|
165
|
+
* @inheritdoc
|
|
166
|
+
* @see {@link K8sInit.PatchStatus}
|
|
167
|
+
*/
|
|
168
|
+
async function PatchStatus(resource: PartialDeep<K>): Promise<K> {
|
|
169
|
+
syncFilters(resource as K);
|
|
170
|
+
return k8sExec(model, filters, "PATCH_STATUS", resource);
|
|
171
|
+
}
|
|
172
|
+
|
|
165
173
|
/**
|
|
166
174
|
* @inheritdoc
|
|
167
175
|
* @see {@link K8sInit.Watch}
|
|
@@ -174,8 +182,8 @@ export function K8s<T extends GenericClass, K extends KubernetesObject = Instanc
|
|
|
174
182
|
* @inheritdoc
|
|
175
183
|
* @see {@link K8sInit.Raw}
|
|
176
184
|
*/
|
|
177
|
-
async function Raw(url: string) {
|
|
178
|
-
const thing = await k8sCfg(
|
|
185
|
+
async function Raw(url: string, method: FetchMethods = "GET") {
|
|
186
|
+
const thing = await k8sCfg(method);
|
|
179
187
|
const { opts, serverUrl } = thing;
|
|
180
188
|
const resp = await fetch<K>(`${serverUrl}${url}`, opts);
|
|
181
189
|
|
|
@@ -186,5 +194,5 @@ export function K8s<T extends GenericClass, K extends KubernetesObject = Instanc
|
|
|
186
194
|
throw resp;
|
|
187
195
|
}
|
|
188
196
|
|
|
189
|
-
return { InNamespace, Apply, Create, Patch, Raw, ...withFilters };
|
|
197
|
+
return { InNamespace, Apply, Create, Patch, PatchStatus, Raw, ...withFilters };
|
|
190
198
|
}
|
package/src/fluent/types.ts
CHANGED
|
@@ -6,7 +6,6 @@ import { Operation } from "fast-json-patch";
|
|
|
6
6
|
import type { PartialDeep } from "type-fest";
|
|
7
7
|
|
|
8
8
|
import { GenericClass, GroupVersionKind } from "../types";
|
|
9
|
-
import { ApplyCfg } from "./apply";
|
|
10
9
|
import { WatchCfg, Watcher } from "./watch";
|
|
11
10
|
|
|
12
11
|
/**
|
|
@@ -20,7 +19,15 @@ export enum WatchPhase {
|
|
|
20
19
|
Error = "ERROR",
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
export type FetchMethods =
|
|
22
|
+
export type FetchMethods =
|
|
23
|
+
| "GET"
|
|
24
|
+
| "APPLY"
|
|
25
|
+
| "POST"
|
|
26
|
+
| "PUT"
|
|
27
|
+
| "DELETE"
|
|
28
|
+
| "PATCH"
|
|
29
|
+
| "WATCH"
|
|
30
|
+
| "PATCH_STATUS";
|
|
24
31
|
|
|
25
32
|
export interface Filters {
|
|
26
33
|
kindOverride?: GroupVersionKind;
|
|
@@ -96,6 +103,20 @@ export type K8sUnfilteredActions<K extends KubernetesObject> = {
|
|
|
96
103
|
*/
|
|
97
104
|
Patch: (payload: Operation[]) => Promise<K>;
|
|
98
105
|
|
|
106
|
+
/**
|
|
107
|
+
* Patch the status of the provided K8s resource. Note this is a special case of the Patch method that
|
|
108
|
+
* only allows patching the status subresource. This can be used in Operator reconciliation loops to
|
|
109
|
+
* update the status of a resource without triggering a new Generation of the resource.
|
|
110
|
+
*
|
|
111
|
+
* See https://stackoverflow.com/q/47100389/467373 for more details.
|
|
112
|
+
*
|
|
113
|
+
* IMPORTANT: This method will throw a 404 error if the resource does not have a status subresource defined.
|
|
114
|
+
*
|
|
115
|
+
* @param resource - the resource to patch
|
|
116
|
+
* @returns the patched resource
|
|
117
|
+
*/
|
|
118
|
+
PatchStatus: (resource: PartialDeep<K>) => Promise<K>;
|
|
119
|
+
|
|
99
120
|
/**
|
|
100
121
|
* Perform a raw GET request to the Kubernetes API. This is useful for calling endpoints that are not supported by the fluent API.
|
|
101
122
|
* This command mirrors the `kubectl get --raw` command.
|
|
@@ -113,7 +134,7 @@ export type K8sUnfilteredActions<K extends KubernetesObject> = {
|
|
|
113
134
|
* @param url the URL to call (e.g. /api)
|
|
114
135
|
* @returns
|
|
115
136
|
*/
|
|
116
|
-
Raw: (url: string) => Promise<K>;
|
|
137
|
+
Raw: (url: string, method?: FetchMethods) => Promise<K>;
|
|
117
138
|
};
|
|
118
139
|
|
|
119
140
|
export type K8sWithFilters<T extends GenericClass, K extends KubernetesObject> = K8sFilteredActions<
|
|
@@ -162,6 +183,16 @@ export type K8sWithFilters<T extends GenericClass, K extends KubernetesObject> =
|
|
|
162
183
|
WithLabel: (key: string, value?: string) => K8sWithFilters<T, K>;
|
|
163
184
|
};
|
|
164
185
|
|
|
186
|
+
/**
|
|
187
|
+
* Configuration for the apply function.
|
|
188
|
+
*/
|
|
189
|
+
export type ApplyCfg = {
|
|
190
|
+
/**
|
|
191
|
+
* Force the apply to be a create.
|
|
192
|
+
*/
|
|
193
|
+
force?: boolean;
|
|
194
|
+
};
|
|
195
|
+
|
|
165
196
|
export type K8sInit<T extends GenericClass, K extends KubernetesObject> = K8sWithFilters<T, K> &
|
|
166
197
|
K8sUnfilteredActions<K> & {
|
|
167
198
|
/**
|
package/src/fluent/utils.test.ts
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
// SPDX-FileCopyrightText: 2023-Present The Kubernetes Fluent Client Authors
|
|
3
3
|
|
|
4
4
|
import { beforeEach, describe, expect, it, jest } from "@jest/globals";
|
|
5
|
+
import { Headers } from "node-fetch";
|
|
5
6
|
|
|
6
7
|
import { fetch } from "../fetch";
|
|
8
|
+
import { RegisterKind } from "../kinds";
|
|
7
9
|
import { GenericClass } from "../types";
|
|
8
10
|
import { ClusterRole, Ingress, Pod } from "../upstream";
|
|
9
11
|
import { Filters } from "./types";
|
|
10
12
|
import { k8sExec, pathBuilder } from "./utils";
|
|
11
|
-
import { RegisterKind } from "../kinds";
|
|
12
13
|
|
|
13
14
|
jest.mock("https");
|
|
14
15
|
jest.mock("../fetch");
|
|
@@ -115,14 +116,18 @@ describe("kubeExec Function", () => {
|
|
|
115
116
|
|
|
116
117
|
const fakeFilters: Filters = { name: "fake", namespace: "default" };
|
|
117
118
|
const fakeMethod = "GET";
|
|
118
|
-
const fakePayload = {
|
|
119
|
+
const fakePayload = {
|
|
120
|
+
metadata: { name: "fake", namespace: "default" },
|
|
121
|
+
status: { phase: "Ready" },
|
|
122
|
+
};
|
|
119
123
|
const fakeUrl = new URL("http://jest-test:8080/api/v1/namespaces/default/pods/fake");
|
|
120
124
|
const fakeOpts = {
|
|
121
125
|
body: JSON.stringify(fakePayload),
|
|
122
|
-
|
|
126
|
+
compress: true,
|
|
127
|
+
headers: new Headers({
|
|
123
128
|
"Content-Type": "application/json",
|
|
124
129
|
"User-Agent": `kubernetes-fluent-client`,
|
|
125
|
-
},
|
|
130
|
+
}),
|
|
126
131
|
method: fakeMethod,
|
|
127
132
|
};
|
|
128
133
|
|
|
@@ -144,6 +149,112 @@ describe("kubeExec Function", () => {
|
|
|
144
149
|
expect(mockedFetch).toHaveBeenCalledWith(fakeUrl, expect.objectContaining(fakeOpts));
|
|
145
150
|
});
|
|
146
151
|
|
|
152
|
+
it("should handle PATCH_STATUS", async () => {
|
|
153
|
+
mockedFetch.mockResolvedValueOnce({
|
|
154
|
+
ok: true,
|
|
155
|
+
data: fakePayload,
|
|
156
|
+
status: 200,
|
|
157
|
+
statusText: "OK",
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
const result = await k8sExec(Pod, fakeFilters, "PATCH_STATUS", fakePayload);
|
|
161
|
+
|
|
162
|
+
expect(result).toEqual(fakePayload);
|
|
163
|
+
expect(mockedFetch).toHaveBeenCalledWith(
|
|
164
|
+
new URL("http://jest-test:8080/api/v1/namespaces/default/pods/fake/status"),
|
|
165
|
+
expect.objectContaining({
|
|
166
|
+
method: "PATCH",
|
|
167
|
+
compress: true,
|
|
168
|
+
headers: new Headers({
|
|
169
|
+
"Content-Type": "application/merge-patch+json",
|
|
170
|
+
"User-Agent": `kubernetes-fluent-client`,
|
|
171
|
+
}),
|
|
172
|
+
body: JSON.stringify({ status: fakePayload.status }),
|
|
173
|
+
}),
|
|
174
|
+
);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it("should handle PATCH", async () => {
|
|
178
|
+
mockedFetch.mockResolvedValueOnce({
|
|
179
|
+
ok: true,
|
|
180
|
+
data: fakePayload,
|
|
181
|
+
status: 200,
|
|
182
|
+
statusText: "OK",
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
const patchPayload = [{ op: "replace", path: "/status/phase", value: "Ready" }];
|
|
186
|
+
|
|
187
|
+
const result = await k8sExec(Pod, fakeFilters, "PATCH", patchPayload);
|
|
188
|
+
|
|
189
|
+
expect(result).toEqual(fakePayload);
|
|
190
|
+
expect(mockedFetch).toHaveBeenCalledWith(
|
|
191
|
+
new URL("http://jest-test:8080/api/v1/namespaces/default/pods/fake"),
|
|
192
|
+
expect.objectContaining({
|
|
193
|
+
method: "PATCH",
|
|
194
|
+
compress: true,
|
|
195
|
+
headers: new Headers({
|
|
196
|
+
"Content-Type": "application/json-patch+json",
|
|
197
|
+
"User-Agent": `kubernetes-fluent-client`,
|
|
198
|
+
}),
|
|
199
|
+
body: JSON.stringify(patchPayload),
|
|
200
|
+
}),
|
|
201
|
+
);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it("should handle APPLY", async () => {
|
|
205
|
+
mockedFetch.mockResolvedValueOnce({
|
|
206
|
+
ok: true,
|
|
207
|
+
data: fakePayload,
|
|
208
|
+
status: 200,
|
|
209
|
+
statusText: "OK",
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
const result = await k8sExec(Pod, fakeFilters, "APPLY", fakePayload);
|
|
213
|
+
|
|
214
|
+
expect(result).toEqual(fakePayload);
|
|
215
|
+
expect(mockedFetch).toHaveBeenCalledWith(
|
|
216
|
+
new URL(
|
|
217
|
+
"http://jest-test:8080/api/v1/namespaces/default/pods/fake?fieldManager=pepr&fieldValidation=Strict&force=false",
|
|
218
|
+
),
|
|
219
|
+
expect.objectContaining({
|
|
220
|
+
method: "PATCH",
|
|
221
|
+
compress: true,
|
|
222
|
+
headers: new Headers({
|
|
223
|
+
"Content-Type": "application/apply-patch+yaml",
|
|
224
|
+
"User-Agent": `kubernetes-fluent-client`,
|
|
225
|
+
}),
|
|
226
|
+
body: JSON.stringify(fakePayload),
|
|
227
|
+
}),
|
|
228
|
+
);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it("should handle APPLY with force", async () => {
|
|
232
|
+
mockedFetch.mockResolvedValueOnce({
|
|
233
|
+
ok: true,
|
|
234
|
+
data: fakePayload,
|
|
235
|
+
status: 200,
|
|
236
|
+
statusText: "OK",
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
const result = await k8sExec(Pod, fakeFilters, "APPLY", fakePayload, { force: true });
|
|
240
|
+
|
|
241
|
+
expect(result).toEqual(fakePayload);
|
|
242
|
+
expect(mockedFetch).toHaveBeenCalledWith(
|
|
243
|
+
new URL(
|
|
244
|
+
"http://jest-test:8080/api/v1/namespaces/default/pods/fake?fieldManager=pepr&fieldValidation=Strict&force=true",
|
|
245
|
+
),
|
|
246
|
+
expect.objectContaining({
|
|
247
|
+
method: "PATCH",
|
|
248
|
+
compress: true,
|
|
249
|
+
headers: new Headers({
|
|
250
|
+
"Content-Type": "application/apply-patch+yaml",
|
|
251
|
+
"User-Agent": `kubernetes-fluent-client`,
|
|
252
|
+
}),
|
|
253
|
+
body: JSON.stringify(fakePayload),
|
|
254
|
+
}),
|
|
255
|
+
);
|
|
256
|
+
});
|
|
257
|
+
|
|
147
258
|
it("should handle fetch call failure", async () => {
|
|
148
259
|
const fakeStatus = 404;
|
|
149
260
|
const fakeStatusText = "Not Found";
|
package/src/fluent/utils.ts
CHANGED
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
// SPDX-FileCopyrightText: 2023-Present The Kubernetes Fluent Client Authors
|
|
3
3
|
|
|
4
4
|
import { KubeConfig, PatchStrategy } from "@kubernetes/client-node";
|
|
5
|
-
|
|
6
5
|
import { Headers } from "node-fetch";
|
|
7
6
|
import { URL } from "url";
|
|
7
|
+
|
|
8
8
|
import { fetch } from "../fetch";
|
|
9
9
|
import { modelToGroupVersionKind } from "../kinds";
|
|
10
10
|
import { GenericClass } from "../types";
|
|
11
|
-
import { FetchMethods, Filters } from "./types";
|
|
12
|
-
import { ApplyCfg } from "./apply";
|
|
11
|
+
import { ApplyCfg, FetchMethods, Filters } from "./types";
|
|
13
12
|
|
|
14
13
|
const SSA_CONTENT_TYPE = "application/apply-patch+yaml";
|
|
15
14
|
|
|
@@ -143,6 +142,14 @@ export async function k8sExec<T extends GenericClass, K>(
|
|
|
143
142
|
const url = pathBuilder(serverUrl, model, filters, method === "POST");
|
|
144
143
|
|
|
145
144
|
switch (opts.method) {
|
|
145
|
+
// PATCH_STATUS is a special case that uses the PATCH method on status subresources
|
|
146
|
+
case "PATCH_STATUS":
|
|
147
|
+
opts.method = "PATCH";
|
|
148
|
+
url.pathname = `${url.pathname}/status`;
|
|
149
|
+
(opts.headers as Headers).set("Content-Type", PatchStrategy.MergePatch);
|
|
150
|
+
payload = { status: (payload as { status: unknown }).status };
|
|
151
|
+
break;
|
|
152
|
+
|
|
146
153
|
case "PATCH":
|
|
147
154
|
(opts.headers as Headers).set("Content-Type", PatchStrategy.JsonPatch);
|
|
148
155
|
break;
|
|
@@ -166,5 +173,10 @@ export async function k8sExec<T extends GenericClass, K>(
|
|
|
166
173
|
return resp.data;
|
|
167
174
|
}
|
|
168
175
|
|
|
176
|
+
if (resp.status === 404 && method === "PATCH_STATUS") {
|
|
177
|
+
resp.statusText =
|
|
178
|
+
"Not Found" + " (NOTE: This error is expected if the resource has no status subresource)";
|
|
179
|
+
}
|
|
180
|
+
|
|
169
181
|
throw resp;
|
|
170
182
|
}
|
package/dist/fluent/apply.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../src/fluent/apply.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC"}
|
package/dist/fluent/apply.js
DELETED
package/src/fluent/apply.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
// SPDX-FileCopyrightText: 2023-Present The Kubernetes Fluent Client Authors
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Configuration for the apply function.
|
|
6
|
-
*/
|
|
7
|
-
export type ApplyCfg = {
|
|
8
|
-
/**
|
|
9
|
-
* Force the apply to be a create.
|
|
10
|
-
*/
|
|
11
|
-
force?: boolean;
|
|
12
|
-
};
|