kubernetes-fluent-client 1.8.4 → 1.10.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.
@@ -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;AAMjF,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAsB,MAAM,SAAS,CAAC;AAI/D;;;;;;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,CAAC,CAmJZ"}
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;AAExC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAsB,MAAM,SAAS,CAAC;AAI/D;;;;;;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,CAAC,CAmKZ"}
@@ -4,6 +4,7 @@
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.K8s = void 0;
6
6
  const http_status_codes_1 = require("http-status-codes");
7
+ const fetch_1 = require("../fetch");
7
8
  const kinds_1 = require("../kinds");
8
9
  const utils_1 = require("./utils");
9
10
  const watch_1 = require("./watch");
@@ -137,6 +138,19 @@ function K8s(model, filters = {}) {
137
138
  async function Watch(callback, watchCfg) {
138
139
  return (0, watch_1.ExecWatch)(model, filters, callback, watchCfg);
139
140
  }
140
- return { InNamespace, Apply, Create, Patch, ...withFilters };
141
+ /**
142
+ * @inheritdoc
143
+ * @see {@link K8sInit.Raw}
144
+ */
145
+ async function Raw(url) {
146
+ const thing = await (0, utils_1.k8sCfg)("GET");
147
+ const { opts, serverUrl } = thing;
148
+ const resp = await (0, fetch_1.fetch)(`${serverUrl}${url}`, opts);
149
+ if (resp.ok) {
150
+ return resp.data;
151
+ }
152
+ throw resp;
153
+ }
154
+ return { InNamespace, Apply, Create, Patch, Raw, ...withFilters };
141
155
  }
142
156
  exports.K8s = K8s;
@@ -1,11 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const globals_1 = require("@jest/globals");
4
- const upstream_1 = require("../upstream");
4
+ const client_node_1 = require("@kubernetes/client-node");
5
5
  const _1 = require(".");
6
+ const fetch_1 = require("../fetch");
7
+ const upstream_1 = require("../upstream");
6
8
  const utils_1 = require("./utils");
7
9
  // Setup mocks
8
10
  globals_1.jest.mock("./utils");
11
+ globals_1.jest.mock("../fetch");
9
12
  const generateFakePodManagedFields = (manager) => {
10
13
  return [
11
14
  {
@@ -49,14 +52,14 @@ const generateFakePodManagedFields = (manager) => {
49
52
  managedFields: generateFakePodManagedFields("pepr"),
50
53
  },
51
54
  };
55
+ const mockedKubeCfg = globals_1.jest.mocked(utils_1.k8sCfg);
52
56
  const mockedKubeExec = globals_1.jest.mocked(utils_1.k8sExec).mockResolvedValue(fakeResource);
53
57
  (0, globals_1.beforeEach)(() => {
54
58
  // Clear all instances and calls to constructor and all methods:
55
59
  mockedKubeExec.mockClear();
56
60
  });
57
61
  (0, globals_1.it)("should create a resource", async () => {
58
- const kube = (0, _1.K8s)(upstream_1.Pod);
59
- const result = await kube.Create(fakeResource);
62
+ const result = await (0, _1.K8s)(upstream_1.Pod).Create(fakeResource);
60
63
  (0, globals_1.expect)(result).toEqual(fakeResource);
61
64
  (0, globals_1.expect)(mockedKubeExec).toHaveBeenCalledWith(upstream_1.Pod, globals_1.expect.objectContaining({
62
65
  name: "fake",
@@ -64,8 +67,7 @@ const generateFakePodManagedFields = (manager) => {
64
67
  }), "POST", fakeResource);
65
68
  });
66
69
  (0, globals_1.it)("should delete a resource", async () => {
67
- const kube = (0, _1.K8s)(upstream_1.Pod);
68
- await kube.Delete(fakeResource);
70
+ await (0, _1.K8s)(upstream_1.Pod).Delete(fakeResource);
69
71
  (0, globals_1.expect)(mockedKubeExec).toHaveBeenCalledWith(upstream_1.Pod, globals_1.expect.objectContaining({
70
72
  name: "fake",
71
73
  namespace: "default",
@@ -75,14 +77,12 @@ const generateFakePodManagedFields = (manager) => {
75
77
  const patchOperations = [
76
78
  { op: "replace", path: "/metadata/name", value: "new-fake" },
77
79
  ];
78
- const kube = (0, _1.K8s)(upstream_1.Pod);
79
- const result = await kube.Patch(patchOperations);
80
+ const result = await (0, _1.K8s)(upstream_1.Pod).Patch(patchOperations);
80
81
  (0, globals_1.expect)(result).toEqual(fakeResource);
81
82
  (0, globals_1.expect)(mockedKubeExec).toHaveBeenCalledWith(upstream_1.Pod, {}, "PATCH", patchOperations);
82
83
  });
83
84
  (0, globals_1.it)("should filter with WithField", async () => {
84
- const kube = (0, _1.K8s)(upstream_1.Pod).WithField("metadata.name", "fake");
85
- await kube.Get();
85
+ await (0, _1.K8s)(upstream_1.Pod).WithField("metadata.name", "fake").Get();
86
86
  (0, globals_1.expect)(mockedKubeExec).toHaveBeenCalledWith(upstream_1.Pod, globals_1.expect.objectContaining({
87
87
  fields: {
88
88
  "metadata.name": "fake",
@@ -90,8 +90,7 @@ const generateFakePodManagedFields = (manager) => {
90
90
  }), "GET");
91
91
  });
92
92
  (0, globals_1.it)("should filter with WithLabel", async () => {
93
- const kube = (0, _1.K8s)(upstream_1.Pod).WithLabel("app", "fakeApp");
94
- await kube.Get();
93
+ await (0, _1.K8s)(upstream_1.Pod).WithLabel("app", "fakeApp").Get();
95
94
  (0, globals_1.expect)(mockedKubeExec).toHaveBeenCalledWith(upstream_1.Pod, globals_1.expect.objectContaining({
96
95
  labels: {
97
96
  app: "fakeApp",
@@ -99,45 +98,37 @@ const generateFakePodManagedFields = (manager) => {
99
98
  }), "GET");
100
99
  });
101
100
  (0, globals_1.it)("should use InNamespace", async () => {
102
- const kube = (0, _1.K8s)(upstream_1.Pod).InNamespace("fakeNamespace");
103
- await kube.Get();
101
+ await (0, _1.K8s)(upstream_1.Pod).InNamespace("fakeNamespace").Get();
104
102
  (0, globals_1.expect)(mockedKubeExec).toHaveBeenCalledWith(upstream_1.Pod, globals_1.expect.objectContaining({
105
103
  namespace: "fakeNamespace",
106
104
  }), "GET");
107
105
  });
108
106
  (0, globals_1.it)("should throw an error if namespace is already specified", async () => {
109
- const kube = (0, _1.K8s)(upstream_1.Pod, { namespace: "default" });
110
- (0, globals_1.expect)(() => kube.InNamespace("fakeNamespace")).toThrow("Namespace already specified: default");
107
+ (0, globals_1.expect)(() => (0, _1.K8s)(upstream_1.Pod, { namespace: "default" }).InNamespace("fakeNamespace")).toThrow("Namespace already specified: default");
111
108
  });
112
109
  (0, globals_1.it)("should handle Delete when the resource doesn't exist", async () => {
113
110
  mockedKubeExec.mockRejectedValueOnce({ status: 404 }); // Not Found on first call
114
- const kube = (0, _1.K8s)(upstream_1.Pod);
115
- await (0, globals_1.expect)(kube.Delete("fakeResource")).resolves.toBeUndefined();
111
+ await (0, globals_1.expect)((0, _1.K8s)(upstream_1.Pod).Delete("fakeResource")).resolves.toBeUndefined();
116
112
  });
117
113
  (0, globals_1.it)("should handle Get", async () => {
118
- const kube = (0, _1.K8s)(upstream_1.Pod);
119
- const result = await kube.Get("fakeResource");
114
+ const result = await (0, _1.K8s)(upstream_1.Pod).Get("fakeResource");
120
115
  (0, globals_1.expect)(result).toEqual(fakeResource);
121
116
  (0, globals_1.expect)(mockedKubeExec).toHaveBeenCalledWith(upstream_1.Pod, globals_1.expect.objectContaining({
122
117
  name: "fakeResource",
123
118
  }), "GET");
124
119
  });
125
120
  (0, globals_1.it)("should thrown an error if Get is called with a name and filters are already specified a name", async () => {
126
- const kube = (0, _1.K8s)(upstream_1.Pod, { name: "fake" });
127
- await (0, globals_1.expect)(kube.Get("fakeResource")).rejects.toThrow("Name already specified: fake");
121
+ await (0, globals_1.expect)((0, _1.K8s)(upstream_1.Pod, { name: "fake" }).Get("fakeResource")).rejects.toThrow("Name already specified: fake");
128
122
  });
129
123
  (0, globals_1.it)("should throw an error if no patch operations provided", async () => {
130
- const kube = (0, _1.K8s)(upstream_1.Pod);
131
- await (0, globals_1.expect)(kube.Patch([])).rejects.toThrow("No operations specified");
124
+ await (0, globals_1.expect)((0, _1.K8s)(upstream_1.Pod).Patch([])).rejects.toThrow("No operations specified");
132
125
  });
133
126
  (0, globals_1.it)("should allow Apply of deep partials", async () => {
134
- const kube = (0, _1.K8s)(upstream_1.Pod);
135
- const result = await kube.Apply({ metadata: { name: "fake" }, spec: { priority: 3 } });
127
+ const result = await (0, _1.K8s)(upstream_1.Pod).Apply({ metadata: { name: "fake" }, spec: { priority: 3 } });
136
128
  (0, globals_1.expect)(result).toEqual(fakeResource);
137
129
  });
138
130
  (0, globals_1.it)("should allow force apply to resolve FieldManagerConflict", async () => {
139
- const kube = (0, _1.K8s)(upstream_1.Pod);
140
- const result = await kube.Apply({
131
+ const result = await (0, _1.K8s)(upstream_1.Pod).Apply({
141
132
  metadata: { name: "fake", managedFields: generateFakePodManagedFields("kubectl") },
142
133
  spec: { priority: 3 },
143
134
  }, { force: true });
@@ -145,7 +136,29 @@ const generateFakePodManagedFields = (manager) => {
145
136
  });
146
137
  (0, globals_1.it)("should throw an error if a Delete failed for a reason other than Not Found", async () => {
147
138
  mockedKubeExec.mockRejectedValueOnce({ status: 500 }); // Internal Server Error on first call
148
- const kube = (0, _1.K8s)(upstream_1.Pod);
149
- await (0, globals_1.expect)(kube.Delete("fakeResource")).rejects.toEqual(globals_1.expect.objectContaining({ status: 500 }));
139
+ await (0, globals_1.expect)((0, _1.K8s)(upstream_1.Pod).Delete("fakeResource")).rejects.toEqual(globals_1.expect.objectContaining({ status: 500 }));
140
+ });
141
+ (0, globals_1.it)("should create a raw api request", async () => {
142
+ mockedKubeCfg.mockReturnValue(new Promise(r => r({
143
+ serverUrl: "http://localhost:8080",
144
+ opts: {},
145
+ })));
146
+ const mockResp = {
147
+ kind: "APIVersions",
148
+ versions: ["v1"],
149
+ serverAddressByClientCIDRs: [
150
+ {
151
+ serverAddress: "172.27.0.3:6443",
152
+ },
153
+ ],
154
+ };
155
+ globals_1.jest.mocked(fetch_1.fetch).mockResolvedValue({
156
+ ok: true,
157
+ data: mockResp,
158
+ status: 200,
159
+ statusText: "OK",
160
+ });
161
+ const result = await (0, _1.K8s)(client_node_1.V1APIGroup).Raw("/api");
162
+ (0, globals_1.expect)(result).toEqual(mockResp);
150
163
  });
151
164
  });
@@ -79,6 +79,24 @@ export type K8sUnfilteredActions<K extends KubernetesObject> = {
79
79
  * @returns The patched resource
80
80
  */
81
81
  Patch: (payload: Operation[]) => Promise<K>;
82
+ /**
83
+ * Perform a raw GET request to the Kubernetes API. This is useful for calling endpoints that are not supported by the fluent API.
84
+ * This command mirrors the `kubectl get --raw` command.
85
+ *
86
+ * E.g.
87
+ *
88
+ * ```ts
89
+ * import { V1APIGroup } from "@kubernetes/client-node";
90
+ *
91
+ * K8s(V1APIGroup).Raw("/api")
92
+ * ```
93
+ *
94
+ * will call the `/api` endpoint and is equivalent to `kubectl get --raw /api`.
95
+ *
96
+ * @param url the URL to call (e.g. /api)
97
+ * @returns
98
+ */
99
+ Raw: (url: string) => Promise<K>;
82
100
  };
83
101
  export type K8sWithFilters<K extends KubernetesObject> = K8sFilteredActions<K> & {
84
102
  /**
@@ -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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"}
package/dist/helpers.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { Cluster } from "@kubernetes/client-node";
1
2
  /**
2
3
  * Get an environment variable (Node, Deno or Bun), or throw an error if it's not set.
3
4
  *
@@ -15,4 +16,11 @@
15
16
  * @throws An error if the environment variable is not set.
16
17
  */
17
18
  export declare function fromEnv(name: string): string;
19
+ /**
20
+ * Wait for the Kubernetes cluster to be ready.
21
+ *
22
+ * @param seconds The number of seconds to wait for the cluster to be ready.
23
+ * @returns The current cluster.
24
+ */
25
+ export declare function waitForCluster(seconds?: number): Promise<Cluster>;
18
26
  //# sourceMappingURL=helpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AASA;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAqB5C"}
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"}
package/dist/helpers.js CHANGED
@@ -2,7 +2,17 @@
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.fromEnv = void 0;
5
+ exports.waitForCluster = exports.fromEnv = void 0;
6
+ const client_node_1 = require("@kubernetes/client-node");
7
+ /**
8
+ * Sleep for a number of seconds.
9
+ *
10
+ * @param seconds The number of seconds to sleep.
11
+ * @returns A promise that resolves after the specified number of seconds.
12
+ */
13
+ function sleep(seconds) {
14
+ return new Promise(resolve => setTimeout(resolve, seconds * 1000));
15
+ }
6
16
  /**
7
17
  * Get an environment variable (Node, Deno or Bun), or throw an error if it's not set.
8
18
  *
@@ -39,3 +49,25 @@ function fromEnv(name) {
39
49
  return envValue;
40
50
  }
41
51
  exports.fromEnv = fromEnv;
52
+ /**
53
+ * Wait for the Kubernetes cluster to be ready.
54
+ *
55
+ * @param seconds The number of seconds to wait for the cluster to be ready.
56
+ * @returns The current cluster.
57
+ */
58
+ async function waitForCluster(seconds = 30) {
59
+ const kubeConfig = new client_node_1.KubeConfig();
60
+ kubeConfig.loadFromDefault();
61
+ const cluster = kubeConfig.getCurrentCluster();
62
+ if (!cluster) {
63
+ await sleep(1);
64
+ if (seconds > 0) {
65
+ return await waitForCluster(seconds - 1);
66
+ }
67
+ else {
68
+ throw new Error("Cluster not ready");
69
+ }
70
+ }
71
+ return cluster;
72
+ }
73
+ exports.waitForCluster = waitForCluster;
@@ -14,3 +14,9 @@ const helpers_1 = require("./helpers");
14
14
  delete process.env.MY_ENV_VAR;
15
15
  });
16
16
  });
17
+ (0, globals_1.describe)("Cluster Wait Function", () => {
18
+ (0, globals_1.it)("should resolve if the cluster is already ready", async () => {
19
+ const cluster = await (0, helpers_1.waitForCluster)(5);
20
+ (0, globals_1.expect)(cluster).toEqual({ server: "http://jest-test:8080" });
21
+ });
22
+ });
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import "./patch";
1
2
  import * as kind from "./upstream";
2
3
  /** kind is a collection of K8s types to be used within a K8s call: `K8s(kind.Secret).Apply({})`. */
3
4
  export { kind };
@@ -7,6 +8,6 @@ export { K8s } from "./fluent";
7
8
  export { RegisterKind, modelToGroupVersionKind } from "./kinds";
8
9
  export { GenericKind } from "./types";
9
10
  export * from "./types";
10
- export * as K8sClientNode from "@kubernetes/client-node";
11
- export { fromEnv } from "./helpers";
11
+ export * as models from "@kubernetes/client-node/dist/gen/models/all";
12
+ export { fromEnv, waitForCluster } from "./helpers";
12
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,IAAI,MAAM,YAAY,CAAC;AAEnC,oGAAoG;AACpG,OAAO,EAAE,IAAI,EAAE,CAAC;AAGhB,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAGhC,OAAO,EAAE,WAAW,IAAI,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAG/D,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAG/B,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAGhE,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEtC,cAAc,SAAS,CAAC;AAExB,OAAO,KAAK,aAAa,MAAM,yBAAyB,CAAC;AAEzD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,SAAS,CAAC;AAGjB,OAAO,KAAK,IAAI,MAAM,YAAY,CAAC;AAEnC,oGAAoG;AACpG,OAAO,EAAE,IAAI,EAAE,CAAC;AAGhB,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAGhC,OAAO,EAAE,WAAW,IAAI,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAG/D,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAG/B,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAGhE,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEtC,cAAc,SAAS,CAAC;AAGxB,OAAO,KAAK,MAAM,MAAM,6CAA6C,CAAC;AAEtE,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
package/dist/index.js CHANGED
@@ -28,7 +28,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
28
28
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
29
29
  };
30
30
  Object.defineProperty(exports, "__esModule", { value: true });
31
- exports.fromEnv = exports.K8sClientNode = exports.GenericKind = exports.modelToGroupVersionKind = exports.RegisterKind = exports.K8s = exports.fetchStatus = exports.fetch = exports.kind = void 0;
31
+ exports.waitForCluster = exports.fromEnv = exports.models = exports.GenericKind = exports.modelToGroupVersionKind = exports.RegisterKind = exports.K8s = exports.fetchStatus = exports.fetch = exports.kind = void 0;
32
+ require("./patch");
32
33
  // Export kinds as a single object
33
34
  const kind = __importStar(require("./upstream"));
34
35
  exports.kind = kind;
@@ -49,6 +50,8 @@ Object.defineProperty(exports, "modelToGroupVersionKind", { enumerable: true, ge
49
50
  var types_1 = require("./types");
50
51
  Object.defineProperty(exports, "GenericKind", { enumerable: true, get: function () { return types_1.GenericKind; } });
51
52
  __exportStar(require("./types"), exports);
52
- exports.K8sClientNode = __importStar(require("@kubernetes/client-node"));
53
+ // Export the upstream raw models
54
+ exports.models = __importStar(require("@kubernetes/client-node/dist/gen/models/all"));
53
55
  var helpers_1 = require("./helpers");
54
56
  Object.defineProperty(exports, "fromEnv", { enumerable: true, get: function () { return helpers_1.fromEnv; } });
57
+ Object.defineProperty(exports, "waitForCluster", { enumerable: true, get: function () { return helpers_1.waitForCluster; } });
@@ -0,0 +1,7 @@
1
+ import { V1NetworkPolicyPeer } from "@kubernetes/client-node";
2
+ declare module "@kubernetes/client-node" {
3
+ interface V1NetworkPolicyIngressRule {
4
+ from?: Array<V1NetworkPolicyPeer>;
5
+ }
6
+ }
7
+ //# sourceMappingURL=patch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patch.d.ts","sourceRoot":"","sources":["../src/patch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAE9D,OAAO,QAAQ,yBAAyB,CAAC;IACvC,UAAU,0BAA0B;QAClC,IAAI,CAAC,EAAE,KAAK,CAAC,mBAAmB,CAAC,CAAC;KAEnC;CACF"}
package/dist/patch.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kubernetes-fluent-client",
3
- "version": "1.8.4",
3
+ "version": "1.10.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,29 +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": "github:defenseunicorns/temp-quicktype-fork#main",
44
- "type-fest": "4.8.2",
43
+ "quicktype-core": "23.0.80",
44
+ "type-fest": "4.8.3",
45
45
  "yargs": "17.7.2"
46
46
  },
47
47
  "devDependencies": {
48
- "@commitlint/cli": "18.4.0",
49
- "@commitlint/config-conventional": "18.4.0",
48
+ "@commitlint/cli": "18.4.3",
49
+ "@commitlint/config-conventional": "18.4.3",
50
50
  "@jest/globals": "29.7.0",
51
51
  "@types/byline": "4.2.36",
52
- "@types/readable-stream": "4.0.5",
53
- "@types/yargs": "17.0.31",
54
- "@typescript-eslint/eslint-plugin": "6.10.0",
55
- "@typescript-eslint/parser": "6.10.0",
56
- "eslint-plugin-jsdoc": "46.9.0",
52
+ "@types/readable-stream": "4.0.10",
53
+ "@types/yargs": "17.0.32",
54
+ "@typescript-eslint/eslint-plugin": "6.15.0",
55
+ "@typescript-eslint/parser": "6.15.0",
56
+ "eslint-plugin-jsdoc": "46.9.1",
57
57
  "jest": "29.7.0",
58
- "nock": "13.3.8",
59
- "prettier": "3.0.3",
60
- "semantic-release": "22.0.7",
58
+ "nock": "13.4.0",
59
+ "prettier": "3.1.1",
60
+ "semantic-release": "22.0.12",
61
61
  "ts-jest": "29.1.1",
62
- "typescript": "5.2.2"
63
- },
64
- "overrides": {
65
- "browser-or-node": "github:defenseunicorns/browser-or-node#master"
62
+ "typescript": "5.3.3"
66
63
  },
67
64
  "release": {
68
65
  "branches": [
@@ -1,12 +1,15 @@
1
1
  import { beforeEach, describe, expect, it, jest } from "@jest/globals";
2
+ import { V1APIGroup } from "@kubernetes/client-node";
2
3
  import { Operation } from "fast-json-patch";
3
4
 
4
- import { Pod } from "../upstream";
5
5
  import { K8s } from ".";
6
- import { k8sExec } from "./utils";
6
+ import { fetch } from "../fetch";
7
+ import { Pod } from "../upstream";
8
+ import { k8sCfg, k8sExec } from "./utils";
7
9
 
8
10
  // Setup mocks
9
11
  jest.mock("./utils");
12
+ jest.mock("../fetch");
10
13
 
11
14
  const generateFakePodManagedFields = (manager: string) => {
12
15
  return [
@@ -52,6 +55,7 @@ describe("Kube", () => {
52
55
  },
53
56
  };
54
57
 
58
+ const mockedKubeCfg = jest.mocked(k8sCfg);
55
59
  const mockedKubeExec = jest.mocked(k8sExec).mockResolvedValue(fakeResource);
56
60
 
57
61
  beforeEach(() => {
@@ -60,8 +64,7 @@ describe("Kube", () => {
60
64
  });
61
65
 
62
66
  it("should create a resource", async () => {
63
- const kube = K8s(Pod);
64
- const result = await kube.Create(fakeResource);
67
+ const result = await K8s(Pod).Create(fakeResource);
65
68
 
66
69
  expect(result).toEqual(fakeResource);
67
70
  expect(mockedKubeExec).toHaveBeenCalledWith(
@@ -76,8 +79,7 @@ describe("Kube", () => {
76
79
  });
77
80
 
78
81
  it("should delete a resource", async () => {
79
- const kube = K8s(Pod);
80
- await kube.Delete(fakeResource);
82
+ await K8s(Pod).Delete(fakeResource);
81
83
 
82
84
  expect(mockedKubeExec).toHaveBeenCalledWith(
83
85
  Pod,
@@ -94,16 +96,15 @@ describe("Kube", () => {
94
96
  { op: "replace", path: "/metadata/name", value: "new-fake" },
95
97
  ];
96
98
 
97
- const kube = K8s(Pod);
98
- const result = await kube.Patch(patchOperations);
99
+ const result = await K8s(Pod).Patch(patchOperations);
99
100
 
100
101
  expect(result).toEqual(fakeResource);
101
102
  expect(mockedKubeExec).toHaveBeenCalledWith(Pod, {}, "PATCH", patchOperations);
102
103
  });
103
104
 
104
105
  it("should filter with WithField", async () => {
105
- const kube = K8s(Pod).WithField("metadata.name", "fake");
106
- await kube.Get();
106
+ await K8s(Pod).WithField("metadata.name", "fake").Get();
107
+
107
108
  expect(mockedKubeExec).toHaveBeenCalledWith(
108
109
  Pod,
109
110
  expect.objectContaining({
@@ -116,8 +117,8 @@ describe("Kube", () => {
116
117
  });
117
118
 
118
119
  it("should filter with WithLabel", async () => {
119
- const kube = K8s(Pod).WithLabel("app", "fakeApp");
120
- await kube.Get();
120
+ await K8s(Pod).WithLabel("app", "fakeApp").Get();
121
+
121
122
  expect(mockedKubeExec).toHaveBeenCalledWith(
122
123
  Pod,
123
124
  expect.objectContaining({
@@ -130,8 +131,8 @@ describe("Kube", () => {
130
131
  });
131
132
 
132
133
  it("should use InNamespace", async () => {
133
- const kube = K8s(Pod).InNamespace("fakeNamespace");
134
- await kube.Get();
134
+ await K8s(Pod).InNamespace("fakeNamespace").Get();
135
+
135
136
  expect(mockedKubeExec).toHaveBeenCalledWith(
136
137
  Pod,
137
138
  expect.objectContaining({
@@ -142,19 +143,18 @@ describe("Kube", () => {
142
143
  });
143
144
 
144
145
  it("should throw an error if namespace is already specified", async () => {
145
- const kube = K8s(Pod, { namespace: "default" });
146
- expect(() => kube.InNamespace("fakeNamespace")).toThrow("Namespace already specified: default");
146
+ expect(() => K8s(Pod, { namespace: "default" }).InNamespace("fakeNamespace")).toThrow(
147
+ "Namespace already specified: default",
148
+ );
147
149
  });
148
150
 
149
151
  it("should handle Delete when the resource doesn't exist", async () => {
150
152
  mockedKubeExec.mockRejectedValueOnce({ status: 404 }); // Not Found on first call
151
- const kube = K8s(Pod);
152
- await expect(kube.Delete("fakeResource")).resolves.toBeUndefined();
153
+ await expect(K8s(Pod).Delete("fakeResource")).resolves.toBeUndefined();
153
154
  });
154
155
 
155
156
  it("should handle Get", async () => {
156
- const kube = K8s(Pod);
157
- const result = await kube.Get("fakeResource");
157
+ const result = await K8s(Pod).Get("fakeResource");
158
158
 
159
159
  expect(result).toEqual(fakeResource);
160
160
  expect(mockedKubeExec).toHaveBeenCalledWith(
@@ -167,24 +167,22 @@ describe("Kube", () => {
167
167
  });
168
168
 
169
169
  it("should thrown an error if Get is called with a name and filters are already specified a name", async () => {
170
- const kube = K8s(Pod, { name: "fake" });
171
- await expect(kube.Get("fakeResource")).rejects.toThrow("Name already specified: fake");
170
+ await expect(K8s(Pod, { name: "fake" }).Get("fakeResource")).rejects.toThrow(
171
+ "Name already specified: fake",
172
+ );
172
173
  });
173
174
 
174
175
  it("should throw an error if no patch operations provided", async () => {
175
- const kube = K8s(Pod);
176
- await expect(kube.Patch([])).rejects.toThrow("No operations specified");
176
+ await expect(K8s(Pod).Patch([])).rejects.toThrow("No operations specified");
177
177
  });
178
178
 
179
179
  it("should allow Apply of deep partials", async () => {
180
- const kube = K8s(Pod);
181
- const result = await kube.Apply({ metadata: { name: "fake" }, spec: { priority: 3 } });
180
+ const result = await K8s(Pod).Apply({ metadata: { name: "fake" }, spec: { priority: 3 } });
182
181
  expect(result).toEqual(fakeResource);
183
182
  });
184
183
 
185
184
  it("should allow force apply to resolve FieldManagerConflict", async () => {
186
- const kube = K8s(Pod);
187
- const result = await kube.Apply(
185
+ const result = await K8s(Pod).Apply(
188
186
  {
189
187
  metadata: { name: "fake", managedFields: generateFakePodManagedFields("kubectl") },
190
188
  spec: { priority: 3 },
@@ -196,9 +194,39 @@ describe("Kube", () => {
196
194
 
197
195
  it("should throw an error if a Delete failed for a reason other than Not Found", async () => {
198
196
  mockedKubeExec.mockRejectedValueOnce({ status: 500 }); // Internal Server Error on first call
199
- const kube = K8s(Pod);
200
- await expect(kube.Delete("fakeResource")).rejects.toEqual(
197
+ await expect(K8s(Pod).Delete("fakeResource")).rejects.toEqual(
201
198
  expect.objectContaining({ status: 500 }),
202
199
  );
203
200
  });
201
+
202
+ it("should create a raw api request", async () => {
203
+ mockedKubeCfg.mockReturnValue(
204
+ new Promise(r =>
205
+ r({
206
+ serverUrl: "http://localhost:8080",
207
+ opts: {},
208
+ }),
209
+ ),
210
+ );
211
+ const mockResp = {
212
+ kind: "APIVersions",
213
+ versions: ["v1"],
214
+ serverAddressByClientCIDRs: [
215
+ {
216
+ serverAddress: "172.27.0.3:6443",
217
+ },
218
+ ],
219
+ };
220
+
221
+ jest.mocked(fetch).mockResolvedValue({
222
+ ok: true,
223
+ data: mockResp,
224
+ status: 200,
225
+ statusText: "OK",
226
+ });
227
+
228
+ const result = await K8s(V1APIGroup).Raw("/api");
229
+
230
+ expect(result).toEqual(mockResp);
231
+ });
204
232
  });
@@ -6,11 +6,12 @@ import { Operation } from "fast-json-patch";
6
6
  import { StatusCodes } from "http-status-codes";
7
7
  import type { PartialDeep } from "type-fest";
8
8
 
9
+ import { fetch } from "../fetch";
9
10
  import { modelToGroupVersionKind } from "../kinds";
10
11
  import { GenericClass } from "../types";
11
12
  import { ApplyCfg } from "./apply";
12
13
  import { Filters, K8sInit, Paths, WatchAction } from "./types";
13
- import { k8sExec } from "./utils";
14
+ import { k8sCfg, k8sExec } from "./utils";
14
15
  import { ExecWatch, WatchCfg } from "./watch";
15
16
 
16
17
  /**
@@ -158,7 +159,7 @@ export function K8s<T extends GenericClass, K extends KubernetesObject = Instanc
158
159
  throw new Error("No operations specified");
159
160
  }
160
161
 
161
- return k8sExec<T, K>(model, filters, "PATCH", payload);
162
+ return k8sExec(model, filters, "PATCH", payload);
162
163
  }
163
164
 
164
165
  /**
@@ -169,5 +170,21 @@ export function K8s<T extends GenericClass, K extends KubernetesObject = Instanc
169
170
  return ExecWatch(model, filters, callback, watchCfg);
170
171
  }
171
172
 
172
- return { InNamespace, Apply, Create, Patch, ...withFilters };
173
+ /**
174
+ * @inheritdoc
175
+ * @see {@link K8sInit.Raw}
176
+ */
177
+ async function Raw(url: string) {
178
+ const thing = await k8sCfg("GET");
179
+ const { opts, serverUrl } = thing;
180
+ const resp = await fetch<K>(`${serverUrl}${url}`, opts);
181
+
182
+ if (resp.ok) {
183
+ return resp.data;
184
+ }
185
+
186
+ throw resp;
187
+ }
188
+
189
+ return { InNamespace, Apply, Create, Patch, Raw, ...withFilters };
173
190
  }
@@ -96,6 +96,25 @@ export type K8sUnfilteredActions<K extends KubernetesObject> = {
96
96
  * @returns The patched resource
97
97
  */
98
98
  Patch: (payload: Operation[]) => Promise<K>;
99
+
100
+ /**
101
+ * Perform a raw GET request to the Kubernetes API. This is useful for calling endpoints that are not supported by the fluent API.
102
+ * This command mirrors the `kubectl get --raw` command.
103
+ *
104
+ * E.g.
105
+ *
106
+ * ```ts
107
+ * import { V1APIGroup } from "@kubernetes/client-node";
108
+ *
109
+ * K8s(V1APIGroup).Raw("/api")
110
+ * ```
111
+ *
112
+ * will call the `/api` endpoint and is equivalent to `kubectl get --raw /api`.
113
+ *
114
+ * @param url the URL to call (e.g. /api)
115
+ * @returns
116
+ */
117
+ Raw: (url: string) => Promise<K>;
99
118
  };
100
119
 
101
120
  export type K8sWithFilters<K extends KubernetesObject> = K8sFilteredActions<K> & {
@@ -167,5 +186,7 @@ type Join<K, P> = K extends string | number
167
186
  export type Paths<T, D extends number = 10> = [D] extends [never]
168
187
  ? never
169
188
  : T extends object
170
- ? { [K in keyof T]-?: K extends string | number ? `${K}` | Join<K, Paths<T[K]>> : never }[keyof T]
171
- : "";
189
+ ? {
190
+ [K in keyof T]-?: K extends string | number ? `${K}` | Join<K, Paths<T[K]>> : never;
191
+ }[keyof T]
192
+ : "";
@@ -1,9 +1,9 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  // SPDX-FileCopyrightText: 2023-Present The Kubernetes Fluent Client Authors
3
3
 
4
- import { describe, expect, test } from "@jest/globals";
4
+ import { describe, expect, it, test } from "@jest/globals";
5
5
 
6
- import { fromEnv } from "./helpers";
6
+ import { fromEnv, waitForCluster } from "./helpers";
7
7
 
8
8
  describe("helpers", () => {
9
9
  test("fromEnv for NodeJS", () => {
@@ -16,3 +16,10 @@ describe("helpers", () => {
16
16
  delete process.env.MY_ENV_VAR;
17
17
  });
18
18
  });
19
+
20
+ describe("Cluster Wait Function", () => {
21
+ it("should resolve if the cluster is already ready", async () => {
22
+ const cluster = await waitForCluster(5);
23
+ expect(cluster).toEqual({ server: "http://jest-test:8080" });
24
+ });
25
+ });
package/src/helpers.ts CHANGED
@@ -1,12 +1,24 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  // SPDX-FileCopyrightText: 2023-Present The Kubernetes Fluent Client Authors
3
3
 
4
+ import { Cluster, KubeConfig } from "@kubernetes/client-node";
5
+
4
6
  declare const Deno: {
5
7
  env: {
6
8
  get(name: string): string | undefined;
7
9
  };
8
10
  };
9
11
 
12
+ /**
13
+ * Sleep for a number of seconds.
14
+ *
15
+ * @param seconds The number of seconds to sleep.
16
+ * @returns A promise that resolves after the specified number of seconds.
17
+ */
18
+ function sleep(seconds: number): Promise<void> {
19
+ return new Promise(resolve => setTimeout(resolve, seconds * 1000));
20
+ }
21
+
10
22
  /**
11
23
  * Get an environment variable (Node, Deno or Bun), or throw an error if it's not set.
12
24
  *
@@ -45,3 +57,26 @@ export function fromEnv(name: string): string {
45
57
 
46
58
  return envValue;
47
59
  }
60
+
61
+ /**
62
+ * Wait for the Kubernetes cluster to be ready.
63
+ *
64
+ * @param seconds The number of seconds to wait for the cluster to be ready.
65
+ * @returns The current cluster.
66
+ */
67
+ export async function waitForCluster(seconds = 30): Promise<Cluster> {
68
+ const kubeConfig = new KubeConfig();
69
+ kubeConfig.loadFromDefault();
70
+
71
+ const cluster = kubeConfig.getCurrentCluster();
72
+ if (!cluster) {
73
+ await sleep(1);
74
+ if (seconds > 0) {
75
+ return await waitForCluster(seconds - 1);
76
+ } else {
77
+ throw new Error("Cluster not ready");
78
+ }
79
+ }
80
+
81
+ return cluster;
82
+ }
package/src/index.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  // SPDX-FileCopyrightText: 2023-Present The Kubernetes Fluent Client Authors
3
3
 
4
+ import "./patch";
5
+
4
6
  // Export kinds as a single object
5
7
  import * as kind from "./upstream";
6
8
 
@@ -24,6 +26,7 @@ export { GenericKind } from "./types";
24
26
 
25
27
  export * from "./types";
26
28
 
27
- export * as K8sClientNode from "@kubernetes/client-node";
29
+ // Export the upstream raw models
30
+ export * as models from "@kubernetes/client-node/dist/gen/models/all";
28
31
 
29
- export { fromEnv } from "./helpers";
32
+ export { fromEnv, waitForCluster } from "./helpers";
package/src/patch.ts ADDED
@@ -0,0 +1,8 @@
1
+ import { V1NetworkPolicyPeer } from "@kubernetes/client-node";
2
+
3
+ declare module "@kubernetes/client-node" {
4
+ interface V1NetworkPolicyIngressRule {
5
+ from?: Array<V1NetworkPolicyPeer>;
6
+ // No need to redeclare other unchanged properties
7
+ }
8
+ }