kubernetes-fluent-client 3.1.0 → 3.1.2

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.
Files changed (78) hide show
  1. package/dist/cli.d.ts +3 -0
  2. package/dist/cli.d.ts.map +1 -0
  3. package/dist/cli.js +68 -0
  4. package/dist/fetch.d.ts +22 -0
  5. package/dist/fetch.d.ts.map +1 -0
  6. package/dist/fetch.js +82 -0
  7. package/dist/fetch.test.d.ts +2 -0
  8. package/dist/fetch.test.d.ts.map +1 -0
  9. package/dist/fetch.test.js +97 -0
  10. package/dist/fileSystem.d.ts +11 -0
  11. package/dist/fileSystem.d.ts.map +1 -0
  12. package/dist/fileSystem.js +42 -0
  13. package/dist/fileSystem.test.d.ts +2 -0
  14. package/dist/fileSystem.test.d.ts.map +1 -0
  15. package/dist/fileSystem.test.js +75 -0
  16. package/dist/fluent/http2-watch.spec.d.ts +2 -0
  17. package/dist/fluent/http2-watch.spec.d.ts.map +1 -0
  18. package/dist/fluent/http2-watch.spec.js +284 -0
  19. package/dist/fluent/index.d.ts +12 -0
  20. package/dist/fluent/index.d.ts.map +1 -0
  21. package/dist/fluent/index.js +228 -0
  22. package/dist/fluent/index.test.d.ts +2 -0
  23. package/dist/fluent/index.test.d.ts.map +1 -0
  24. package/dist/fluent/index.test.js +193 -0
  25. package/dist/fluent/types.d.ts +201 -0
  26. package/dist/fluent/types.d.ts.map +1 -0
  27. package/dist/fluent/types.js +16 -0
  28. package/dist/fluent/utils.d.ts +41 -0
  29. package/dist/fluent/utils.d.ts.map +1 -0
  30. package/dist/fluent/utils.js +153 -0
  31. package/dist/fluent/utils.test.d.ts +2 -0
  32. package/dist/fluent/utils.test.d.ts.map +1 -0
  33. package/dist/fluent/utils.test.js +215 -0
  34. package/dist/fluent/watch.d.ts +88 -0
  35. package/dist/fluent/watch.d.ts.map +1 -0
  36. package/dist/fluent/watch.js +595 -0
  37. package/dist/fluent/watch.spec.d.ts +2 -0
  38. package/dist/fluent/watch.spec.d.ts.map +1 -0
  39. package/dist/fluent/watch.spec.js +261 -0
  40. package/dist/generate.d.ts +84 -0
  41. package/dist/generate.d.ts.map +1 -0
  42. package/dist/generate.js +208 -0
  43. package/dist/generate.test.d.ts +2 -0
  44. package/dist/generate.test.d.ts.map +1 -0
  45. package/dist/generate.test.js +320 -0
  46. package/dist/helpers.d.ts +33 -0
  47. package/dist/helpers.d.ts.map +1 -0
  48. package/dist/helpers.js +103 -0
  49. package/dist/helpers.test.d.ts +2 -0
  50. package/dist/helpers.test.d.ts.map +1 -0
  51. package/dist/helpers.test.js +37 -0
  52. package/dist/index.d.ts +14 -0
  53. package/dist/index.d.ts.map +1 -0
  54. package/dist/index.js +60 -0
  55. package/dist/kinds.d.ts +16 -0
  56. package/dist/kinds.d.ts.map +1 -0
  57. package/dist/kinds.js +570 -0
  58. package/dist/kinds.test.d.ts +2 -0
  59. package/dist/kinds.test.d.ts.map +1 -0
  60. package/dist/kinds.test.js +155 -0
  61. package/dist/patch.d.ts +7 -0
  62. package/dist/patch.d.ts.map +1 -0
  63. package/dist/patch.js +2 -0
  64. package/dist/postProcessing.d.ts +246 -0
  65. package/dist/postProcessing.d.ts.map +1 -0
  66. package/dist/postProcessing.js +497 -0
  67. package/dist/postProcessing.test.d.ts +2 -0
  68. package/dist/postProcessing.test.d.ts.map +1 -0
  69. package/dist/postProcessing.test.js +550 -0
  70. package/dist/types.d.ts +32 -0
  71. package/dist/types.d.ts.map +1 -0
  72. package/dist/types.js +16 -0
  73. package/dist/upstream.d.ts +4 -0
  74. package/dist/upstream.d.ts.map +1 -0
  75. package/dist/upstream.js +56 -0
  76. package/package.json +1 -1
  77. package/src/fluent/types.ts +16 -0
  78. package/src/fluent/watch.ts +134 -81
@@ -0,0 +1,193 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const globals_1 = require("@jest/globals");
4
+ const client_node_1 = require("@kubernetes/client-node");
5
+ const _1 = require(".");
6
+ const fetch_1 = require("../fetch");
7
+ const upstream_1 = require("../upstream");
8
+ const utils_1 = require("./utils");
9
+ // Setup mocks
10
+ globals_1.jest.mock("./utils");
11
+ globals_1.jest.mock("../fetch");
12
+ const generateFakePodManagedFields = (manager) => {
13
+ return [
14
+ {
15
+ apiVersion: "v1",
16
+ fieldsType: "FieldsV1",
17
+ fieldsV1: {
18
+ "f:metadata": {
19
+ "f:labels": {
20
+ "f:fake": {},
21
+ },
22
+ "f:spec": {
23
+ "f:containers": {
24
+ 'k:{"name":"fake"}': {
25
+ "f:image": {},
26
+ "f:name": {},
27
+ "f:resources": {
28
+ "f:limits": {
29
+ "f:cpu": {},
30
+ "f:memory": {},
31
+ },
32
+ "f:requests": {
33
+ "f:cpu": {},
34
+ "f:memory": {},
35
+ },
36
+ },
37
+ },
38
+ },
39
+ },
40
+ },
41
+ },
42
+ manager: manager,
43
+ operation: "Apply",
44
+ },
45
+ ];
46
+ };
47
+ (0, globals_1.describe)("Kube", () => {
48
+ const fakeResource = {
49
+ metadata: {
50
+ name: "fake",
51
+ namespace: "default",
52
+ managedFields: generateFakePodManagedFields("pepr"),
53
+ },
54
+ };
55
+ const mockedKubeCfg = globals_1.jest.mocked(utils_1.k8sCfg);
56
+ const mockedKubeExec = globals_1.jest.mocked(utils_1.k8sExec).mockResolvedValue(fakeResource);
57
+ (0, globals_1.beforeEach)(() => {
58
+ // Clear all instances and calls to constructor and all methods:
59
+ mockedKubeExec.mockClear();
60
+ });
61
+ (0, globals_1.it)("should create a resource", async () => {
62
+ const result = await (0, _1.K8s)(upstream_1.Pod).Create(fakeResource);
63
+ (0, globals_1.expect)(result).toEqual(fakeResource);
64
+ (0, globals_1.expect)(mockedKubeExec).toHaveBeenCalledWith(upstream_1.Pod, globals_1.expect.objectContaining({
65
+ name: "fake",
66
+ namespace: "default",
67
+ }), "POST", fakeResource);
68
+ });
69
+ (0, globals_1.it)("should delete a resource", async () => {
70
+ await (0, _1.K8s)(upstream_1.Pod).Delete(fakeResource);
71
+ (0, globals_1.expect)(mockedKubeExec).toHaveBeenCalledWith(upstream_1.Pod, globals_1.expect.objectContaining({
72
+ name: "fake",
73
+ namespace: "default",
74
+ }), "DELETE");
75
+ });
76
+ (0, globals_1.it)("should patch a resource", async () => {
77
+ const patchOperations = [
78
+ { op: "replace", path: "/metadata/name", value: "new-fake" },
79
+ ];
80
+ const result = await (0, _1.K8s)(upstream_1.Pod).Patch(patchOperations);
81
+ (0, globals_1.expect)(result).toEqual(fakeResource);
82
+ (0, globals_1.expect)(mockedKubeExec).toHaveBeenCalledWith(upstream_1.Pod, {}, "PATCH", patchOperations);
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
+ });
113
+ (0, globals_1.it)("should filter with WithField", async () => {
114
+ await (0, _1.K8s)(upstream_1.Pod).WithField("metadata.name", "fake").Get();
115
+ (0, globals_1.expect)(mockedKubeExec).toHaveBeenCalledWith(upstream_1.Pod, globals_1.expect.objectContaining({
116
+ fields: {
117
+ "metadata.name": "fake",
118
+ },
119
+ }), "GET");
120
+ });
121
+ (0, globals_1.it)("should filter with WithLabel", async () => {
122
+ await (0, _1.K8s)(upstream_1.Pod).WithLabel("app", "fakeApp").Get();
123
+ (0, globals_1.expect)(mockedKubeExec).toHaveBeenCalledWith(upstream_1.Pod, globals_1.expect.objectContaining({
124
+ labels: {
125
+ app: "fakeApp",
126
+ },
127
+ }), "GET");
128
+ });
129
+ (0, globals_1.it)("should use InNamespace", async () => {
130
+ await (0, _1.K8s)(upstream_1.Pod).InNamespace("fakeNamespace").Get();
131
+ (0, globals_1.expect)(mockedKubeExec).toHaveBeenCalledWith(upstream_1.Pod, globals_1.expect.objectContaining({
132
+ namespace: "fakeNamespace",
133
+ }), "GET");
134
+ });
135
+ (0, globals_1.it)("should throw an error if namespace is already specified", async () => {
136
+ (0, globals_1.expect)(() => (0, _1.K8s)(upstream_1.Pod, { namespace: "default" }).InNamespace("fakeNamespace")).toThrow("Namespace already specified: default");
137
+ });
138
+ (0, globals_1.it)("should handle Delete when the resource doesn't exist", async () => {
139
+ mockedKubeExec.mockRejectedValueOnce({ status: 404 }); // Not Found on first call
140
+ await (0, globals_1.expect)((0, _1.K8s)(upstream_1.Pod).Delete("fakeResource")).resolves.toBeUndefined();
141
+ });
142
+ (0, globals_1.it)("should handle Get", async () => {
143
+ const result = await (0, _1.K8s)(upstream_1.Pod).Get("fakeResource");
144
+ (0, globals_1.expect)(result).toEqual(fakeResource);
145
+ (0, globals_1.expect)(mockedKubeExec).toHaveBeenCalledWith(upstream_1.Pod, globals_1.expect.objectContaining({
146
+ name: "fakeResource",
147
+ }), "GET");
148
+ });
149
+ (0, globals_1.it)("should thrown an error if Get is called with a name and filters are already specified a name", async () => {
150
+ await (0, globals_1.expect)((0, _1.K8s)(upstream_1.Pod, { name: "fake" }).Get("fakeResource")).rejects.toThrow("Name already specified: fake");
151
+ });
152
+ (0, globals_1.it)("should throw an error if no patch operations provided", async () => {
153
+ await (0, globals_1.expect)((0, _1.K8s)(upstream_1.Pod).Patch([])).rejects.toThrow("No operations specified");
154
+ });
155
+ (0, globals_1.it)("should allow Apply of deep partials", async () => {
156
+ const result = await (0, _1.K8s)(upstream_1.Pod).Apply({ metadata: { name: "fake" }, spec: { priority: 3 } });
157
+ (0, globals_1.expect)(result).toEqual(fakeResource);
158
+ });
159
+ (0, globals_1.it)("should allow force apply to resolve FieldManagerConflict", async () => {
160
+ const result = await (0, _1.K8s)(upstream_1.Pod).Apply({
161
+ metadata: { name: "fake", managedFields: generateFakePodManagedFields("kubectl") },
162
+ spec: { priority: 3 },
163
+ }, { force: true });
164
+ (0, globals_1.expect)(result).toEqual(fakeResource);
165
+ });
166
+ (0, globals_1.it)("should throw an error if a Delete failed for a reason other than Not Found", async () => {
167
+ mockedKubeExec.mockRejectedValueOnce({ status: 500 }); // Internal Server Error on first call
168
+ await (0, globals_1.expect)((0, _1.K8s)(upstream_1.Pod).Delete("fakeResource")).rejects.toEqual(globals_1.expect.objectContaining({ status: 500 }));
169
+ });
170
+ (0, globals_1.it)("should create a raw api request", async () => {
171
+ mockedKubeCfg.mockReturnValue(new Promise(r => r({
172
+ serverUrl: "http://localhost:8080",
173
+ opts: {},
174
+ })));
175
+ const mockResp = {
176
+ kind: "APIVersions",
177
+ versions: ["v1"],
178
+ serverAddressByClientCIDRs: [
179
+ {
180
+ serverAddress: "172.27.0.3:6443",
181
+ },
182
+ ],
183
+ };
184
+ globals_1.jest.mocked(fetch_1.fetch).mockResolvedValue({
185
+ ok: true,
186
+ data: mockResp,
187
+ status: 200,
188
+ statusText: "OK",
189
+ });
190
+ const result = await (0, _1.K8s)(client_node_1.V1APIGroup).Raw("/api");
191
+ (0, globals_1.expect)(result).toEqual(mockResp);
192
+ });
193
+ });
@@ -0,0 +1,201 @@
1
+ import { KubernetesListObject, KubernetesObject } from "@kubernetes/client-node";
2
+ import { Operation } from "fast-json-patch";
3
+ import type { PartialDeep } from "type-fest";
4
+ import { GenericClass, GroupVersionKind } from "../types";
5
+ import { WatchCfg, Watcher } from "./watch";
6
+ import https from "https";
7
+ import { SecureClientSessionOptions } from "http2";
8
+ /**
9
+ * Agent options for the the http2Watch
10
+ */
11
+ export type AgentOptions = Pick<SecureClientSessionOptions, "ca" | "cert" | "key" | "rejectUnauthorized">;
12
+ /**
13
+ * Options for the http2Watch
14
+ */
15
+ export interface Options {
16
+ agent?: https.Agent & {
17
+ options?: AgentOptions;
18
+ };
19
+ }
20
+ /**
21
+ * The Phase matched when using the K8s Watch API.
22
+ */
23
+ export declare enum WatchPhase {
24
+ Added = "ADDED",
25
+ Modified = "MODIFIED",
26
+ Deleted = "DELETED",
27
+ Bookmark = "BOOKMARK",
28
+ Error = "ERROR"
29
+ }
30
+ export type FetchMethods = "GET" | "APPLY" | "POST" | "PUT" | "DELETE" | "PATCH" | "WATCH" | "PATCH_STATUS" | "LOG";
31
+ export interface Filters {
32
+ kindOverride?: GroupVersionKind;
33
+ fields?: Record<string, string>;
34
+ labels?: Record<string, string>;
35
+ name?: string;
36
+ namespace?: string;
37
+ }
38
+ /**
39
+ * Get the resource or resources matching the filters.
40
+ * If no filters are specified, all resources will be returned.
41
+ * If a name is specified, only a single resource will be returned.
42
+ *
43
+ * @param name - (optional) the name of the resource to get
44
+ * @returns the resource or list of resources
45
+ */
46
+ export type GetFunction<K extends KubernetesObject> = {
47
+ (): Promise<KubernetesListObject<K>>;
48
+ (name: string): Promise<K>;
49
+ };
50
+ export type K8sFilteredActions<T extends GenericClass, K extends KubernetesObject> = {
51
+ /**
52
+ * Gets the logs.
53
+ *
54
+ * @param name - the name of the Object to get logs from
55
+ * @returns array of logs
56
+ */
57
+ Logs: (name: string) => Promise<string[]>;
58
+ /**
59
+ * Get the resource or resources matching the filters.
60
+ * If no filters are specified, all resources will be returned.
61
+ * If a name is specified, only a single resource will be returned.
62
+ */
63
+ Get: GetFunction<K>;
64
+ /**
65
+ * Delete the resource matching the filters.
66
+ *
67
+ * @param filter - the resource or resource name to delete
68
+ */
69
+ Delete: (filter?: K | string) => Promise<void>;
70
+ /**
71
+ * Watch the resource matching the filters.
72
+ *
73
+ * @param callback - the callback function to call when an event occurs
74
+ * @param watchCfg - (optional) watch configuration
75
+ * @returns a watch controller
76
+ */
77
+ Watch: (callback: WatchAction<T>, watchCfg?: WatchCfg) => Watcher<T>;
78
+ };
79
+ export type K8sUnfilteredActions<K extends KubernetesObject> = {
80
+ /**
81
+ * Perform a server-side apply of the provided K8s resource.
82
+ *
83
+ * @param resource - the resource to apply
84
+ * @param applyCfg - (optional) apply configuration
85
+ * @returns the applied resource
86
+ */
87
+ Apply: (resource: PartialDeep<K>, applyCfg?: ApplyCfg) => Promise<K>;
88
+ /**
89
+ * Create the provided K8s resource or throw an error if it already exists.
90
+ *
91
+ * @param resource - the resource to create
92
+ * @returns the created resource
93
+ */
94
+ Create: (resource: K) => Promise<K>;
95
+ /**
96
+ * Advanced JSON Patch operations for when Server Side Apply, K8s().Apply(), is insufficient.
97
+ *
98
+ * Note: Throws an error on an empty list of patch operations.
99
+ *
100
+ * @param payload The patch operations to run
101
+ * @returns The patched resource
102
+ */
103
+ Patch: (payload: Operation[]) => Promise<K>;
104
+ /**
105
+ * Patch the status of the provided K8s resource. Note this is a special case of the Patch method that
106
+ * only allows patching the status subresource. This can be used in Operator reconciliation loops to
107
+ * update the status of a resource without triggering a new Generation of the resource.
108
+ *
109
+ * See https://stackoverflow.com/q/47100389/467373 for more details.
110
+ *
111
+ * IMPORTANT: This method will throw a 404 error if the resource does not have a status subresource defined.
112
+ *
113
+ * @param resource - the resource to patch
114
+ * @returns the patched resource
115
+ */
116
+ PatchStatus: (resource: PartialDeep<K>) => Promise<K>;
117
+ /**
118
+ * Perform a raw GET request to the Kubernetes API. This is useful for calling endpoints that are not supported by the fluent API.
119
+ * This command mirrors the `kubectl get --raw` command.
120
+ *
121
+ * E.g.
122
+ *
123
+ * ```ts
124
+ * import { V1APIGroup } from "@kubernetes/client-node";
125
+ *
126
+ * K8s(V1APIGroup).Raw("/api")
127
+ * ```
128
+ *
129
+ * will call the `/api` endpoint and is equivalent to `kubectl get --raw /api`.
130
+ *
131
+ * @param url the URL to call (e.g. /api)
132
+ * @returns
133
+ */
134
+ Raw: (url: string, method?: FetchMethods) => Promise<K>;
135
+ };
136
+ export type K8sWithFilters<T extends GenericClass, K extends KubernetesObject> = K8sFilteredActions<T, K> & {
137
+ /**
138
+ * Filter the query by the given field.
139
+ * Note multiple calls to this method will result in an AND condition. e.g.
140
+ *
141
+ * ```ts
142
+ * K8s(kind.Deployment)
143
+ * .WithField("metadata.name", "bar")
144
+ * .WithField("metadata.namespace", "qux")
145
+ * .Delete(...)
146
+ * ```
147
+ *
148
+ * Will only delete the Deployment if it has the `metadata.name=bar` and `metadata.namespace=qux` fields.
149
+ * Not all fields are supported, see https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/#supported-fields,
150
+ * but Typescript will limit to only fields that exist on the resource.
151
+ *
152
+ * @param key - the field key
153
+ * @param value - the field value
154
+ * @returns the fluent API
155
+ */
156
+ WithField: <P extends Paths<K>>(key: P, value: string) => K8sWithFilters<T, K>;
157
+ /**
158
+ * Filter the query by the given label. If no value is specified, the label simply must exist.
159
+ * Note multiple calls to this method will result in an AND condition. e.g.
160
+ *
161
+ * ```ts
162
+ * K8s(kind.Deployment)
163
+ * .WithLabel("foo", "bar")
164
+ * .WithLabel("baz", "qux")
165
+ * .WithLabel("quux")
166
+ * .Delete(...)
167
+ * ```
168
+ *
169
+ * Will only delete the Deployment if it has the`foo=bar` and `baz=qux` labels and the `quux` label exists.
170
+ *
171
+ * @param key - the label key
172
+ * @param value - the label value
173
+ * @returns the fluent API
174
+ */
175
+ WithLabel: (key: string, value?: string) => K8sWithFilters<T, K>;
176
+ };
177
+ /**
178
+ * Configuration for the apply function.
179
+ */
180
+ export type ApplyCfg = {
181
+ /**
182
+ * Force the apply to be a create.
183
+ */
184
+ force?: boolean;
185
+ };
186
+ export type K8sInit<T extends GenericClass, K extends KubernetesObject> = K8sWithFilters<T, K> & K8sUnfilteredActions<K> & {
187
+ /**
188
+ * Set the namespace filter.
189
+ *
190
+ * @param namespace - the namespace to filter on
191
+ * @returns the fluent API
192
+ */
193
+ InNamespace: (namespace: string) => K8sWithFilters<T, K>;
194
+ };
195
+ export type WatchAction<T extends GenericClass, K extends KubernetesObject = InstanceType<T>> = (update: K, phase: WatchPhase) => Promise<void> | void;
196
+ type Join<K, P> = K extends string | number ? P extends string | number ? `${K}${"" extends P ? "" : "."}${P}` : never : never;
197
+ export type Paths<T, D extends number = 10> = [D] extends [never] ? never : T extends object ? {
198
+ [K in keyof T]-?: K extends string | number ? `${K}` | Join<K, Paths<T[K]>> : never;
199
+ }[keyof T] : "";
200
+ export {};
201
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/fluent/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-FileCopyrightText: 2023-Present The Kubernetes Fluent Client Authors
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.WatchPhase = void 0;
6
+ /**
7
+ * The Phase matched when using the K8s Watch API.
8
+ */
9
+ var WatchPhase;
10
+ (function (WatchPhase) {
11
+ WatchPhase["Added"] = "ADDED";
12
+ WatchPhase["Modified"] = "MODIFIED";
13
+ WatchPhase["Deleted"] = "DELETED";
14
+ WatchPhase["Bookmark"] = "BOOKMARK";
15
+ WatchPhase["Error"] = "ERROR";
16
+ })(WatchPhase || (exports.WatchPhase = WatchPhase = {}));
@@ -0,0 +1,41 @@
1
+ import { URL } from "url";
2
+ import { GenericClass } from "../types";
3
+ import { ApplyCfg, FetchMethods, Filters } from "./types";
4
+ /**
5
+ * Generate a path to a Kubernetes resource
6
+ *
7
+ * @param serverUrl - the URL of the Kubernetes API server
8
+ * @param model - the model to use for the API
9
+ * @param filters - (optional) filter overrides, can also be chained
10
+ * @param excludeName - (optional) exclude the name from the path
11
+ * @returns the path to the resource
12
+ */
13
+ export declare function pathBuilder<T extends GenericClass>(serverUrl: string, model: T, filters: Filters, excludeName?: boolean): URL;
14
+ /**
15
+ * Sets up the kubeconfig and https agent for a request
16
+ *
17
+ * A few notes:
18
+ * - The kubeconfig is loaded from the default location, and can check for in-cluster config
19
+ * - We have to create an agent to handle the TLS connection (for the custom CA + mTLS in some cases)
20
+ * - The K8s lib uses request instead of node-fetch today so the object is slightly different
21
+ *
22
+ * @param method - the HTTP method to use
23
+ * @returns the fetch options and server URL
24
+ */
25
+ export declare function k8sCfg(method: FetchMethods): Promise<{
26
+ opts: import("node-fetch").RequestInit;
27
+ serverUrl: string;
28
+ }>;
29
+ /**
30
+ * Execute a request against the Kubernetes API server.
31
+ *
32
+ * @param model - the model to use for the API
33
+ * @param filters - (optional) filter overrides, can also be chained
34
+ * @param method - the HTTP method to use
35
+ * @param payload - (optional) the payload to send
36
+ * @param applyCfg - (optional) configuration for the apply method
37
+ *
38
+ * @returns the parsed JSON response
39
+ */
40
+ export declare function k8sExec<T extends GenericClass, K>(model: T, filters: Filters, method: FetchMethods, payload?: K | unknown, applyCfg?: ApplyCfg): Promise<K>;
41
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +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,cAwDtC"}
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-FileCopyrightText: 2023-Present The Kubernetes Fluent Client Authors
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.pathBuilder = pathBuilder;
6
+ exports.k8sCfg = k8sCfg;
7
+ exports.k8sExec = k8sExec;
8
+ const client_node_1 = require("@kubernetes/client-node");
9
+ const url_1 = require("url");
10
+ const fetch_1 = require("../fetch");
11
+ const kinds_1 = require("../kinds");
12
+ const SSA_CONTENT_TYPE = "application/apply-patch+yaml";
13
+ /**
14
+ * Generate a path to a Kubernetes resource
15
+ *
16
+ * @param serverUrl - the URL of the Kubernetes API server
17
+ * @param model - the model to use for the API
18
+ * @param filters - (optional) filter overrides, can also be chained
19
+ * @param excludeName - (optional) exclude the name from the path
20
+ * @returns the path to the resource
21
+ */
22
+ function pathBuilder(serverUrl, model, filters, excludeName = false) {
23
+ const matchedKind = filters.kindOverride || (0, kinds_1.modelToGroupVersionKind)(model.name);
24
+ // If the kind is not specified and the model is not a KubernetesObject, throw an error
25
+ if (!matchedKind) {
26
+ throw new Error(`Kind not specified for ${model.name}`);
27
+ }
28
+ // Use the plural property if it exists, otherwise use lowercase kind + s
29
+ const plural = matchedKind.plural || `${matchedKind.kind.toLowerCase()}s`;
30
+ let base = "/api/v1";
31
+ // If the kind is not in the core group, add the group and version to the path
32
+ if (matchedKind.group) {
33
+ if (!matchedKind.version) {
34
+ throw new Error(`Version not specified for ${model.name}`);
35
+ }
36
+ base = `/apis/${matchedKind.group}/${matchedKind.version}`;
37
+ }
38
+ // Namespaced paths require a namespace prefix
39
+ const namespace = filters.namespace ? `namespaces/${filters.namespace}` : "";
40
+ // Name should not be included in some paths
41
+ const name = excludeName ? "" : filters.name;
42
+ // Build the complete path to the resource
43
+ const path = [base, namespace, plural, name].filter(Boolean).join("/");
44
+ // Generate the URL object
45
+ const url = new url_1.URL(path, serverUrl);
46
+ // Add field selectors to the query params
47
+ if (filters.fields) {
48
+ const fieldSelector = Object.entries(filters.fields)
49
+ .map(([key, value]) => `${key}=${value}`)
50
+ .join(",");
51
+ url.searchParams.set("fieldSelector", fieldSelector);
52
+ }
53
+ // Add label selectors to the query params
54
+ if (filters.labels) {
55
+ const labelSelector = Object.entries(filters.labels)
56
+ // Exists set-based operators only include the key
57
+ // See https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#set-based-requirement
58
+ .map(([key, value]) => (value ? `${key}=${value}` : key))
59
+ .join(",");
60
+ url.searchParams.set("labelSelector", labelSelector);
61
+ }
62
+ return url;
63
+ }
64
+ /**
65
+ * Sets up the kubeconfig and https agent for a request
66
+ *
67
+ * A few notes:
68
+ * - The kubeconfig is loaded from the default location, and can check for in-cluster config
69
+ * - We have to create an agent to handle the TLS connection (for the custom CA + mTLS in some cases)
70
+ * - The K8s lib uses request instead of node-fetch today so the object is slightly different
71
+ *
72
+ * @param method - the HTTP method to use
73
+ * @returns the fetch options and server URL
74
+ */
75
+ async function k8sCfg(method) {
76
+ const kubeConfig = new client_node_1.KubeConfig();
77
+ kubeConfig.loadFromDefault();
78
+ const cluster = kubeConfig.getCurrentCluster();
79
+ if (!cluster) {
80
+ throw new Error("No currently active cluster");
81
+ }
82
+ // Setup the TLS options & auth headers, as needed
83
+ const opts = await kubeConfig.applyToFetchOptions({
84
+ method,
85
+ headers: {
86
+ // Set the default content type to JSON
87
+ "Content-Type": "application/json",
88
+ // Set the user agent like kubectl does
89
+ "User-Agent": `kubernetes-fluent-client`,
90
+ },
91
+ });
92
+ // Enable compression
93
+ opts.compress = true;
94
+ return { opts, serverUrl: cluster.server };
95
+ }
96
+ /**
97
+ * Execute a request against the Kubernetes API server.
98
+ *
99
+ * @param model - the model to use for the API
100
+ * @param filters - (optional) filter overrides, can also be chained
101
+ * @param method - the HTTP method to use
102
+ * @param payload - (optional) the payload to send
103
+ * @param applyCfg - (optional) configuration for the apply method
104
+ *
105
+ * @returns the parsed JSON response
106
+ */
107
+ async function k8sExec(model, filters, method, payload, applyCfg = { force: false }) {
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);
122
+ switch (opts.method) {
123
+ // PATCH_STATUS is a special case that uses the PATCH method on status subresources
124
+ case "PATCH_STATUS":
125
+ opts.method = "PATCH";
126
+ url.pathname = `${url.pathname}/status`;
127
+ opts.headers.set("Content-Type", client_node_1.PatchStrategy.MergePatch);
128
+ payload = { status: payload.status };
129
+ break;
130
+ case "PATCH":
131
+ opts.headers.set("Content-Type", client_node_1.PatchStrategy.JsonPatch);
132
+ break;
133
+ case "APPLY":
134
+ opts.headers.set("Content-Type", SSA_CONTENT_TYPE);
135
+ opts.method = "PATCH";
136
+ url.searchParams.set("fieldManager", "pepr");
137
+ url.searchParams.set("fieldValidation", "Strict");
138
+ url.searchParams.set("force", applyCfg.force ? "true" : "false");
139
+ break;
140
+ }
141
+ if (payload) {
142
+ opts.body = JSON.stringify(payload);
143
+ }
144
+ const resp = await (0, fetch_1.fetch)(url, opts);
145
+ if (resp.ok) {
146
+ return resp.data;
147
+ }
148
+ if (resp.status === 404 && method === "PATCH_STATUS") {
149
+ resp.statusText =
150
+ "Not Found" + " (NOTE: This error is expected if the resource has no status subresource)";
151
+ }
152
+ throw resp;
153
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=utils.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.test.d.ts","sourceRoot":"","sources":["../../src/fluent/utils.test.ts"],"names":[],"mappings":""}