mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
chore: Extract @k8slens/kube-object package
Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
1 parent
576373b16b
commit
1bf24db797
466 files changed
+6838
-6375
No files matched your search
+1
-1
@@ -3,7 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import replicationControllersRouteInjectable from "./replicationcontrollers-route.injectable";
|
||||
import replicationControllersRouteInjectable from "./route.injectable";
|
||||
import { navigateToRouteInjectionToken } from "../../../../navigate-to-route-injection-token";
|
||||
|
||||
const navigateToReplicationControllersInjectable = getInjectable({
|
||||
+2
-2
@@ -7,10 +7,10 @@ import { shouldShowResourceInjectionToken } from "../../../../../../features/clu
|
||||
import { frontEndRouteInjectionToken } from "../../../../front-end-route-injection-token";
|
||||
|
||||
const replicationControllersRouteInjectable = getInjectable({
|
||||
id: "replicationcontrollers-route",
|
||||
id: "replication-controllers-route",
|
||||
|
||||
instantiate: (di) => ({
|
||||
path: "/replicationcontrollers",
|
||||
path: "/replication-controllers",
|
||||
clusterFrame: true,
|
||||
isEnabled: di.inject(shouldShowResourceInjectionToken, {
|
||||
apiName: "replicationcontrollers",
|
||||
@@ -15,7 +15,7 @@ import loggerInjectable from "../../logger.injectable";
|
||||
import type { ApiManager } from "../api-manager";
|
||||
import apiManagerInjectable from "../api-manager/manager.injectable";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { KubeObject } from "@k8slens/kube-object";
|
||||
import { KubeObjectStore } from "../kube-object.store";
|
||||
import maybeKubeApiInjectable from "../maybe-kube-api.injectable";
|
||||
|
||||
@@ -27,8 +27,8 @@ import { customResourceDefinitionApiInjectionToken } from "../api-manager/crd-ap
|
||||
import assert from "assert";
|
||||
|
||||
class TestApi extends KubeApi<KubeObject> {
|
||||
protected async checkPreferredVersion() {
|
||||
return;
|
||||
protected checkPreferredVersion() {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { CustomResourceDefinitionSpec } from "../endpoints";
|
||||
import { CustomResourceDefinition } from "../endpoints";
|
||||
import type { CustomResourceDefinitionSpec } from "@k8slens/kube-object";
|
||||
import { CustomResourceDefinition } from "@k8slens/kube-object";
|
||||
|
||||
describe("Crds", () => {
|
||||
describe("getVersion()", () => {
|
||||
|
||||
@@ -33,7 +33,7 @@ describe("DeploymentApi", () => {
|
||||
|
||||
describe("scale", () => {
|
||||
it("requests Kubernetes API with PATCH verb and correct amount of replicas", () => {
|
||||
deploymentApi.scale({ namespace: "default", name: "deployment-1" }, 5);
|
||||
void deploymentApi.scale({ namespace: "default", name: "deployment-1" }, 5);
|
||||
|
||||
expect(kubeJsonApi.patch).toHaveBeenCalledWith("/apis/apps/v1/namespaces/default/deployments/deployment-1/scale", {
|
||||
data: {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { formatEndpointSubset } from "../endpoints";
|
||||
import { formatEndpointSubset } from "@k8slens/kube-object";
|
||||
|
||||
describe("endpoint tests", () => {
|
||||
describe("EndpointSubset", () => {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { computeRuleDeclarations, Ingress } from "../endpoints";
|
||||
import { computeRuleDeclarations, Ingress } from "@k8slens/kube-object";
|
||||
|
||||
describe("Ingress", () => {
|
||||
it("given no loadbalancer ingresses in status property, loadbalancers should be an empty array", () => {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
jest.mock("../kube-object");
|
||||
jest.mock("../kube-api");
|
||||
jest.mock("../api-manager", () => ({
|
||||
apiManager() {
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
*/
|
||||
import type { ApiManager } from "../api-manager";
|
||||
import type { IngressApi } from "../endpoints";
|
||||
import { Ingress, HorizontalPodAutoscalerApi } from "../endpoints";
|
||||
import { HorizontalPodAutoscalerApi } from "../endpoints";
|
||||
import { Ingress } from "@k8slens/kube-object";
|
||||
import { getDiForUnitTesting } from "../../../renderer/getDiForUnitTesting";
|
||||
import type { Fetch } from "../../fetch/fetch.injectable";
|
||||
import fetchInjectable from "../../fetch/fetch.injectable";
|
||||
|
||||
@@ -4,38 +4,27 @@
|
||||
*/
|
||||
import type { KubeApiWatchCallback } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import { PassThrough } from "stream";
|
||||
import type { DeploymentApi, NamespaceApi } from "../endpoints";
|
||||
import { Deployment, Pod, PodApi } from "../endpoints";
|
||||
import { PodApi } from "../endpoints";
|
||||
import type { DeploymentApi, NamespaceApi } from "../endpoints";
|
||||
import { Deployment, Pod } from "@k8slens/kube-object";
|
||||
import { getDiForUnitTesting } from "../../../renderer/getDiForUnitTesting";
|
||||
import type { Fetch } from "../../fetch/fetch.injectable";
|
||||
import fetchInjectable from "../../fetch/fetch.injectable";
|
||||
import type {
|
||||
CreateKubeApiForRemoteCluster,
|
||||
} from "../create-kube-api-for-remote-cluster.injectable";
|
||||
import createKubeApiForRemoteClusterInjectable
|
||||
from "../create-kube-api-for-remote-cluster.injectable";
|
||||
import type { CreateKubeApiForRemoteCluster } from "../create-kube-api-for-remote-cluster.injectable";
|
||||
import createKubeApiForRemoteClusterInjectable from "../create-kube-api-for-remote-cluster.injectable";
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import { flushPromises } from "@k8slens/test-utils";
|
||||
import createKubeJsonApiInjectable from "../create-kube-json-api.injectable";
|
||||
import type { IKubeWatchEvent } from "../kube-watch-event";
|
||||
import type { KubeJsonApiDataFor, KubeStatusData } from "../kube-object";
|
||||
import setupAutoRegistrationInjectable
|
||||
from "../../../renderer/before-frame-starts/runnables/setup-auto-registration.injectable";
|
||||
import {
|
||||
createMockResponseFromStream,
|
||||
createMockResponseFromString,
|
||||
} from "../../../test-utils/mock-responses";
|
||||
import storesAndApisCanBeCreatedInjectable
|
||||
from "../../../renderer/stores-apis-can-be-created.injectable";
|
||||
import directoryForUserDataInjectable
|
||||
from "../../app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
import hostedClusterInjectable
|
||||
from "../../../renderer/cluster-frame-context/hosted-cluster.injectable";
|
||||
import directoryForKubeConfigsInjectable
|
||||
from "../../app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable";
|
||||
import type { KubeJsonApiDataFor, KubeStatusData, KubeJsonApiData } from "@k8slens/kube-object";
|
||||
import setupAutoRegistrationInjectable from "../../../renderer/before-frame-starts/runnables/setup-auto-registration.injectable";
|
||||
import { createMockResponseFromStream, createMockResponseFromString } from "../../../test-utils/mock-responses";
|
||||
import storesAndApisCanBeCreatedInjectable from "../../../renderer/stores-apis-can-be-created.injectable";
|
||||
import directoryForUserDataInjectable from "../../app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
import hostedClusterInjectable from "../../../renderer/cluster-frame-context/hosted-cluster.injectable";
|
||||
import directoryForKubeConfigsInjectable from "../../app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable";
|
||||
import apiKubeInjectable from "../../../renderer/k8s/api-kube.injectable";
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import deploymentApiInjectable from "../endpoints/deployment.api.injectable";
|
||||
@@ -51,7 +40,7 @@ describe("createKubeApiForRemoteCluster", () => {
|
||||
let createKubeApiForRemoteCluster: CreateKubeApiForRemoteCluster;
|
||||
let fetchMock: AsyncFnMock<Fetch>;
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeEach(() => {
|
||||
const di = getDiForUnitTesting();
|
||||
|
||||
di.override(directoryForUserDataInjectable, () => "/some-user-store-path");
|
||||
@@ -70,7 +59,7 @@ describe("createKubeApiForRemoteCluster", () => {
|
||||
createKubeApiForRemoteCluster = di.inject(createKubeApiForRemoteClusterInjectable);
|
||||
});
|
||||
|
||||
it("builds api client for KubeObject", async () => {
|
||||
it("builds api client for KubeObject", () => {
|
||||
const api = createKubeApiForRemoteCluster({
|
||||
cluster: {
|
||||
server: "https://127.0.0.1:6443",
|
||||
@@ -150,7 +139,7 @@ describe("KubeApi", () => {
|
||||
let fetchMock: AsyncFnMock<Fetch>;
|
||||
let di: DiContainer;
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeEach(() => {
|
||||
di = getDiForUnitTesting();
|
||||
|
||||
di.override(directoryForUserDataInjectable, () => "/some-user-store-path");
|
||||
@@ -374,7 +363,7 @@ describe("KubeApi", () => {
|
||||
|
||||
describe("when request resolves", () => {
|
||||
beforeEach(async () => {
|
||||
fetchMock.resolveSpecific(
|
||||
await fetchMock.resolveSpecific(
|
||||
["http://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foo?propagationPolicy=Background"],
|
||||
createMockResponseFromString("http://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foo?propagationPolicy=Background", "{}"),
|
||||
);
|
||||
@@ -410,7 +399,7 @@ describe("KubeApi", () => {
|
||||
|
||||
describe("when request resolves", () => {
|
||||
beforeEach(async () => {
|
||||
fetchMock.resolveSpecific(
|
||||
await fetchMock.resolveSpecific(
|
||||
["http://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foo?propagationPolicy=Background"],
|
||||
createMockResponseFromString("http://127.0.0.1:9999/api-kube/api/v1/namespaces/default/pods/foo?propagationPolicy=Background", "{}"),
|
||||
);
|
||||
@@ -446,7 +435,7 @@ describe("KubeApi", () => {
|
||||
|
||||
describe("when request resolves", () => {
|
||||
beforeEach(async () => {
|
||||
fetchMock.resolveSpecific(
|
||||
await fetchMock.resolveSpecific(
|
||||
["http://127.0.0.1:9999/api-kube/api/v1/namespaces/test/pods/foo?propagationPolicy=Background"],
|
||||
createMockResponseFromString("http://127.0.0.1:9999/api-kube/api/v1/namespaces/test/pods/foo?propagationPolicy=Background", "{}"),
|
||||
);
|
||||
@@ -461,7 +450,7 @@ describe("KubeApi", () => {
|
||||
describe("eviction-api as better replacement for pod.delete() request", () => {
|
||||
let evictRequest: Promise<string>;
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeEach(() => {
|
||||
evictRequest = api.evict({ name: "foo", namespace: "test" });
|
||||
});
|
||||
|
||||
@@ -478,7 +467,7 @@ describe("KubeApi", () => {
|
||||
});
|
||||
|
||||
it("should resolve the call with >=200 <300 http code", async () => {
|
||||
fetchMock.resolveSpecific(
|
||||
await fetchMock.resolveSpecific(
|
||||
["http://127.0.0.1:9999/api-kube/api/v1/namespaces/test/pods/foo/eviction"],
|
||||
createMockResponseFromString("http://127.0.0.1:9999/api-kube/api/v1/namespaces/test/pods/foo/eviction", JSON.stringify({
|
||||
apiVersion: "policy/v1",
|
||||
@@ -492,7 +481,7 @@ describe("KubeApi", () => {
|
||||
});
|
||||
|
||||
it("should throw in case of error", async () => {
|
||||
fetchMock.resolveSpecific(
|
||||
await fetchMock.resolveSpecific(
|
||||
["http://127.0.0.1:9999/api-kube/api/v1/namespaces/test/pods/foo/eviction"],
|
||||
createMockResponseFromString("http://127.0.0.1:9999/api-kube/api/v1/namespaces/test/pods/foo/eviction", JSON.stringify({
|
||||
apiVersion: "policy/v1",
|
||||
@@ -502,12 +491,12 @@ describe("KubeApi", () => {
|
||||
} as KubeStatusData)),
|
||||
);
|
||||
|
||||
expect(async () => evictRequest).rejects.toBe("500: something went wrong");
|
||||
await expect(async () => evictRequest).rejects.toBe("500: something went wrong");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("deleting namespaces (cluser scoped resource)", () => {
|
||||
describe("deleting namespaces (cluster scoped resource)", () => {
|
||||
let api: NamespaceApi;
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -538,7 +527,7 @@ describe("KubeApi", () => {
|
||||
|
||||
describe("when request resolves", () => {
|
||||
beforeEach(async () => {
|
||||
fetchMock.resolveSpecific(
|
||||
await fetchMock.resolveSpecific(
|
||||
["http://127.0.0.1:9999/api-kube/api/v1/namespaces/foo?propagationPolicy=Background"],
|
||||
createMockResponseFromString("http://127.0.0.1:9999/api-kube/api/v1/namespaces/foo?propagationPolicy=Background", "{}"),
|
||||
);
|
||||
@@ -574,7 +563,7 @@ describe("KubeApi", () => {
|
||||
|
||||
describe("when request resolves", () => {
|
||||
beforeEach(async () => {
|
||||
fetchMock.resolveSpecific(
|
||||
await fetchMock.resolveSpecific(
|
||||
["http://127.0.0.1:9999/api-kube/api/v1/namespaces/foo?propagationPolicy=Background"],
|
||||
createMockResponseFromString("http://127.0.0.1:9999/api-kube/api/v1/namespaces/foo?propagationPolicy=Background", "{}"),
|
||||
);
|
||||
@@ -587,8 +576,8 @@ describe("KubeApi", () => {
|
||||
});
|
||||
|
||||
describe("when deleting by name and namespace", () => {
|
||||
it("rejects request", () => {
|
||||
expect(api.delete({ name: "foo", namespace: "test" })).rejects.toBeDefined();
|
||||
it("rejects request", async () => {
|
||||
await expect(api.delete({ name: "foo", namespace: "test" })).rejects.toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { noop } from "@k8slens/utilities";
|
||||
import type { KubeApi } from "../kube-api";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { KubeObject } from "@k8slens/kube-object";
|
||||
import type { KubeObjectStoreLoadingParams } from "../kube-object.store";
|
||||
import { KubeObjectStore } from "../kube-object.store";
|
||||
|
||||
@@ -30,7 +30,7 @@ class FakeKubeObjectStore extends KubeObjectStore<KubeObject> {
|
||||
}
|
||||
|
||||
async loadItems(params: KubeObjectStoreLoadingParams) {
|
||||
return this._loadItems(params);
|
||||
return Promise.resolve(this._loadItems(params));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { KubeObject } from "@k8slens/kube-object";
|
||||
|
||||
describe("KubeObject", () => {
|
||||
describe("isJsonApiData", () => {
|
||||
|
||||
@@ -1,192 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { Node } from "../endpoints";
|
||||
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
describe("Node tests", () => {
|
||||
describe("isMasterNode()", () => {
|
||||
it("given a master node labelled before kubernetes 1.20, should return true", () => {
|
||||
const node = new Node({
|
||||
apiVersion: "foo",
|
||||
kind: "Node",
|
||||
metadata: {
|
||||
name: "bar",
|
||||
resourceVersion: "1",
|
||||
uid: "bat",
|
||||
labels: {
|
||||
"node-role.kubernetes.io/master": "NoSchedule",
|
||||
},
|
||||
selfLink: "/api/v1/nodes/bar",
|
||||
},
|
||||
});
|
||||
|
||||
expect(node.isMasterNode()).toBe(true);
|
||||
});
|
||||
|
||||
it("given a master node labelled after kubernetes 1.20, should return true", () => {
|
||||
const node = new Node({
|
||||
apiVersion: "foo",
|
||||
kind: "Node",
|
||||
metadata: {
|
||||
name: "bar",
|
||||
resourceVersion: "1",
|
||||
uid: "bat",
|
||||
labels: {
|
||||
"node-role.kubernetes.io/control-plane": "NoSchedule",
|
||||
},
|
||||
selfLink: "/api/v1/nodes/bar",
|
||||
},
|
||||
});
|
||||
|
||||
expect(node.isMasterNode()).toBe(true);
|
||||
});
|
||||
|
||||
it("given a non master node, should return false", () => {
|
||||
const node = new Node({
|
||||
apiVersion: "foo",
|
||||
kind: "Node",
|
||||
metadata: {
|
||||
name: "bar",
|
||||
resourceVersion: "1",
|
||||
uid: "bat",
|
||||
labels: {},
|
||||
selfLink: "/api/v1/nodes/bar",
|
||||
},
|
||||
});
|
||||
|
||||
expect(node.isMasterNode()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getRoleLabels()", () => {
|
||||
it("should return empty string if labels is not present", () => {
|
||||
const node = new Node({
|
||||
apiVersion: "foo",
|
||||
kind: "Node",
|
||||
metadata: {
|
||||
name: "bar",
|
||||
resourceVersion: "1",
|
||||
uid: "bat",
|
||||
selfLink: "/api/v1/nodes/bar",
|
||||
},
|
||||
});
|
||||
|
||||
expect(node.getRoleLabels()).toBe("");
|
||||
});
|
||||
|
||||
it("should return empty string if labels is empty object", () => {
|
||||
const node = new Node({
|
||||
apiVersion: "foo",
|
||||
kind: "Node",
|
||||
metadata: {
|
||||
name: "bar",
|
||||
resourceVersion: "1",
|
||||
uid: "bat",
|
||||
labels: {},
|
||||
selfLink: "/api/v1/nodes/bar",
|
||||
},
|
||||
});
|
||||
|
||||
expect(node.getRoleLabels()).toBe("");
|
||||
});
|
||||
|
||||
it("should return rest of keys with substring node-role.kubernetes.io/", () => {
|
||||
const node = new Node({
|
||||
apiVersion: "foo",
|
||||
kind: "Node",
|
||||
metadata: {
|
||||
name: "bar",
|
||||
resourceVersion: "1",
|
||||
uid: "bat",
|
||||
labels: {
|
||||
"node-role.kubernetes.io/foobar": "bat",
|
||||
"hellonode-role.kubernetes.io/foobar1": "bat",
|
||||
},
|
||||
selfLink: "/api/v1/nodes/bar",
|
||||
},
|
||||
});
|
||||
|
||||
expect(node.getRoleLabels()).toBe("foobar, foobar1");
|
||||
});
|
||||
|
||||
it("should return rest of keys with substring node-role.kubernetes.io/ after last /", () => {
|
||||
const node = new Node({
|
||||
apiVersion: "foo",
|
||||
kind: "Node",
|
||||
metadata: {
|
||||
name: "bar",
|
||||
resourceVersion: "1",
|
||||
uid: "bat",
|
||||
labels: {
|
||||
"node-role.kubernetes.io/foobar": "bat",
|
||||
"hellonode-role.kubernetes.io//////foobar1": "bat",
|
||||
},
|
||||
selfLink: "/api/v1/nodes/bar",
|
||||
},
|
||||
});
|
||||
|
||||
expect(node.getRoleLabels()).toBe("foobar, foobar1");
|
||||
});
|
||||
|
||||
it("should return value of label kubernetes.io/role if present", () => {
|
||||
const node = new Node({
|
||||
apiVersion: "foo",
|
||||
kind: "Node",
|
||||
metadata: {
|
||||
name: "bar",
|
||||
resourceVersion: "1",
|
||||
uid: "bat",
|
||||
labels: {
|
||||
"kubernetes.io/role": "master",
|
||||
},
|
||||
selfLink: "/api/v1/nodes/bar",
|
||||
},
|
||||
});
|
||||
|
||||
expect(node.getRoleLabels()).toBe("master");
|
||||
});
|
||||
|
||||
it("should return value of label node.kubernetes.io/role if present", () => {
|
||||
const node = new Node({
|
||||
apiVersion: "foo",
|
||||
kind: "Node",
|
||||
metadata: {
|
||||
name: "bar",
|
||||
resourceVersion: "1",
|
||||
uid: "bat",
|
||||
labels: {
|
||||
"node.kubernetes.io/role": "master",
|
||||
},
|
||||
selfLink: "/api/v1/nodes/bar",
|
||||
},
|
||||
});
|
||||
|
||||
expect(node.getRoleLabels()).toBe("master");
|
||||
});
|
||||
|
||||
it("all sources should be joined together", () => {
|
||||
const node = new Node({
|
||||
apiVersion: "foo",
|
||||
kind: "Node",
|
||||
metadata: {
|
||||
name: "bar",
|
||||
resourceVersion: "1",
|
||||
uid: "bat",
|
||||
labels: {
|
||||
"aksjhdkjahsdnode-role.kubernetes.io/foobar": "bat",
|
||||
"kubernetes.io/role": "master",
|
||||
"node.kubernetes.io/role": "master-v2-max",
|
||||
},
|
||||
selfLink: "/api/v1/nodes/bar",
|
||||
},
|
||||
});
|
||||
|
||||
expect(node.getRoleLabels()).toBe("foobar, master, master-v2-max");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { Pod } from "../endpoints";
|
||||
import { Pod } from "@k8slens/kube-object";
|
||||
|
||||
describe("Pod tests", () => {
|
||||
it("getAllContainers() should never throw", () => {
|
||||
|
||||
@@ -1,318 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import assert from "assert";
|
||||
import type { Container, PodContainerStatus } from "../endpoints";
|
||||
import { Pod } from "../endpoints";
|
||||
|
||||
interface GetDummyPodOptions {
|
||||
running?: number;
|
||||
dead?: number;
|
||||
initRunning?: number;
|
||||
initDead?: number;
|
||||
}
|
||||
|
||||
function getDummyPod(rawOpts: GetDummyPodOptions = {}): Pod {
|
||||
const {
|
||||
running = 0,
|
||||
dead = 0,
|
||||
initDead = 0,
|
||||
initRunning = 0,
|
||||
} = rawOpts;
|
||||
|
||||
const containers: Container[] = [];
|
||||
const initContainers: Container[] = [];
|
||||
const containerStatuses: PodContainerStatus[] = [];
|
||||
const initContainerStatuses: PodContainerStatus[] = [];
|
||||
const pod = new Pod({
|
||||
apiVersion: "v1",
|
||||
kind: "Pod",
|
||||
metadata: {
|
||||
uid: "1",
|
||||
name: "test",
|
||||
resourceVersion: "v1",
|
||||
namespace: "default",
|
||||
selfLink: "/api/v1/pods/default/test",
|
||||
},
|
||||
spec: {
|
||||
containers,
|
||||
initContainers,
|
||||
serviceAccount: "dummy",
|
||||
serviceAccountName: "dummy",
|
||||
},
|
||||
status: {
|
||||
phase: "Running",
|
||||
conditions: [],
|
||||
hostIP: "10.0.0.1",
|
||||
podIP: "10.0.0.1",
|
||||
startTime: "now",
|
||||
containerStatuses,
|
||||
initContainerStatuses,
|
||||
},
|
||||
});
|
||||
|
||||
for (let i = 0; i < running; i += 1) {
|
||||
const name = `container_running_${i}`;
|
||||
|
||||
containers.push({
|
||||
image: "dummy",
|
||||
imagePullPolicy: "Always",
|
||||
name,
|
||||
});
|
||||
containerStatuses.push({
|
||||
image: "dummy",
|
||||
imageID: "dummy",
|
||||
name,
|
||||
ready: true,
|
||||
restartCount: i,
|
||||
state: {
|
||||
running: {
|
||||
startedAt: "before",
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
for (let i = 0; i < dead; i += 1) {
|
||||
const name = `container_dead_${i}`;
|
||||
|
||||
containers.push({
|
||||
image: "dummy",
|
||||
imagePullPolicy: "Always",
|
||||
name,
|
||||
});
|
||||
containerStatuses.push({
|
||||
image: "dummy",
|
||||
imageID: "dummy",
|
||||
name,
|
||||
ready: false,
|
||||
restartCount: i,
|
||||
state: {
|
||||
terminated: {
|
||||
startedAt: "before",
|
||||
exitCode: i+1,
|
||||
finishedAt: "later",
|
||||
reason: `reason_${i}`,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
for (let i = 0; i < initRunning; i += 1) {
|
||||
const name = `container_init-running_${i}`;
|
||||
|
||||
initContainers.push({
|
||||
image: "dummy",
|
||||
imagePullPolicy: "Always",
|
||||
name,
|
||||
});
|
||||
initContainerStatuses.push({
|
||||
image: "dummy",
|
||||
imageID: "dummy",
|
||||
name,
|
||||
ready: true,
|
||||
restartCount: i,
|
||||
state: {
|
||||
running: {
|
||||
startedAt: "before",
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
for (let i = 0; i < initDead; i += 1) {
|
||||
const name = `container_init-dead_${i}`;
|
||||
|
||||
initContainers.push({
|
||||
image: "dummy",
|
||||
imagePullPolicy: "Always",
|
||||
name,
|
||||
});
|
||||
initContainerStatuses.push({
|
||||
image: "dummy",
|
||||
imageID: "dummy",
|
||||
name,
|
||||
ready: false,
|
||||
restartCount: i,
|
||||
state: {
|
||||
terminated: {
|
||||
startedAt: "before",
|
||||
exitCode: i+1,
|
||||
finishedAt: "later",
|
||||
reason: `reason_${i}`,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return pod;
|
||||
}
|
||||
|
||||
describe("Pods", () => {
|
||||
const podTests = [];
|
||||
|
||||
for (let r = 0; r < 3; r += 1) {
|
||||
for (let d = 0; d < 3; d += 1) {
|
||||
for (let ir = 0; ir < 3; ir += 1) {
|
||||
for (let id = 0; id < 3; id += 1) {
|
||||
podTests.push([r, d, ir, id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
describe.each(podTests)("for [%d running, %d dead] & initial [%d running, %d dead]", (running, dead, initRunning, initDead) => {
|
||||
const pod = getDummyPod({ running, dead, initRunning, initDead });
|
||||
|
||||
function getNamedContainer(name: string) {
|
||||
return {
|
||||
image: "dummy",
|
||||
imagePullPolicy: "Always",
|
||||
name,
|
||||
};
|
||||
}
|
||||
|
||||
it("getRunningContainers should return only running and init running", () => {
|
||||
const res = [
|
||||
...Array.from(new Array(running), (val, index) => getNamedContainer(`container_running_${index}`)),
|
||||
...Array.from(new Array(initRunning), (val, index) => getNamedContainer(`container_init-running_${index}`)),
|
||||
];
|
||||
|
||||
expect(pod.getRunningContainers()).toStrictEqual(res);
|
||||
});
|
||||
|
||||
it("getAllContainers should return all containers", () => {
|
||||
const res = [
|
||||
...Array.from(new Array(running), (val, index) => getNamedContainer(`container_running_${index}`)),
|
||||
...Array.from(new Array(dead), (val, index) => getNamedContainer(`container_dead_${index}`)),
|
||||
...Array.from(new Array(initRunning), (val, index) => getNamedContainer(`container_init-running_${index}`)),
|
||||
...Array.from(new Array(initDead), (val, index) => getNamedContainer(`container_init-dead_${index}`)),
|
||||
];
|
||||
|
||||
expect(pod.getAllContainers()).toStrictEqual(res);
|
||||
});
|
||||
|
||||
it("getRestartsCount should return total restart counts", () => {
|
||||
function sum(len: number): number {
|
||||
let res = 0;
|
||||
|
||||
for (let i = 0; i < len; i += 1) {
|
||||
res += i;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
expect(pod.getRestartsCount()).toStrictEqual(sum(running) + sum(dead));
|
||||
});
|
||||
|
||||
it("hasIssues should return false", () => {
|
||||
expect(pod.hasIssues()).toStrictEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getSelectedNodeOs", () => {
|
||||
it("should return stable", () => {
|
||||
const pod = getDummyPod();
|
||||
|
||||
pod.spec.nodeSelector = {
|
||||
"kubernetes.io/os": "foobar",
|
||||
};
|
||||
|
||||
expect(pod.getSelectedNodeOs()).toStrictEqual("foobar");
|
||||
});
|
||||
|
||||
it("should return beta", () => {
|
||||
const pod = getDummyPod();
|
||||
|
||||
pod.spec.nodeSelector = {
|
||||
"beta.kubernetes.io/os": "foobar1",
|
||||
};
|
||||
|
||||
expect(pod.getSelectedNodeOs()).toStrictEqual("foobar1");
|
||||
});
|
||||
|
||||
it("should return stable over beta", () => {
|
||||
const pod = getDummyPod();
|
||||
|
||||
pod.spec.nodeSelector = {
|
||||
"kubernetes.io/os": "foobar2",
|
||||
"beta.kubernetes.io/os": "foobar3",
|
||||
};
|
||||
|
||||
expect(pod.getSelectedNodeOs()).toStrictEqual("foobar2");
|
||||
});
|
||||
|
||||
it("should return undefined if none set", () => {
|
||||
const pod = getDummyPod();
|
||||
|
||||
expect(pod.getSelectedNodeOs()).toStrictEqual(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe("hasIssues", () => {
|
||||
it("should return true if a condition isn't ready", () => {
|
||||
const pod = getDummyPod({ running: 1 });
|
||||
|
||||
pod.status?.conditions.push({
|
||||
type: "Ready",
|
||||
status: "foobar",
|
||||
lastProbeTime: 1,
|
||||
lastTransitionTime: "longer ago",
|
||||
});
|
||||
|
||||
expect(pod.hasIssues()).toStrictEqual(true);
|
||||
});
|
||||
|
||||
it("should return false if a condition is non-ready", () => {
|
||||
const pod = getDummyPod({ running: 1 });
|
||||
|
||||
pod.status?.conditions.push({
|
||||
type: "dummy",
|
||||
status: "foobar",
|
||||
lastProbeTime: 1,
|
||||
lastTransitionTime: "longer ago",
|
||||
});
|
||||
|
||||
expect(pod.hasIssues()).toStrictEqual(false);
|
||||
});
|
||||
|
||||
it("should return true if a current container is in a crash loop back off", () => {
|
||||
const pod = getDummyPod({ running: 1 });
|
||||
const firstStatus = pod.status?.containerStatuses?.[0];
|
||||
|
||||
assert(firstStatus);
|
||||
|
||||
firstStatus.state = {
|
||||
waiting: {
|
||||
reason: "CrashLookBackOff",
|
||||
message: "too much foobar",
|
||||
},
|
||||
};
|
||||
|
||||
expect(pod.hasIssues()).toStrictEqual(true);
|
||||
});
|
||||
|
||||
it("should return true if a current phase isn't running", () => {
|
||||
const pod = getDummyPod({ running: 1 });
|
||||
|
||||
assert(pod.status);
|
||||
|
||||
pod.status.phase = "not running";
|
||||
|
||||
expect(pod.hasIssues()).toStrictEqual(true);
|
||||
});
|
||||
|
||||
it("should return false if a current phase is running", () => {
|
||||
const pod = getDummyPod({ running: 1 });
|
||||
|
||||
assert(pod.status);
|
||||
|
||||
pod.status.phase = "Running";
|
||||
|
||||
expect(pod.hasIssues()).toStrictEqual(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -8,7 +8,7 @@ import type { KubeObjectStore } from "../kube-object.store";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import { autorun, action, observable } from "mobx";
|
||||
import type { KubeApi } from "../kube-api";
|
||||
import type { KubeObject, ObjectReference } from "../kube-object";
|
||||
import type { KubeObject, ObjectReference } from "@k8slens/kube-object";
|
||||
import { parseKubeApi, createKubeApiURL } from "../kube-api-parse";
|
||||
import { getOrInsertWith, iter } from "@k8slens/utilities";
|
||||
import type { CreateCustomResourceStore } from "./create-custom-resource-store.injectable";
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
||||
import clusterFrameContextForNamespacedResourcesInjectable from "../../../renderer/cluster-frame-context/for-namespaced-resources.injectable";
|
||||
import loggerInjectable from "../../logger.injectable";
|
||||
import type { KubeApi } from "../kube-api";
|
||||
import type { KubeObject } from "../kube-object";
|
||||
import type { KubeObject } from "@k8slens/kube-object";
|
||||
import type { KubeObjectStoreDependencies } from "../kube-object.store";
|
||||
import { CustomResourceStore } from "./resource.store";
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import type { KubeApi } from "../kube-api";
|
||||
import type { KubeObjectStoreDependencies } from "../kube-object.store";
|
||||
import { KubeObjectStore } from "../kube-object.store";
|
||||
import type { KubeObject } from "../kube-object";
|
||||
import type { KubeObject } from "@k8slens/kube-object";
|
||||
|
||||
export class CustomResourceStore<K extends KubeObject> extends KubeObjectStore<K, KubeApi<K>> {
|
||||
constructor(deps: KubeObjectStoreDependencies, api: KubeApi<K>) {
|
||||
|
||||
@@ -10,7 +10,7 @@ import apiBaseInjectable from "./api-base.injectable";
|
||||
import type { KubeApiConstructor } from "./create-kube-api-for-remote-cluster.injectable";
|
||||
import createKubeJsonApiInjectable from "./create-kube-json-api.injectable";
|
||||
import { KubeApi } from "./kube-api";
|
||||
import type { KubeJsonApiDataFor, KubeObject, KubeObjectConstructor } from "./kube-object";
|
||||
import type { KubeJsonApiDataFor, KubeObject, KubeObjectConstructor } from "@k8slens/kube-object";
|
||||
|
||||
export interface CreateKubeApiForLocalClusterConfig {
|
||||
metadata: {
|
||||
|
||||
@@ -11,7 +11,7 @@ import isDevelopmentInjectable from "../vars/is-development.injectable";
|
||||
import createKubeJsonApiInjectable from "./create-kube-json-api.injectable";
|
||||
import type { KubeApiOptions } from "./kube-api";
|
||||
import { KubeApi } from "./kube-api";
|
||||
import type { KubeJsonApiDataFor, KubeObject, KubeObjectConstructor } from "./kube-object";
|
||||
import type { KubeJsonApiDataFor, KubeObject, KubeObjectConstructor } from "@k8slens/kube-object";
|
||||
|
||||
export interface CreateKubeApiForRemoteClusterConfig {
|
||||
cluster: {
|
||||
|
||||
@@ -4,47 +4,8 @@
|
||||
*/
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import type { ClusterScopedMetadata, KubeObjectMetadata, KubeObjectScope } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { RoleRef } from "./types/role-ref";
|
||||
import type { Subject } from "./types/subject";
|
||||
|
||||
export interface ClusterRoleBindingData extends KubeJsonApiData<KubeObjectMetadata<KubeObjectScope.Cluster>, void, void> {
|
||||
subjects?: Subject[];
|
||||
roleRef: RoleRef;
|
||||
}
|
||||
|
||||
export class ClusterRoleBinding extends KubeObject<
|
||||
ClusterScopedMetadata,
|
||||
void,
|
||||
void
|
||||
> {
|
||||
static kind = "ClusterRoleBinding";
|
||||
static namespaced = false;
|
||||
static apiBase = "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings";
|
||||
|
||||
subjects?: Subject[];
|
||||
roleRef: RoleRef;
|
||||
|
||||
constructor({
|
||||
subjects,
|
||||
roleRef,
|
||||
...rest
|
||||
}: ClusterRoleBindingData) {
|
||||
super(rest);
|
||||
this.subjects = subjects;
|
||||
this.roleRef = roleRef;
|
||||
}
|
||||
|
||||
getSubjects() {
|
||||
return this.subjects ?? [];
|
||||
}
|
||||
|
||||
getSubjectNames(): string {
|
||||
return this.getSubjects().map(subject => subject.name).join(", ");
|
||||
}
|
||||
}
|
||||
import type { ClusterRoleBindingData } from "@k8slens/kube-object";
|
||||
import { ClusterRoleBinding } from "@k8slens/kube-object";
|
||||
|
||||
export class ClusterRoleBindingApi extends KubeApi<ClusterRoleBinding, ClusterRoleBindingData> {
|
||||
constructor(deps: KubeApiDependencies, opts: DerivedKubeApiOptions = {}) {
|
||||
|
||||
@@ -5,39 +5,8 @@
|
||||
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import type { ClusterScopedMetadata, KubeObjectMetadata, KubeObjectScope } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { AggregationRule } from "./types/aggregation-rule";
|
||||
import type { PolicyRule } from "./types/policy-rule";
|
||||
|
||||
export interface ClusterRoleData extends KubeJsonApiData<KubeObjectMetadata<KubeObjectScope.Cluster>, void, void> {
|
||||
rules?: PolicyRule[];
|
||||
aggregationRule?: AggregationRule;
|
||||
}
|
||||
|
||||
export class ClusterRole extends KubeObject<
|
||||
ClusterScopedMetadata,
|
||||
void,
|
||||
void
|
||||
> {
|
||||
static kind = "ClusterRole";
|
||||
static namespaced = false;
|
||||
static apiBase = "/apis/rbac.authorization.k8s.io/v1/clusterroles";
|
||||
|
||||
rules?: PolicyRule[];
|
||||
aggregationRule?: AggregationRule;
|
||||
|
||||
constructor({ rules, aggregationRule, ...rest }: ClusterRoleData) {
|
||||
super(rest);
|
||||
this.rules = rules;
|
||||
this.aggregationRule = aggregationRule;
|
||||
}
|
||||
|
||||
getRules() {
|
||||
return this.rules || [];
|
||||
}
|
||||
}
|
||||
import type { ClusterRoleData } from "@k8slens/kube-object";
|
||||
import { ClusterRole } from "@k8slens/kube-object";
|
||||
|
||||
export class ClusterRoleApi extends KubeApi<ClusterRole, ClusterRoleData> {
|
||||
constructor(deps: KubeApiDependencies, opts: DerivedKubeApiOptions = {}) {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { Cluster } from "@k8slens/kube-object";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
|
||||
@@ -25,58 +25,3 @@ export class ClusterApi extends KubeApi<Cluster> {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export enum ClusterStatus {
|
||||
ACTIVE = "Active",
|
||||
CREATING = "Creating",
|
||||
REMOVING = "Removing",
|
||||
ERROR = "Error",
|
||||
}
|
||||
|
||||
export interface Cluster {
|
||||
spec: {
|
||||
clusterNetwork?: {
|
||||
serviceDomain?: string;
|
||||
pods?: {
|
||||
cidrBlocks?: string[];
|
||||
};
|
||||
services?: {
|
||||
cidrBlocks?: string[];
|
||||
};
|
||||
};
|
||||
providerSpec: {
|
||||
value: {
|
||||
profile: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
status?: {
|
||||
apiEndpoints: {
|
||||
host: string;
|
||||
port: string;
|
||||
}[];
|
||||
providerStatus: {
|
||||
adminUser?: string;
|
||||
adminPassword?: string;
|
||||
kubeconfig?: string;
|
||||
processState?: string;
|
||||
lensAddress?: string;
|
||||
};
|
||||
errorMessage?: string;
|
||||
errorReason?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export class Cluster extends KubeObject {
|
||||
static kind = "Cluster";
|
||||
static apiBase = "/apis/cluster.k8s.io/v1alpha1/clusters";
|
||||
static namespaced = true;
|
||||
|
||||
getStatus() {
|
||||
if (this.metadata.deletionTimestamp) return ClusterStatus.REMOVING;
|
||||
if (!this.status || !this.status) return ClusterStatus.CREATING;
|
||||
if (this.status.errorMessage) return ClusterStatus.ERROR;
|
||||
|
||||
return ClusterStatus.ACTIVE;
|
||||
}
|
||||
}
|
||||
@@ -3,30 +3,10 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { ComponentStatus } from "@k8slens/kube-object";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
|
||||
export interface ComponentStatusCondition {
|
||||
type: string;
|
||||
status: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface ComponentStatus {
|
||||
conditions: ComponentStatusCondition[];
|
||||
}
|
||||
|
||||
export class ComponentStatus extends KubeObject {
|
||||
static kind = "ComponentStatus";
|
||||
static namespaced = false;
|
||||
static apiBase = "/api/v1/componentstatuses";
|
||||
|
||||
getTruthyConditions() {
|
||||
return this.conditions.filter(c => c.status === "True");
|
||||
}
|
||||
}
|
||||
|
||||
export class ComponentStatusApi extends KubeApi<ComponentStatus> {
|
||||
constructor(deps: KubeApiDependencies, opts: DerivedKubeApiOptions = {}) {
|
||||
super(deps, {
|
||||
|
||||
@@ -3,45 +3,10 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { KubeObjectMetadata, KubeObjectScope, NamespaceScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import type { ConfigMapData } from "@k8slens/kube-object";
|
||||
import { ConfigMap } from "@k8slens/kube-object";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import autoBind from "auto-bind";
|
||||
|
||||
export interface ConfigMapData extends KubeJsonApiData<KubeObjectMetadata<KubeObjectScope.Namespace>, void, void> {
|
||||
data?: Partial<Record<string, string>>;
|
||||
binaryData?: Partial<Record<string, string>>;
|
||||
immutable?: boolean;
|
||||
}
|
||||
|
||||
export class ConfigMap extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
void,
|
||||
void
|
||||
> {
|
||||
static kind = "ConfigMap";
|
||||
static namespaced = true;
|
||||
static apiBase = "/api/v1/configmaps";
|
||||
|
||||
data: Partial<Record<string, string>>;
|
||||
binaryData: Partial<Record<string, string>>;
|
||||
immutable?: boolean;
|
||||
|
||||
constructor({ data, binaryData, immutable, ...rest }: ConfigMapData) {
|
||||
super(rest);
|
||||
autoBind(this);
|
||||
|
||||
this.data = data ?? {};
|
||||
this.binaryData = binaryData ?? {};
|
||||
this.immutable = immutable;
|
||||
}
|
||||
|
||||
getKeys(): string[] {
|
||||
return Object.keys(this.data);
|
||||
}
|
||||
}
|
||||
|
||||
export class ConfigMapApi extends KubeApi<ConfigMap, ConfigMapData> {
|
||||
constructor(deps: KubeApiDependencies, opts?: DerivedKubeApiOptions) {
|
||||
|
||||
@@ -3,13 +3,9 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import moment from "moment";
|
||||
import type { NamespaceScopedMetadata, ObjectReference } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { formatDuration } from "@k8slens/utilities";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { CronJob } from "@k8slens/kube-object";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies, NamespacedResourceDescriptor } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { JobTemplateSpec } from "./types/job-template-spec";
|
||||
|
||||
export class CronJobApi extends KubeApi<CronJob> {
|
||||
constructor(deps: KubeApiDependencies, opts: DerivedKubeApiOptions) {
|
||||
@@ -19,90 +15,19 @@ export class CronJobApi extends KubeApi<CronJob> {
|
||||
});
|
||||
}
|
||||
|
||||
suspend(params: { namespace: string; name: string }) {
|
||||
return this.request.patch(this.getUrl(params), {
|
||||
data: {
|
||||
spec: {
|
||||
suspend: true,
|
||||
},
|
||||
private requestSetSuspend(params: NamespacedResourceDescriptor, suspend: boolean) {
|
||||
return this.patch(params, {
|
||||
spec: {
|
||||
suspend,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"content-type": "application/strategic-merge-patch+json",
|
||||
},
|
||||
});
|
||||
}, "strategic");
|
||||
}
|
||||
|
||||
resume(params: { namespace: string; name: string }) {
|
||||
return this.request.patch(this.getUrl(params), {
|
||||
data: {
|
||||
spec: {
|
||||
suspend: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"content-type": "application/strategic-merge-patch+json",
|
||||
},
|
||||
});
|
||||
suspend(params: NamespacedResourceDescriptor) {
|
||||
return this.requestSetSuspend(params, true);
|
||||
}
|
||||
}
|
||||
|
||||
export interface CronJobSpec {
|
||||
concurrencyPolicy?: string;
|
||||
failedJobsHistoryLimit?: number;
|
||||
jobTemplate?: JobTemplateSpec;
|
||||
schedule: string;
|
||||
startingDeadlineSeconds?: number;
|
||||
successfulJobsHistoryLimit?: number;
|
||||
suspend?: boolean;
|
||||
}
|
||||
|
||||
export interface CronJobStatus {
|
||||
lastScheduleTime?: string;
|
||||
lastSuccessfulTime?: string;
|
||||
active?: ObjectReference[];
|
||||
}
|
||||
|
||||
export class CronJob extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
CronJobStatus,
|
||||
CronJobSpec
|
||||
> {
|
||||
static readonly kind = "CronJob";
|
||||
static readonly namespaced = true;
|
||||
static readonly apiBase = "/apis/batch/v1/cronjobs";
|
||||
|
||||
getSuspendFlag() {
|
||||
return (this.spec.suspend ?? false).toString();
|
||||
}
|
||||
|
||||
getLastScheduleTime() {
|
||||
if (!this.status?.lastScheduleTime) return "-";
|
||||
const diff = moment().diff(this.status.lastScheduleTime);
|
||||
|
||||
return formatDuration(diff, true);
|
||||
}
|
||||
|
||||
getSchedule() {
|
||||
return this.spec.schedule;
|
||||
}
|
||||
|
||||
isNeverRun() {
|
||||
const schedule = this.getSchedule();
|
||||
const daysInMonth = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
||||
const stamps = schedule.split(" ");
|
||||
const day = Number(stamps[stamps.length - 3]); // 1-31
|
||||
const month = Number(stamps[stamps.length - 2]); // 1-12
|
||||
|
||||
if (schedule.startsWith("@")) return false;
|
||||
|
||||
return day > daysInMonth[month - 1];
|
||||
}
|
||||
|
||||
isSuspend() {
|
||||
return this.spec.suspend;
|
||||
resume(params: NamespacedResourceDescriptor) {
|
||||
return this.requestSetSuspend(params, false);
|
||||
}
|
||||
}
|
||||
@@ -3,235 +3,9 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getLegacyGlobalDiForExtensionApi } from "@k8slens/legacy-global-di";
|
||||
import customResourcesRouteInjectable from "../../front-end-routing/routes/cluster/custom-resources/custom-resources/custom-resources-route.injectable";
|
||||
import { buildURL } from "@k8slens/utilities";
|
||||
import type { BaseKubeObjectCondition, ClusterScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { CustomResourceDefinition } from "@k8slens/kube-object";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { JSONSchemaProps } from "./types/json-schema-props";
|
||||
|
||||
interface AdditionalPrinterColumnsCommon {
|
||||
name: string;
|
||||
type: "integer" | "number" | "string" | "boolean" | "date";
|
||||
priority?: number;
|
||||
format?: "int32" | "int64" | "float" | "double" | "byte" | "binary" | "date" | "date-time" | "password";
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export type AdditionalPrinterColumnsV1 = AdditionalPrinterColumnsCommon & {
|
||||
jsonPath: string;
|
||||
};
|
||||
|
||||
type AdditionalPrinterColumnsV1Beta = AdditionalPrinterColumnsCommon & {
|
||||
JSONPath: string;
|
||||
};
|
||||
|
||||
export interface CustomResourceValidation {
|
||||
openAPIV3Schema?: JSONSchemaProps;
|
||||
}
|
||||
|
||||
export interface CustomResourceDefinitionVersion {
|
||||
name: string;
|
||||
served: boolean;
|
||||
storage: boolean;
|
||||
schema?: CustomResourceValidation; // required in v1 but not present in v1beta
|
||||
additionalPrinterColumns?: AdditionalPrinterColumnsV1[];
|
||||
}
|
||||
|
||||
export interface CustomResourceDefinitionNames {
|
||||
categories?: string[];
|
||||
kind: string;
|
||||
listKind?: string;
|
||||
plural: string;
|
||||
shortNames?: string[];
|
||||
singular?: string;
|
||||
}
|
||||
|
||||
export interface CustomResourceConversion {
|
||||
strategy?: string;
|
||||
webhook?: WebhookConversion;
|
||||
}
|
||||
|
||||
export interface WebhookConversion {
|
||||
clientConfig?: WebhookClientConfig[];
|
||||
conversionReviewVersions: string[];
|
||||
}
|
||||
|
||||
export interface WebhookClientConfig {
|
||||
caBundle?: string;
|
||||
url?: string;
|
||||
service?: ServiceReference;
|
||||
}
|
||||
|
||||
export interface ServiceReference {
|
||||
name: string;
|
||||
namespace: string;
|
||||
path?: string;
|
||||
port?: number;
|
||||
}
|
||||
|
||||
export interface CustomResourceDefinitionSpec {
|
||||
group: string;
|
||||
/**
|
||||
* @deprecated for apiextensions.k8s.io/v1 but used in v1beta1
|
||||
*/
|
||||
version?: string;
|
||||
names: CustomResourceDefinitionNames;
|
||||
scope: "Namespaced" | "Cluster";
|
||||
/**
|
||||
* @deprecated for apiextensions.k8s.io/v1 but used in v1beta1
|
||||
*/
|
||||
validation?: object;
|
||||
versions?: CustomResourceDefinitionVersion[];
|
||||
conversion?: CustomResourceConversion;
|
||||
/**
|
||||
* @deprecated for apiextensions.k8s.io/v1 but used in v1beta1
|
||||
*/
|
||||
additionalPrinterColumns?: AdditionalPrinterColumnsV1Beta[];
|
||||
preserveUnknownFields?: boolean;
|
||||
}
|
||||
|
||||
export interface CustomResourceDefinitionConditionAcceptedNames {
|
||||
plural: string;
|
||||
singular: string;
|
||||
kind: string;
|
||||
shortNames: string[];
|
||||
listKind: string;
|
||||
}
|
||||
|
||||
export interface CustomResourceDefinitionStatus {
|
||||
conditions?: BaseKubeObjectCondition[];
|
||||
acceptedNames: CustomResourceDefinitionConditionAcceptedNames;
|
||||
storedVersions: string[];
|
||||
}
|
||||
|
||||
export class CustomResourceDefinition extends KubeObject<
|
||||
ClusterScopedMetadata,
|
||||
CustomResourceDefinitionStatus,
|
||||
CustomResourceDefinitionSpec
|
||||
> {
|
||||
static kind = "CustomResourceDefinition";
|
||||
static namespaced = false;
|
||||
static apiBase = "/apis/apiextensions.k8s.io/v1/customresourcedefinitions";
|
||||
|
||||
getResourceUrl() {
|
||||
const di = getLegacyGlobalDiForExtensionApi();
|
||||
|
||||
const customResourcesRoute = di.inject(customResourcesRouteInjectable);
|
||||
|
||||
return buildURL(customResourcesRoute.path, {
|
||||
params: {
|
||||
group: this.getGroup(),
|
||||
name: this.getPluralName(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
getResourceApiBase() {
|
||||
const { group } = this.spec;
|
||||
|
||||
return `/apis/${group}/${this.getVersion()}/${this.getPluralName()}`;
|
||||
}
|
||||
|
||||
getPluralName() {
|
||||
return this.getNames().plural;
|
||||
}
|
||||
|
||||
getResourceKind() {
|
||||
return this.spec.names.kind;
|
||||
}
|
||||
|
||||
getResourceTitle() {
|
||||
const name = this.getPluralName();
|
||||
|
||||
return name[0].toUpperCase() + name.slice(1);
|
||||
}
|
||||
|
||||
getGroup() {
|
||||
return this.spec.group;
|
||||
}
|
||||
|
||||
getScope() {
|
||||
return this.spec.scope;
|
||||
}
|
||||
|
||||
getPreferedVersion(): CustomResourceDefinitionVersion {
|
||||
const { apiVersion } = this;
|
||||
|
||||
switch (apiVersion) {
|
||||
case "apiextensions.k8s.io/v1":
|
||||
for (const version of this.spec.versions ?? []) {
|
||||
if (version.storage) {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "apiextensions.k8s.io/v1beta1": {
|
||||
const { additionalPrinterColumns: apc } = this.spec;
|
||||
const additionalPrinterColumns = apc?.map(({ JSONPath, ...apc }) => ({ ...apc, jsonPath: JSONPath }));
|
||||
|
||||
return {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
name: this.spec.version!,
|
||||
served: true,
|
||||
storage: true,
|
||||
schema: this.spec.validation,
|
||||
additionalPrinterColumns,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Unknown apiVersion=${apiVersion}: Failed to find a version for CustomResourceDefinition ${this.metadata.name}`);
|
||||
}
|
||||
|
||||
getVersion() {
|
||||
return this.getPreferedVersion().name;
|
||||
}
|
||||
|
||||
isNamespaced() {
|
||||
return this.getScope() === "Namespaced";
|
||||
}
|
||||
|
||||
getStoredVersions() {
|
||||
return this.status?.storedVersions.join(", ") ?? "";
|
||||
}
|
||||
|
||||
getNames() {
|
||||
return this.spec.names;
|
||||
}
|
||||
|
||||
getConversion() {
|
||||
return JSON.stringify(this.spec.conversion);
|
||||
}
|
||||
|
||||
getPrinterColumns(ignorePriority = true): AdditionalPrinterColumnsV1[] {
|
||||
const columns = this.getPreferedVersion().additionalPrinterColumns ?? [];
|
||||
|
||||
return columns
|
||||
.filter(column => column.name.toLowerCase() != "age" && (ignorePriority || !column.priority));
|
||||
}
|
||||
|
||||
getValidation() {
|
||||
return JSON.stringify(this.getPreferedVersion().schema, null, 2);
|
||||
}
|
||||
|
||||
getConditions() {
|
||||
if (!this.status?.conditions) return [];
|
||||
|
||||
return this.status.conditions.map(condition => {
|
||||
const { message, reason, lastTransitionTime, status } = condition;
|
||||
|
||||
return {
|
||||
...condition,
|
||||
isReady: status === "True",
|
||||
tooltip: `${message || reason} (${lastTransitionTime})`,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class CustomResourceDefinitionApi extends KubeApi<CustomResourceDefinition> {
|
||||
constructor(deps: KubeApiDependencies, opts: DerivedKubeApiOptions = {}) {
|
||||
|
||||
@@ -13,7 +13,7 @@ import maybeKubeApiInjectable from "../maybe-kube-api.injectable";
|
||||
const daemonSetApiInjectable = getInjectable({
|
||||
id: "daemon-set-api",
|
||||
instantiate: (di) => {
|
||||
assert(di.inject(storesAndApisCanBeCreatedInjectionToken), "daemonSetApi is only available in certain environements");
|
||||
assert(di.inject(storesAndApisCanBeCreatedInjectionToken), "daemonSetApi is only available in certain environments");
|
||||
|
||||
return new DaemonSetApi({
|
||||
logger: di.inject(loggerInjectable),
|
||||
|
||||
@@ -4,83 +4,9 @@
|
||||
*/
|
||||
|
||||
import moment from "moment";
|
||||
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies, NamespacedResourceDescriptor } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeObjectStatus, LabelSelector, NamespaceScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { PodTemplateSpec } from "./types/pod-template-spec";
|
||||
|
||||
export interface RollingUpdateDaemonSet {
|
||||
maxUnavailable?: number | string;
|
||||
maxSurge?: number | string;
|
||||
}
|
||||
|
||||
export interface DaemonSetUpdateStrategy {
|
||||
type: string;
|
||||
rollingUpdate: RollingUpdateDaemonSet;
|
||||
}
|
||||
|
||||
export interface DaemonSetSpec {
|
||||
selector: LabelSelector;
|
||||
template: PodTemplateSpec;
|
||||
updateStrategy: DaemonSetUpdateStrategy;
|
||||
minReadySeconds?: number;
|
||||
revisionHistoryLimit?: number;
|
||||
}
|
||||
|
||||
export interface DaemonSetStatus extends KubeObjectStatus {
|
||||
collisionCount?: number;
|
||||
currentNumberScheduled: number;
|
||||
desiredNumberScheduled: number;
|
||||
numberAvailable?: number;
|
||||
numberMisscheduled: number;
|
||||
numberReady: number;
|
||||
numberUnavailable?: number;
|
||||
observedGeneration?: number;
|
||||
updatedNumberScheduled?: number;
|
||||
}
|
||||
|
||||
export class DaemonSet extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
DaemonSetStatus,
|
||||
DaemonSetSpec
|
||||
> {
|
||||
static kind = "DaemonSet";
|
||||
static namespaced = true;
|
||||
static apiBase = "/apis/apps/v1/daemonsets";
|
||||
|
||||
getSelectors(): string[] {
|
||||
return KubeObject.stringifyLabels(this.spec.selector.matchLabels);
|
||||
}
|
||||
|
||||
getNodeSelectors(): string[] {
|
||||
return KubeObject.stringifyLabels(this.spec.template.spec?.nodeSelector);
|
||||
}
|
||||
|
||||
getTemplateLabels(): string[] {
|
||||
return KubeObject.stringifyLabels(this.spec.template.metadata?.labels);
|
||||
}
|
||||
|
||||
getTolerations() {
|
||||
return this.spec.template.spec?.tolerations ?? [];
|
||||
}
|
||||
|
||||
getAffinity() {
|
||||
return this.spec.template.spec?.affinity;
|
||||
}
|
||||
|
||||
getAffinityNumber() {
|
||||
return Object.keys(this.getAffinity() ?? {}).length;
|
||||
}
|
||||
|
||||
getImages() {
|
||||
const containers = this.spec.template?.spec?.containers ?? [];
|
||||
const initContainers = this.spec.template?.spec?.initContainers ?? [];
|
||||
|
||||
return [...containers, ...initContainers].map(container => container.image);
|
||||
}
|
||||
}
|
||||
import { DaemonSet } from "@k8slens/kube-object";
|
||||
|
||||
export class DaemonSetApi extends KubeApi<DaemonSet> {
|
||||
constructor(deps: KubeApiDependencies, opts?: DerivedKubeApiOptions) {
|
||||
@@ -90,22 +16,15 @@ export class DaemonSetApi extends KubeApi<DaemonSet> {
|
||||
});
|
||||
}
|
||||
|
||||
restart(params: { namespace: string; name: string }) {
|
||||
return this.request.patch(this.getUrl(params), {
|
||||
data: {
|
||||
spec: {
|
||||
template: {
|
||||
metadata: {
|
||||
annotations: { "kubectl.kubernetes.io/restartedAt" : moment.utc().format() },
|
||||
},
|
||||
restart(params: NamespacedResourceDescriptor) {
|
||||
return this.patch(params, {
|
||||
spec: {
|
||||
template: {
|
||||
metadata: {
|
||||
annotations: { "kubectl.kubernetes.io/restartedAt" : moment.utc().format() },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"content-type": "application/strategic-merge-patch+json",
|
||||
},
|
||||
});
|
||||
}, "strategic");
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,9 @@
|
||||
|
||||
import moment from "moment";
|
||||
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies, NamespacedResourceDescriptor } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { PodSpec } from "./pod.api";
|
||||
import type { KubeObjectStatus, LabelSelector, NamespaceScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { Deployment } from "@k8slens/kube-object";
|
||||
import { hasTypedProperty, isNumber, isObject } from "@k8slens/utilities";
|
||||
|
||||
export class DeploymentApi extends KubeApi<Deployment> {
|
||||
@@ -20,11 +18,11 @@ export class DeploymentApi extends KubeApi<Deployment> {
|
||||
});
|
||||
}
|
||||
|
||||
protected getScaleApiUrl(params: { namespace: string; name: string }) {
|
||||
return `${this.getUrl(params)}/scale`;
|
||||
protected getScaleApiUrl(params: NamespacedResourceDescriptor) {
|
||||
return `${this.formatUrlForNotListing(params)}/scale`;
|
||||
}
|
||||
|
||||
async getReplicas(params: { namespace: string; name: string }): Promise<number> {
|
||||
async getReplicas(params: NamespacedResourceDescriptor): Promise<number> {
|
||||
const { status } = await this.request.get(this.getScaleApiUrl(params));
|
||||
|
||||
if (isObject(status) && hasTypedProperty(status, "replicas", isNumber)) {
|
||||
@@ -34,7 +32,7 @@ export class DeploymentApi extends KubeApi<Deployment> {
|
||||
return 0;
|
||||
}
|
||||
|
||||
scale(params: { namespace: string; name: string }, replicas: number) {
|
||||
scale(params: NamespacedResourceDescriptor, replicas: number) {
|
||||
return this.request.patch(this.getScaleApiUrl(params), {
|
||||
data: {
|
||||
spec: {
|
||||
@@ -49,105 +47,15 @@ export class DeploymentApi extends KubeApi<Deployment> {
|
||||
});
|
||||
}
|
||||
|
||||
restart(params: { namespace: string; name: string }) {
|
||||
return this.request.patch(this.getUrl(params), {
|
||||
data: {
|
||||
spec: {
|
||||
template: {
|
||||
metadata: {
|
||||
annotations: { "kubectl.kubernetes.io/restartedAt" : moment.utc().format() },
|
||||
},
|
||||
restart(params: NamespacedResourceDescriptor) {
|
||||
return this.patch(params, {
|
||||
spec: {
|
||||
template: {
|
||||
metadata: {
|
||||
annotations: { "kubectl.kubernetes.io/restartedAt" : moment.utc().format() },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"content-type": "application/strategic-merge-patch+json",
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export interface DeploymentSpec {
|
||||
replicas: number;
|
||||
selector: LabelSelector;
|
||||
template: {
|
||||
metadata: {
|
||||
creationTimestamp?: string;
|
||||
labels: Partial<Record<string, string>>;
|
||||
annotations?: Partial<Record<string, string>>;
|
||||
};
|
||||
spec: PodSpec;
|
||||
};
|
||||
strategy: {
|
||||
type: string;
|
||||
rollingUpdate: {
|
||||
maxUnavailable: number;
|
||||
maxSurge: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface DeploymentStatus extends KubeObjectStatus {
|
||||
observedGeneration: number;
|
||||
replicas: number;
|
||||
updatedReplicas: number;
|
||||
readyReplicas: number;
|
||||
availableReplicas?: number;
|
||||
unavailableReplicas?: number;
|
||||
}
|
||||
|
||||
export class Deployment extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
DeploymentStatus,
|
||||
DeploymentSpec
|
||||
> {
|
||||
static kind = "Deployment";
|
||||
static namespaced = true;
|
||||
static apiBase = "/apis/apps/v1/deployments";
|
||||
|
||||
getSelectors(): string[] {
|
||||
return KubeObject.stringifyLabels(this.spec.selector.matchLabels);
|
||||
}
|
||||
|
||||
getNodeSelectors(): string[] {
|
||||
return KubeObject.stringifyLabels(this.spec.template.spec.nodeSelector);
|
||||
}
|
||||
|
||||
getTemplateLabels(): string[] {
|
||||
return KubeObject.stringifyLabels(this.spec.template.metadata.labels);
|
||||
}
|
||||
|
||||
getTolerations() {
|
||||
return this.spec.template.spec.tolerations ?? [];
|
||||
}
|
||||
|
||||
getAffinity() {
|
||||
return this.spec.template.spec.affinity;
|
||||
}
|
||||
|
||||
getAffinityNumber() {
|
||||
return Object.keys(this.getAffinity() ?? {}).length;
|
||||
}
|
||||
|
||||
getConditions(activeOnly = false) {
|
||||
const { conditions = [] } = this.status ?? {};
|
||||
|
||||
if (activeOnly) {
|
||||
return conditions.filter(c => c.status === "True");
|
||||
}
|
||||
|
||||
return conditions;
|
||||
}
|
||||
|
||||
getConditionsText(activeOnly = true) {
|
||||
return this.getConditions(activeOnly)
|
||||
.map(({ type }) => type)
|
||||
.join(" ");
|
||||
}
|
||||
|
||||
getReplicas() {
|
||||
return this.spec.replicas || 0;
|
||||
}, "strategic");
|
||||
}
|
||||
}
|
||||
@@ -3,113 +3,10 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import autoBind from "auto-bind";
|
||||
import type { KubeObjectMetadata, KubeObjectScope, NamespaceScopedMetadata, ObjectReference } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { EndpointsData } from "@k8slens/kube-object";
|
||||
import { Endpoints } from "@k8slens/kube-object";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
|
||||
export function formatEndpointSubset(subset: EndpointSubset): string {
|
||||
const { addresses, ports } = subset;
|
||||
|
||||
if (!addresses || !ports) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return addresses
|
||||
.map(address => (
|
||||
ports
|
||||
.map(port => `${address.ip}:${port.port}`)
|
||||
.join(", ")
|
||||
))
|
||||
.join(", ");
|
||||
|
||||
}
|
||||
|
||||
export interface ForZone {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface EndpointHints {
|
||||
forZones?: ForZone[];
|
||||
}
|
||||
|
||||
export interface EndpointConditions {
|
||||
ready?: boolean;
|
||||
serving?: boolean;
|
||||
terminating?: boolean;
|
||||
}
|
||||
|
||||
export interface EndpointData {
|
||||
addresses: string[];
|
||||
conditions?: EndpointConditions;
|
||||
hints?: EndpointHints;
|
||||
hostname?: string;
|
||||
nodeName?: string;
|
||||
targetRef?: ObjectReference;
|
||||
zone?: string;
|
||||
}
|
||||
|
||||
export interface EndpointPort {
|
||||
appProtocol?: string;
|
||||
name?: string;
|
||||
protocol?: string;
|
||||
port: number;
|
||||
}
|
||||
|
||||
export interface EndpointAddress {
|
||||
hostname?: string;
|
||||
ip: string;
|
||||
nodeName?: string;
|
||||
targetRef?: ObjectReference;
|
||||
}
|
||||
|
||||
export interface EndpointSubset {
|
||||
addresses?: EndpointAddress[];
|
||||
notReadyAddresses?: EndpointAddress[];
|
||||
ports?: EndpointPort[];
|
||||
}
|
||||
|
||||
export interface EndpointsData extends KubeJsonApiData<KubeObjectMetadata<KubeObjectScope.Namespace>, void, void> {
|
||||
subsets?: EndpointSubset[];
|
||||
}
|
||||
|
||||
export class Endpoints extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
void,
|
||||
void
|
||||
> {
|
||||
static kind = "Endpoints";
|
||||
static namespaced = true;
|
||||
static apiBase = "/api/v1/endpoints";
|
||||
|
||||
subsets?: EndpointSubset[];
|
||||
|
||||
constructor({ subsets, ...rest }: EndpointsData) {
|
||||
super(rest);
|
||||
autoBind(this);
|
||||
this.subsets = subsets;
|
||||
}
|
||||
|
||||
getEndpointSubsets(): Required<EndpointSubset>[] {
|
||||
return this.subsets?.map(({
|
||||
addresses = [],
|
||||
notReadyAddresses = [],
|
||||
ports = [],
|
||||
}) => ({
|
||||
addresses,
|
||||
notReadyAddresses,
|
||||
ports,
|
||||
})) ?? [];
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return this.getEndpointSubsets()
|
||||
.map(formatEndpointSubset)
|
||||
.join(", ") || "<none>";
|
||||
}
|
||||
}
|
||||
|
||||
export class EndpointsApi extends KubeApi<Endpoints, EndpointsData> {
|
||||
constructor(deps: KubeApiDependencies, opts: DerivedKubeApiOptions = {}) {
|
||||
|
||||
@@ -3,133 +3,10 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import moment from "moment";
|
||||
import type { KubeObjectMetadata, KubeObjectScope, ObjectReference } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { formatDuration } from "@k8slens/utilities";
|
||||
import type { KubeEventData } from "@k8slens/kube-object";
|
||||
import { KubeEvent } from "@k8slens/kube-object";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
|
||||
export interface EventSeries {
|
||||
count?: number;
|
||||
lastObservedTime?: string;
|
||||
}
|
||||
|
||||
export interface EventSource {
|
||||
component?: string;
|
||||
host?: string;
|
||||
}
|
||||
|
||||
export interface KubeEventData extends KubeJsonApiData<KubeObjectMetadata<KubeObjectScope.Namespace>, void, void> {
|
||||
action?: string;
|
||||
count?: number;
|
||||
eventTime?: string;
|
||||
firstTimestamp?: string;
|
||||
involvedObject: Required<ObjectReference>;
|
||||
lastTimestamp?: string;
|
||||
message?: string;
|
||||
reason?: string;
|
||||
related?: ObjectReference;
|
||||
reportingComponent?: string;
|
||||
reportingInstance?: string;
|
||||
series?: EventSeries;
|
||||
source?: EventSource;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
export class KubeEvent extends KubeObject<KubeObjectMetadata<KubeObjectScope.Namespace>, void, void> {
|
||||
static kind = "Event";
|
||||
static namespaced = true;
|
||||
static apiBase = "/api/v1/events";
|
||||
|
||||
action?: string;
|
||||
count?: number;
|
||||
eventTime?: string;
|
||||
firstTimestamp?: string;
|
||||
involvedObject: Required<ObjectReference>;
|
||||
lastTimestamp?: string;
|
||||
message?: string;
|
||||
reason?: string;
|
||||
related?: ObjectReference;
|
||||
reportingComponent?: string;
|
||||
reportingInstance?: string;
|
||||
series?: EventSeries;
|
||||
source?: EventSource;
|
||||
|
||||
/**
|
||||
* Current supported values are:
|
||||
* - "Normal"
|
||||
* - "Warning"
|
||||
*/
|
||||
type?: string;
|
||||
|
||||
constructor({
|
||||
action,
|
||||
count,
|
||||
eventTime,
|
||||
firstTimestamp,
|
||||
involvedObject,
|
||||
lastTimestamp,
|
||||
message,
|
||||
reason,
|
||||
related,
|
||||
reportingComponent,
|
||||
reportingInstance,
|
||||
series,
|
||||
source,
|
||||
type,
|
||||
...rest
|
||||
}: KubeEventData) {
|
||||
super(rest);
|
||||
this.action = action;
|
||||
this.count = count;
|
||||
this.eventTime = eventTime;
|
||||
this.firstTimestamp = firstTimestamp;
|
||||
this.involvedObject = involvedObject;
|
||||
this.lastTimestamp = lastTimestamp;
|
||||
this.message = message;
|
||||
this.reason = reason;
|
||||
this.related = related;
|
||||
this.reportingComponent = reportingComponent;
|
||||
this.reportingInstance = reportingInstance;
|
||||
this.series = series;
|
||||
this.source = source;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
isWarning() {
|
||||
return this.type === "Warning";
|
||||
}
|
||||
|
||||
getSource() {
|
||||
if (!this.source?.component) {
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
const { component, host = "" } = this.source;
|
||||
|
||||
return `${component} ${host}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This function is not reactive to changing of time. If rendering use `<ReactiveDuration />` instead
|
||||
*/
|
||||
getFirstSeenTime() {
|
||||
const diff = moment().diff(this.firstTimestamp);
|
||||
|
||||
return formatDuration(diff, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This function is not reactive to changing of time. If rendering use `<ReactiveDuration />` instead
|
||||
*/
|
||||
getLastSeenTime() {
|
||||
const diff = moment().diff(this.lastTimestamp);
|
||||
|
||||
return formatDuration(diff, true);
|
||||
}
|
||||
}
|
||||
|
||||
export class KubeEventApi extends KubeApi<KubeEvent, KubeEventData> {
|
||||
constructor(deps: KubeApiDependencies, opts: DerivedKubeApiOptions = {}) {
|
||||
|
||||
+3
-3
@@ -3,7 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { KubeJsonApiData } from "../../kube-json-api";
|
||||
import type { KubeJsonApiData } from "@k8slens/kube-object";
|
||||
import { urlBuilderFor } from "@k8slens/utilities";
|
||||
import apiBaseInjectable from "../../api-base.injectable";
|
||||
|
||||
@@ -26,7 +26,7 @@ export interface HelmReleaseDetails {
|
||||
|
||||
export type CallForHelmReleaseDetails = (name: string, namespace: string) => Promise<HelmReleaseDetails>;
|
||||
|
||||
const requestDetailsEnpoint = urlBuilderFor("/v2/releases/:namespace/:name");
|
||||
const requestDetailsEndpoint = urlBuilderFor("/v2/releases/:namespace/:name");
|
||||
|
||||
const requestHelmReleaseDetailsInjectable = getInjectable({
|
||||
id: "call-for-helm-release-details",
|
||||
@@ -34,7 +34,7 @@ const requestHelmReleaseDetailsInjectable = getInjectable({
|
||||
instantiate: (di): CallForHelmReleaseDetails => {
|
||||
const apiBase = di.inject(apiBaseInjectable);
|
||||
|
||||
return (name, namespace) => apiBase.get(requestDetailsEnpoint.compile({ name, namespace }));
|
||||
return (name, namespace) => apiBase.get(requestDetailsEndpoint.compile({ name, namespace }));
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -3,365 +3,9 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { OptionVariant } from "@k8slens/utilities";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { BaseKubeObjectCondition, LabelSelector, NamespaceScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { CrossVersionObjectReference } from "./types/cross-version-object-reference";
|
||||
|
||||
export enum HpaMetricType {
|
||||
Resource = "Resource",
|
||||
Pods = "Pods",
|
||||
Object = "Object",
|
||||
External = "External",
|
||||
ContainerResource = "ContainerResource",
|
||||
}
|
||||
|
||||
export interface MetricCurrentTarget {
|
||||
current?: string;
|
||||
target?: string;
|
||||
}
|
||||
|
||||
export interface HorizontalPodAutoscalerMetricTarget {
|
||||
kind: string;
|
||||
name: string;
|
||||
apiVersion: string;
|
||||
}
|
||||
|
||||
export interface V2ContainerResourceMetricSource {
|
||||
container: string;
|
||||
name: string;
|
||||
target?: {
|
||||
averageUtilization?: number;
|
||||
averageValue?: string;
|
||||
type?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface V2Beta1ContainerResourceMetricSource {
|
||||
container: string;
|
||||
name: string;
|
||||
targetAverageUtilization?: number;
|
||||
targetAverageValue?: string;
|
||||
}
|
||||
|
||||
export type ContainerResourceMetricSource =
|
||||
| V2ContainerResourceMetricSource
|
||||
| V2Beta1ContainerResourceMetricSource;
|
||||
|
||||
export interface V2ExternalMetricSource {
|
||||
metricName?: string;
|
||||
metricSelector?: LabelSelector;
|
||||
metric?: {
|
||||
name?: string;
|
||||
selector?: LabelSelector;
|
||||
};
|
||||
target?: {
|
||||
type: string;
|
||||
value?: string;
|
||||
averageValue?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface V2Beta1ExternalMetricSource {
|
||||
metricName?: string;
|
||||
metricSelector?: LabelSelector;
|
||||
targetAverageValue?: string;
|
||||
targetValue?: string;
|
||||
metric?: {
|
||||
selector?: LabelSelector;
|
||||
};
|
||||
}
|
||||
|
||||
export type ExternalMetricSource =
|
||||
| V2Beta1ExternalMetricSource
|
||||
| V2ExternalMetricSource;
|
||||
|
||||
export interface V2ObjectMetricSource {
|
||||
metric?: {
|
||||
name?: string;
|
||||
selector?: LabelSelector;
|
||||
};
|
||||
target?: {
|
||||
type?: string;
|
||||
value?: string;
|
||||
averageValue?: string;
|
||||
};
|
||||
describedObject?: CrossVersionObjectReference;
|
||||
}
|
||||
|
||||
export interface V2Beta1ObjectMetricSource {
|
||||
averageValue?: string;
|
||||
metricName?: string;
|
||||
selector?: LabelSelector;
|
||||
targetValue?: string;
|
||||
describedObject?: CrossVersionObjectReference;
|
||||
}
|
||||
|
||||
export type ObjectMetricSource =
|
||||
| V2ObjectMetricSource
|
||||
| V2Beta1ObjectMetricSource;
|
||||
|
||||
export interface V2PodsMetricSource {
|
||||
metric?: {
|
||||
name?: string;
|
||||
selector?: LabelSelector;
|
||||
};
|
||||
target?: {
|
||||
averageValue?: string;
|
||||
type?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface V2Beta1PodsMetricSource {
|
||||
metricName?: string;
|
||||
selector?: LabelSelector;
|
||||
targetAverageValue?: string;
|
||||
}
|
||||
|
||||
export type PodsMetricSource =
|
||||
| V2PodsMetricSource
|
||||
| V2Beta1PodsMetricSource;
|
||||
|
||||
export interface V2ResourceMetricSource {
|
||||
name: string;
|
||||
target?: {
|
||||
averageUtilization?: number;
|
||||
averageValue?: string;
|
||||
type?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface V2Beta1ResourceMetricSource {
|
||||
name: string;
|
||||
targetAverageUtilization?: number;
|
||||
targetAverageValue?: string;
|
||||
}
|
||||
|
||||
export type ResourceMetricSource =
|
||||
| V2ResourceMetricSource
|
||||
| V2Beta1ResourceMetricSource;
|
||||
|
||||
export interface BaseHorizontalPodAutoscalerMetricSpec {
|
||||
containerResource: ContainerResourceMetricSource;
|
||||
external: ExternalMetricSource;
|
||||
object: ObjectMetricSource;
|
||||
pods: PodsMetricSource;
|
||||
resource: ResourceMetricSource;
|
||||
}
|
||||
|
||||
export type HorizontalPodAutoscalerMetricSpec =
|
||||
| OptionVariant<HpaMetricType.Resource, BaseHorizontalPodAutoscalerMetricSpec, "resource">
|
||||
| OptionVariant<HpaMetricType.External, BaseHorizontalPodAutoscalerMetricSpec, "external">
|
||||
| OptionVariant<HpaMetricType.Object, BaseHorizontalPodAutoscalerMetricSpec, "object">
|
||||
| OptionVariant<HpaMetricType.Pods, BaseHorizontalPodAutoscalerMetricSpec, "pods">
|
||||
| OptionVariant<HpaMetricType.ContainerResource, BaseHorizontalPodAutoscalerMetricSpec, "containerResource">;
|
||||
|
||||
interface HorizontalPodAutoscalerBehavior {
|
||||
scaleUp?: HPAScalingRules;
|
||||
scaleDown?: HPAScalingRules;
|
||||
}
|
||||
|
||||
interface HPAScalingRules {
|
||||
stabilizationWindowSecond?: number;
|
||||
selectPolicy?: ScalingPolicySelect;
|
||||
policies?: HPAScalingPolicy[];
|
||||
}
|
||||
|
||||
type ScalingPolicySelect = string;
|
||||
|
||||
interface HPAScalingPolicy {
|
||||
type: HPAScalingPolicyType;
|
||||
value: number;
|
||||
periodSeconds: number;
|
||||
}
|
||||
|
||||
type HPAScalingPolicyType = string;
|
||||
|
||||
export interface V2ContainerResourceMetricStatus {
|
||||
container?: string;
|
||||
name: string;
|
||||
current?: {
|
||||
averageUtilization?: number;
|
||||
averageValue?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface V2Beta1ContainerResourceMetricStatus {
|
||||
container?: string;
|
||||
currentAverageUtilization?: number;
|
||||
currentAverageValue?: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export type ContainerResourceMetricStatus =
|
||||
| V2ContainerResourceMetricStatus
|
||||
| V2Beta1ContainerResourceMetricStatus;
|
||||
|
||||
export interface V2ExternalMetricStatus {
|
||||
metric?: {
|
||||
name?: string;
|
||||
selector?: LabelSelector;
|
||||
};
|
||||
current?: {
|
||||
averageValue?: string;
|
||||
value?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface V2Beta1ExternalMetricStatus {
|
||||
currentAverageValue?: string;
|
||||
currentValue?: string;
|
||||
metricName?: string;
|
||||
metricSelector?: LabelSelector;
|
||||
}
|
||||
|
||||
export type ExternalMetricStatus =
|
||||
| V2Beta1ExternalMetricStatus
|
||||
| V2ExternalMetricStatus;
|
||||
|
||||
export interface V2ObjectMetricStatus {
|
||||
metric?: {
|
||||
name?: string;
|
||||
selector?: LabelSelector;
|
||||
};
|
||||
current?: {
|
||||
type?: string;
|
||||
value?: string;
|
||||
averageValue?: string;
|
||||
};
|
||||
describedObject?: CrossVersionObjectReference;
|
||||
}
|
||||
|
||||
export interface V2Beta1ObjectMetricStatus {
|
||||
averageValue?: string;
|
||||
currentValue?: string;
|
||||
metricName?: string;
|
||||
selector?: LabelSelector;
|
||||
describedObject?: CrossVersionObjectReference;
|
||||
}
|
||||
|
||||
export type ObjectMetricStatus =
|
||||
| V2Beta1ObjectMetricStatus
|
||||
| V2ObjectMetricStatus;
|
||||
|
||||
export interface V2PodsMetricStatus {
|
||||
selector?: LabelSelector;
|
||||
metric?: {
|
||||
name?: string;
|
||||
selector?: LabelSelector;
|
||||
};
|
||||
current?: {
|
||||
averageValue?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface V2Beta1PodsMetricStatus {
|
||||
currentAverageValue?: string;
|
||||
metricName?: string;
|
||||
selector?: LabelSelector;
|
||||
}
|
||||
|
||||
export type PodsMetricStatus =
|
||||
| V2Beta1PodsMetricStatus
|
||||
| V2PodsMetricStatus;
|
||||
|
||||
export interface V2ResourceMetricStatus {
|
||||
name: string;
|
||||
current?: {
|
||||
averageUtilization?: number;
|
||||
averageValue?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface V2Beta1ResourceMetricStatus {
|
||||
currentAverageUtilization?: number;
|
||||
currentAverageValue?: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export type ResourceMetricStatus =
|
||||
| V2Beta1ResourceMetricStatus
|
||||
| V2ResourceMetricStatus;
|
||||
|
||||
export interface BaseHorizontalPodAutoscalerMetricStatus {
|
||||
containerResource: ContainerResourceMetricStatus;
|
||||
external: ExternalMetricStatus;
|
||||
object: ObjectMetricStatus;
|
||||
pods: PodsMetricStatus;
|
||||
resource: ResourceMetricStatus;
|
||||
}
|
||||
|
||||
export type HorizontalPodAutoscalerMetricStatus =
|
||||
| OptionVariant<HpaMetricType.Resource, BaseHorizontalPodAutoscalerMetricStatus, "resource">
|
||||
| OptionVariant<HpaMetricType.External, BaseHorizontalPodAutoscalerMetricStatus, "external">
|
||||
| OptionVariant<HpaMetricType.Object, BaseHorizontalPodAutoscalerMetricStatus, "object">
|
||||
| OptionVariant<HpaMetricType.Pods, BaseHorizontalPodAutoscalerMetricStatus, "pods">
|
||||
| OptionVariant<HpaMetricType.ContainerResource, BaseHorizontalPodAutoscalerMetricStatus, "containerResource">;
|
||||
|
||||
export interface HorizontalPodAutoscalerSpec {
|
||||
scaleTargetRef: CrossVersionObjectReference;
|
||||
minReplicas?: number;
|
||||
maxReplicas: number;
|
||||
metrics?: HorizontalPodAutoscalerMetricSpec[];
|
||||
behavior?: HorizontalPodAutoscalerBehavior;
|
||||
targetCPUUtilizationPercentage?: number; // used only in autoscaling/v1
|
||||
}
|
||||
|
||||
export interface HorizontalPodAutoscalerStatus {
|
||||
conditions?: BaseKubeObjectCondition[];
|
||||
currentReplicas: number;
|
||||
desiredReplicas: number;
|
||||
currentMetrics?: HorizontalPodAutoscalerMetricStatus[];
|
||||
currentCPUUtilizationPercentage?: number; // used only in autoscaling/v1
|
||||
}
|
||||
|
||||
export class HorizontalPodAutoscaler extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
HorizontalPodAutoscalerStatus,
|
||||
HorizontalPodAutoscalerSpec
|
||||
> {
|
||||
static readonly kind = "HorizontalPodAutoscaler";
|
||||
static readonly namespaced = true;
|
||||
static readonly apiBase = "/apis/autoscaling/v2/horizontalpodautoscalers";
|
||||
|
||||
getMaxPods() {
|
||||
return this.spec.maxReplicas ?? 0;
|
||||
}
|
||||
|
||||
getMinPods() {
|
||||
return this.spec.minReplicas ?? 0;
|
||||
}
|
||||
|
||||
getReplicas() {
|
||||
return this.status?.currentReplicas ?? 0;
|
||||
}
|
||||
|
||||
getReadyConditions() {
|
||||
return this.getConditions().filter(({ isReady }) => isReady);
|
||||
}
|
||||
|
||||
getConditions() {
|
||||
return this.status?.conditions?.map(condition => {
|
||||
const { message, reason, lastTransitionTime, status } = condition;
|
||||
|
||||
return {
|
||||
...condition,
|
||||
isReady: status === "True",
|
||||
tooltip: `${message || reason} (${lastTransitionTime})`,
|
||||
};
|
||||
}) ?? [];
|
||||
}
|
||||
|
||||
getMetrics() {
|
||||
return this.spec.metrics ?? [];
|
||||
}
|
||||
|
||||
getCurrentMetrics() {
|
||||
return this.status?.currentMetrics ?? [];
|
||||
}
|
||||
}
|
||||
import { HorizontalPodAutoscaler } from "@k8slens/kube-object";
|
||||
|
||||
export class HorizontalPodAutoscalerApi extends KubeApi<HorizontalPodAutoscaler> {
|
||||
constructor(deps: KubeApiDependencies, opts?: DerivedKubeApiOptions) {
|
||||
|
||||
@@ -46,5 +46,4 @@ export * from "./service.api";
|
||||
export * from "./service-account.api";
|
||||
export * from "./stateful-set.api";
|
||||
export * from "./storage-class.api";
|
||||
export * from "./types";
|
||||
export * from "./vertical-pod-autoscaler.api";
|
||||
@@ -3,8 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { KubeObjectMetadata, KubeObjectScope } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { IngressClass } from "@k8slens/kube-object";
|
||||
import type { KubeApiDependencies, ResourceDescriptor } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
|
||||
@@ -18,84 +17,12 @@ export class IngressClassApi extends KubeApi<IngressClass> {
|
||||
}
|
||||
|
||||
setAsDefault({ name }: ResourceDescriptor, isDefault = true) {
|
||||
const reqUrl = this.formatUrlForNotListing({ name });
|
||||
|
||||
return this.request.patch(reqUrl, {
|
||||
data: {
|
||||
metadata: {
|
||||
annotations: {
|
||||
[IngressClass.ANNOTATION_IS_DEFAULT]: JSON.stringify(isDefault),
|
||||
},
|
||||
return this.patch({ name }, {
|
||||
metadata: {
|
||||
annotations: {
|
||||
[IngressClass.ANNOTATION_IS_DEFAULT]: String(isDefault),
|
||||
},
|
||||
},
|
||||
}, {
|
||||
headers: {
|
||||
"content-type": "application/strategic-merge-patch+json",
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// API docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#ingressclass-v1-networking-k8s-io
|
||||
export type IngressClassMetadata = KubeObjectMetadata<KubeObjectScope.Cluster> & {
|
||||
"name": string;
|
||||
"labels"?: {
|
||||
[name: string]: string | undefined;
|
||||
"app.kubernetes.io/component"?: "controller";
|
||||
};
|
||||
"annotations"?: {
|
||||
[name: string]: string | undefined;
|
||||
"ingressclass.kubernetes.io/is-default-class"?: "true";
|
||||
};
|
||||
};
|
||||
|
||||
export interface IngressClassParametersReference {
|
||||
"apiGroup": string; // k8s.example.net
|
||||
"scope": "Namespace" | "Cluster";
|
||||
"kind": "ClusterIngressParameter" | "IngressParameter";
|
||||
"name": string; // external-config-1
|
||||
"namespace"?: string; // namespaced for IngressClass must be defined in `spec.parameters.namespace` instead of `metadata.namespace` (!)
|
||||
}
|
||||
|
||||
export interface IngressClassSpec {
|
||||
controller: string; // "example.com/ingress-controller"
|
||||
parameters?: IngressClassParametersReference;
|
||||
}
|
||||
|
||||
export interface IngressClassStatus {
|
||||
}
|
||||
|
||||
export class IngressClass extends KubeObject<IngressClassMetadata, IngressClassStatus, IngressClassSpec> {
|
||||
static readonly kind = "IngressClass";
|
||||
static readonly namespaced = false;
|
||||
static readonly apiBase = "/apis/networking.k8s.io/v1/ingressclasses";
|
||||
static readonly ANNOTATION_IS_DEFAULT = "ingressclass.kubernetes.io/is-default-class";
|
||||
|
||||
getController(): string {
|
||||
return this.spec.controller;
|
||||
}
|
||||
|
||||
getCtrlApiGroup() {
|
||||
return this.spec?.parameters?.apiGroup;
|
||||
}
|
||||
|
||||
getCtrlScope() {
|
||||
return this.spec?.parameters?.scope;
|
||||
}
|
||||
|
||||
getCtrlNs() {
|
||||
return this.spec?.parameters?.namespace;
|
||||
}
|
||||
|
||||
getCtrlKind() {
|
||||
return this.spec?.parameters?.kind;
|
||||
}
|
||||
|
||||
getCtrlName() {
|
||||
return this.spec?.parameters?.name as string;
|
||||
}
|
||||
|
||||
get isDefault() {
|
||||
return this.metadata.annotations?.[IngressClass.ANNOTATION_IS_DEFAULT] === "true";
|
||||
}, "strategic");
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,9 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { NamespaceScopedMetadata, TypedLocalObjectReference } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { hasTypedProperty, isString, iter } from "@k8slens/utilities";
|
||||
import { Ingress } from "@k8slens/kube-object";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { RequireExactlyOne } from "type-fest";
|
||||
|
||||
export class IngressApi extends KubeApi<Ingress> {
|
||||
constructor(deps: KubeApiDependencies, opts?: DerivedKubeApiOptions) {
|
||||
@@ -21,193 +18,3 @@ export class IngressApi extends KubeApi<Ingress> {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export interface ILoadBalancerIngress {
|
||||
hostname?: string;
|
||||
ip?: string;
|
||||
}
|
||||
|
||||
// extensions/v1beta1
|
||||
export interface ExtensionsBackend {
|
||||
serviceName?: string;
|
||||
servicePort?: number | string;
|
||||
}
|
||||
|
||||
// networking.k8s.io/v1
|
||||
export interface NetworkingBackend {
|
||||
service?: IngressService;
|
||||
}
|
||||
|
||||
export type IngressBackend = (ExtensionsBackend | NetworkingBackend) & {
|
||||
resource?: TypedLocalObjectReference;
|
||||
};
|
||||
|
||||
export interface IngressService {
|
||||
name: string;
|
||||
port: RequireExactlyOne<{
|
||||
name: string;
|
||||
number: number;
|
||||
}>;
|
||||
}
|
||||
|
||||
function isExtensionsBackend(backend: IngressBackend): backend is ExtensionsBackend {
|
||||
return hasTypedProperty(backend, "serviceName", isString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format an ingress backend into the name of the service and port
|
||||
* @param backend The ingress target
|
||||
*/
|
||||
export function getBackendServiceNamePort(backend: IngressBackend | undefined): string {
|
||||
if (!backend) {
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
if (isExtensionsBackend(backend)) {
|
||||
return `${backend.serviceName}:${backend.servicePort}`;
|
||||
}
|
||||
|
||||
if (backend.service) {
|
||||
const { name, port } = backend.service;
|
||||
|
||||
return `${name}:${port.number ?? port.name}`;
|
||||
}
|
||||
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
export interface HTTPIngressPath {
|
||||
pathType: "Exact" | "Prefix" | "ImplementationSpecific";
|
||||
path?: string;
|
||||
backend?: IngressBackend;
|
||||
}
|
||||
|
||||
export interface HTTPIngressRuleValue {
|
||||
paths: HTTPIngressPath[];
|
||||
}
|
||||
|
||||
export interface IngressRule {
|
||||
host?: string;
|
||||
http?: HTTPIngressRuleValue;
|
||||
}
|
||||
|
||||
export interface IngressSpec {
|
||||
tls: {
|
||||
secretName: string;
|
||||
}[];
|
||||
rules?: IngressRule[];
|
||||
// extensions/v1beta1
|
||||
backend?: ExtensionsBackend;
|
||||
/**
|
||||
* The default backend which is exactly on of:
|
||||
* - service
|
||||
* - resource
|
||||
*/
|
||||
defaultBackend?: RequireExactlyOne<NetworkingBackend & {
|
||||
resource: {
|
||||
apiGroup: string;
|
||||
kind: string;
|
||||
name: string;
|
||||
};
|
||||
}>;
|
||||
}
|
||||
|
||||
export interface IngressStatus {
|
||||
loadBalancer: {
|
||||
ingress?: ILoadBalancerIngress[];
|
||||
};
|
||||
}
|
||||
|
||||
export class Ingress extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
IngressStatus,
|
||||
IngressSpec
|
||||
> {
|
||||
static readonly kind = "Ingress";
|
||||
static readonly namespaced = true;
|
||||
static readonly apiBase = "/apis/networking.k8s.io/v1/ingresses";
|
||||
|
||||
getRules() {
|
||||
return this.spec.rules ?? [];
|
||||
}
|
||||
|
||||
getRoutes(): string[] {
|
||||
return computeRouteDeclarations(this).map(({ url, service }) => `${url} ⇢ ${service}`);
|
||||
}
|
||||
|
||||
getServiceNamePort(): ExtensionsBackend | undefined {
|
||||
const { spec: { backend, defaultBackend } = {}} = this;
|
||||
|
||||
const serviceName = defaultBackend?.service?.name ?? backend?.serviceName;
|
||||
const servicePort = defaultBackend?.service?.port.number ?? defaultBackend?.service?.port.name ?? backend?.servicePort;
|
||||
|
||||
if (!serviceName || !servicePort) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
serviceName,
|
||||
servicePort,
|
||||
};
|
||||
}
|
||||
|
||||
getHosts() {
|
||||
const { spec: { rules = [] }} = this;
|
||||
|
||||
return [...iter.filterMap(rules, rule => rule.host)];
|
||||
}
|
||||
|
||||
getPorts() {
|
||||
const ports: number[] = [];
|
||||
const { spec: { tls, rules = [], backend, defaultBackend }} = this;
|
||||
const httpPort = 80;
|
||||
const tlsPort = 443;
|
||||
// Note: not using the port name (string)
|
||||
const servicePort = defaultBackend?.service?.port.number ?? backend?.servicePort;
|
||||
|
||||
if (rules.length > 0) {
|
||||
if (rules.some(rule => rule.http)) {
|
||||
ports.push(httpPort);
|
||||
}
|
||||
} else if (servicePort !== undefined) {
|
||||
ports.push(Number(servicePort));
|
||||
}
|
||||
|
||||
if (tls && tls.length > 0) {
|
||||
ports.push(tlsPort);
|
||||
}
|
||||
|
||||
return ports.join(", ");
|
||||
}
|
||||
|
||||
getLoadBalancers() {
|
||||
return this.status?.loadBalancer?.ingress?.map(address => (
|
||||
address.hostname || address.ip
|
||||
)) ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
export interface ComputedIngressRoute {
|
||||
displayAsLink: boolean;
|
||||
pathname: string;
|
||||
url: string;
|
||||
service: string;
|
||||
}
|
||||
|
||||
export function computeRuleDeclarations(ingress: Ingress, rule: IngressRule): ComputedIngressRoute[] {
|
||||
const { host = "*", http: { paths } = { paths: [] }} = rule;
|
||||
const protocol = (ingress.spec?.tls?.length ?? 0) === 0
|
||||
? "http"
|
||||
: "https";
|
||||
|
||||
return paths.map(({ path = "/", backend }) => ({
|
||||
displayAsLink: !host.includes("*"),
|
||||
pathname: path,
|
||||
url: `${protocol}://${host}${path}`,
|
||||
service: getBackendServiceNamePort(backend),
|
||||
}));
|
||||
}
|
||||
|
||||
export function computeRouteDeclarations(ingress: Ingress): ComputedIngressRoute[] {
|
||||
return ingress.getRules().flatMap(rule => computeRuleDeclarations(ingress, rule));
|
||||
}
|
||||
@@ -5,94 +5,7 @@
|
||||
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { PodSpec } from "./pod.api";
|
||||
import type { Container } from "./types/container";
|
||||
import type { KubeObjectStatus, LabelSelector, NamespaceScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
|
||||
export interface JobSpec {
|
||||
parallelism?: number;
|
||||
completions?: number;
|
||||
backoffLimit?: number;
|
||||
selector?: LabelSelector;
|
||||
template: {
|
||||
metadata: {
|
||||
creationTimestamp?: string;
|
||||
labels?: Partial<Record<string, string>>;
|
||||
annotations?: Partial<Record<string, string>>;
|
||||
};
|
||||
spec: PodSpec;
|
||||
};
|
||||
containers?: Container[];
|
||||
restartPolicy?: string;
|
||||
terminationGracePeriodSeconds?: number;
|
||||
dnsPolicy?: string;
|
||||
serviceAccountName?: string;
|
||||
serviceAccount?: string;
|
||||
schedulerName?: string;
|
||||
}
|
||||
|
||||
export interface JobStatus extends KubeObjectStatus {
|
||||
startTime: string;
|
||||
completionTime: string;
|
||||
succeeded: number;
|
||||
}
|
||||
|
||||
export class Job extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
JobStatus,
|
||||
JobSpec
|
||||
> {
|
||||
static readonly kind = "Job";
|
||||
static readonly namespaced = true;
|
||||
static readonly apiBase = "/apis/batch/v1/jobs";
|
||||
|
||||
getSelectors(): string[] {
|
||||
return KubeObject.stringifyLabels(this.spec.selector?.matchLabels);
|
||||
}
|
||||
|
||||
getNodeSelectors(): string[] {
|
||||
return KubeObject.stringifyLabels(this.spec.template.spec.nodeSelector);
|
||||
}
|
||||
|
||||
getTemplateLabels(): string[] {
|
||||
return KubeObject.stringifyLabels(this.spec.template.metadata.labels);
|
||||
}
|
||||
|
||||
getTolerations() {
|
||||
return this.spec.template.spec.tolerations ?? [];
|
||||
}
|
||||
|
||||
getAffinity() {
|
||||
return this.spec.template.spec.affinity;
|
||||
}
|
||||
|
||||
getAffinityNumber() {
|
||||
return Object.keys(this.getAffinity() ?? {}).length;
|
||||
}
|
||||
|
||||
getDesiredCompletions() {
|
||||
return this.spec.completions ?? 0;
|
||||
}
|
||||
|
||||
getCompletions() {
|
||||
return this.status?.succeeded ?? 0;
|
||||
}
|
||||
|
||||
getParallelism() {
|
||||
return this.spec.parallelism;
|
||||
}
|
||||
|
||||
getCondition() {
|
||||
// Type of Job condition could be only Complete or Failed
|
||||
// https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.21/#jobcondition-v1-batch
|
||||
return this.status?.conditions?.find(({ status }) => status === "True");
|
||||
}
|
||||
|
||||
getImages() {
|
||||
return this.spec.template.spec.containers?.map(container => container.image) ?? [];
|
||||
}
|
||||
}
|
||||
import { Job } from "@k8slens/kube-object";
|
||||
|
||||
export class JobApi extends KubeApi<Job> {
|
||||
constructor(deps: KubeApiDependencies, opts?: DerivedKubeApiOptions) {
|
||||
|
||||
@@ -5,46 +5,7 @@
|
||||
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { NamespaceScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
|
||||
export interface LeaseSpec {
|
||||
acquireTime?: string;
|
||||
holderIdentity: string;
|
||||
leaseDurationSeconds: number;
|
||||
leaseTransitions?: number;
|
||||
renewTime: string;
|
||||
}
|
||||
|
||||
export class Lease extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
void,
|
||||
LeaseSpec
|
||||
> {
|
||||
static readonly kind = "Lease";
|
||||
static readonly namespaced = true;
|
||||
static readonly apiBase = "/apis/coordination.k8s.io/v1/leases";
|
||||
|
||||
getAcquireTime(): string {
|
||||
return this.spec.acquireTime || "";
|
||||
}
|
||||
|
||||
getHolderIdentity(): string {
|
||||
return this.spec.holderIdentity;
|
||||
}
|
||||
|
||||
getLeaseDurationSeconds(): number {
|
||||
return this.spec.leaseDurationSeconds;
|
||||
}
|
||||
|
||||
getLeaseTransitions(): number | undefined {
|
||||
return this.spec.leaseTransitions;
|
||||
}
|
||||
|
||||
getRenewTime(): string {
|
||||
return this.spec.renewTime;
|
||||
}
|
||||
}
|
||||
import { Lease } from "@k8slens/kube-object";
|
||||
|
||||
export class LeaseApi extends KubeApi<Lease> {
|
||||
constructor(deps: KubeApiDependencies, opts?: DerivedKubeApiOptions) {
|
||||
|
||||
@@ -3,63 +3,10 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { NamespaceScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { LimitRange } from "@k8slens/kube-object";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
|
||||
export enum LimitType {
|
||||
CONTAINER = "Container",
|
||||
POD = "Pod",
|
||||
PVC = "PersistentVolumeClaim",
|
||||
}
|
||||
|
||||
export enum Resource {
|
||||
MEMORY = "memory",
|
||||
CPU = "cpu",
|
||||
STORAGE = "storage",
|
||||
EPHEMERAL_STORAGE = "ephemeral-storage",
|
||||
}
|
||||
|
||||
export enum LimitPart {
|
||||
MAX = "max",
|
||||
MIN = "min",
|
||||
DEFAULT = "default",
|
||||
DEFAULT_REQUEST = "defaultRequest",
|
||||
MAX_LIMIT_REQUEST_RATIO = "maxLimitRequestRatio",
|
||||
}
|
||||
|
||||
type LimitRangeParts = Partial<Record<LimitPart, Record<string, string>>>;
|
||||
|
||||
export interface LimitRangeItem extends LimitRangeParts {
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface LimitRangeSpec {
|
||||
limits: LimitRangeItem[];
|
||||
}
|
||||
|
||||
export class LimitRange extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
void,
|
||||
LimitRangeSpec
|
||||
> {
|
||||
static readonly kind = "LimitRange";
|
||||
static readonly namespaced = true;
|
||||
static readonly apiBase = "/api/v1/limitranges";
|
||||
|
||||
getContainerLimits() {
|
||||
return this.spec.limits.filter(limit => limit.type === LimitType.CONTAINER);
|
||||
}
|
||||
|
||||
getPodLimits() {
|
||||
return this.spec.limits.filter(limit => limit.type === LimitType.POD);
|
||||
}
|
||||
|
||||
getPVCLimits() {
|
||||
return this.spec.limits.filter(limit => limit.type === LimitType.PVC);
|
||||
}
|
||||
}
|
||||
|
||||
export class LimitRangeApi extends KubeApi<LimitRange> {
|
||||
constructor(deps: KubeApiDependencies, opts?: DerivedKubeApiOptions) {
|
||||
|
||||
@@ -7,7 +7,6 @@ import { getSecondsFromUnixEpoch } from "../../../utils/date/get-current-date-ti
|
||||
import apiBaseInjectable from "../../api-base.injectable";
|
||||
import type { MetricData } from "../metrics.api";
|
||||
|
||||
|
||||
export interface RequestMetricsParams {
|
||||
/**
|
||||
* timestamp in seconds or valid date-string
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { MetricData } from "../metrics.api";
|
||||
import type { PersistentVolumeClaim } from "../persistent-volume-claim.api";
|
||||
import type { PersistentVolumeClaim } from "@k8slens/kube-object";
|
||||
import requestMetricsInjectable from "./request-metrics.injectable";
|
||||
|
||||
export interface PersistentVolumeClaimMetricData {
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { DaemonSet } from "../daemon-set.api";
|
||||
import type { DaemonSet } from "@k8slens/kube-object";
|
||||
import type { MetricData } from "../metrics.api";
|
||||
import requestMetricsInjectable from "./request-metrics.injectable";
|
||||
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { Deployment } from "../deployment.api";
|
||||
import type { Deployment } from "@k8slens/kube-object";
|
||||
import type { MetricData } from "../metrics.api";
|
||||
import requestMetricsInjectable from "./request-metrics.injectable";
|
||||
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { Job } from "../job.api";
|
||||
import type { Job } from "@k8slens/kube-object";
|
||||
import type { MetricData } from "../metrics.api";
|
||||
import requestMetricsInjectable from "./request-metrics.injectable";
|
||||
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { MetricData } from "../metrics.api";
|
||||
import type { ReplicaSet } from "../replica-set.api";
|
||||
import type { ReplicaSet } from "@k8slens/kube-object";
|
||||
import requestMetricsInjectable from "./request-metrics.injectable";
|
||||
|
||||
export interface ReplicaSetPodMetricData {
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { MetricData } from "../metrics.api";
|
||||
import type { StatefulSet } from "../stateful-set.api";
|
||||
import type { StatefulSet } from "@k8slens/kube-object";
|
||||
import requestMetricsInjectable from "./request-metrics.injectable";
|
||||
|
||||
export interface StatefulSetPodMetricData {
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { MetricData } from "../metrics.api";
|
||||
import type { Pod } from "../pod.api";
|
||||
import type { Pod } from "@k8slens/kube-object";
|
||||
import requestMetricsInjectable from "./request-metrics.injectable";
|
||||
|
||||
export interface PodMetricData {
|
||||
|
||||
@@ -2,151 +2,9 @@
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { LabelSelector, NamespaceScopedMetadata, KubeObjectMetadata, KubeObjectScope } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { MutatingWebhookConfiguration } from "@k8slens/kube-object";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
|
||||
interface WebhookClientConfig {
|
||||
// `url` gives the location of the webhook
|
||||
url?: string;
|
||||
|
||||
// `service` is a reference to the service for this webhook. Either `service` or `url` must be specified.
|
||||
service?: ServiceReference;
|
||||
|
||||
// `caBundle` is a PEM encoded CA bundle which will be used to validate the webhook's server certificate.
|
||||
// If unspecified, system trust roots on the apiserver are used.
|
||||
caBundle?: string;
|
||||
}
|
||||
|
||||
interface RuleWithOperations {
|
||||
// APIGroups is the API groups the resources belong to. '*' is all groups. If '*' is present, the length of the slice must be one.
|
||||
apiGroups: string[];
|
||||
|
||||
// APIVersions is the API versions the resources belong to. '*' is all versions.
|
||||
apiVersions?: string[];
|
||||
|
||||
// Resources is a list of resources this rule applies to.
|
||||
// For example: 'pods' means pods.
|
||||
// '*' means all resources, but not subresources.
|
||||
// 'pods/' means all subresources of pods.
|
||||
// '*/scale' means all scale subresources. Allowed values are "Resource" / "Resource/Scale" / "Resource/Status".
|
||||
resources: string[];
|
||||
|
||||
// Operations is a list of operations this rule applies to.
|
||||
// The valid values are: "CREATE" / "UPDATE" / "DELETE" / "CONNECT".
|
||||
operations: string[];
|
||||
|
||||
// Scope specifies the scope of this rule. Valid values are "Cluster" / "Namespace".
|
||||
// Default is "Cluster".
|
||||
scope?: string;
|
||||
}
|
||||
|
||||
export interface Webhook {
|
||||
// The name of the webhook configuration.
|
||||
name: string;
|
||||
|
||||
// ClientConfig defines how to communicate with the hook.
|
||||
clientConfig: WebhookClientConfig;
|
||||
|
||||
// Rules describes what operations on what resources/subresources the webhook cares about.
|
||||
// The webhook cares about an operation if it matches _any_ Rule.
|
||||
rules?: RuleWithOperations[];
|
||||
|
||||
// AdmissionReviewVersions is an ordered list of preferred `AdmissionReview` versions
|
||||
// the webhook expects. API server will try to use first version in the list which it
|
||||
// supports. If none of the versions specified in this list supported by API server,
|
||||
// validation will fail for this object.
|
||||
admissionReviewVersions?: string[];
|
||||
|
||||
// TimeoutSeconds specifies the timeout for this webhook. After the timeout passes, the webhook call will be ignored
|
||||
// or the API call will fail depending on the failure policy.
|
||||
timeoutSeconds?: number;
|
||||
|
||||
// FailurePolicy specifies how unrecognized errors from the webhook are handled - allowed values are Ignore or Fail.
|
||||
// Defaults to Fail.
|
||||
failurePolicy?: string;
|
||||
|
||||
// matchPolicy defines how the "rules" list is used to match incoming requests. Allowed values are "Exact" or "Equivalent".
|
||||
// - Exact: match a request only if it exactly matches a specified rule.
|
||||
// - Equivalent: match a request if modifies a resource listed in rules, even via another API group or version.
|
||||
// Defaults to "Equivalent".
|
||||
matchPolicy?: string;
|
||||
|
||||
// NamespaceSelector decides whether to run the webhook on an object based on whether the namespace for that object
|
||||
// matches the selector. If the object itself is a namespace, the matching is performed on object.metadata.labels.
|
||||
// If both the object and the webhook configuration specify namespaceSelector, they must match.
|
||||
namespaceSelector?: LabelSelector;
|
||||
|
||||
// ObjectSelector decides whether to run the webhook based on if the object has matching labels.
|
||||
// objectSelector and namespaceSelector are ANDed. An empty objectSelector matches all objects.
|
||||
// A null objectSelector matches no objects.
|
||||
objectSelector?: LabelSelector;
|
||||
|
||||
// SideEffects states whether this webhookk should run when no mutating or validating webhook
|
||||
// needs to run. This should be false when the webhook only applies to resources that have
|
||||
// the sideEffects field set to None. Defaults to true.
|
||||
sideEffects?: string;
|
||||
|
||||
// reinvocationPolicy indicates whether this webhook should be called multiple times as part of a
|
||||
// single admission evaluation. Allowed values are "Never" and "IfNeeded"
|
||||
reinvocationPolicy?: "Never" | "IfNeeded";
|
||||
}
|
||||
|
||||
export interface MutatingWebhook extends Webhook {
|
||||
}
|
||||
|
||||
interface ServiceReference {
|
||||
// `namespace` is the namespace of the service.
|
||||
namespace: string;
|
||||
|
||||
// `name` is the name of the service.
|
||||
name: string;
|
||||
|
||||
// `path` is an optional URL path which will be sent in any request to this service.
|
||||
path?: string;
|
||||
|
||||
// `port` is an optional service port which will be used when accessing the service.
|
||||
port?: number | string;
|
||||
}
|
||||
|
||||
interface MutatingWebhookConfigurationData extends KubeJsonApiData<KubeObjectMetadata<KubeObjectScope.Namespace>, void, void> {
|
||||
webhooks?: MutatingWebhook[];
|
||||
}
|
||||
|
||||
export class MutatingWebhookConfiguration extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
void,
|
||||
void
|
||||
> {
|
||||
static kind = "MutatingWebhookConfiguration";
|
||||
static namespaced = false;
|
||||
static apiBase = "/apis/admissionregistration.k8s.io/v1/mutatingwebhookconfigurations";
|
||||
|
||||
webhooks?: MutatingWebhook[];
|
||||
|
||||
constructor({ webhooks, ...rest }: MutatingWebhookConfigurationData) {
|
||||
super(rest);
|
||||
this.webhooks = webhooks;
|
||||
}
|
||||
|
||||
getWebhooks(): MutatingWebhook[] {
|
||||
return this.webhooks ?? [];
|
||||
}
|
||||
|
||||
getClientConfig(serviceName: string, serviceNamespace: string): WebhookClientConfig | undefined {
|
||||
const webhooks = this.getWebhooks();
|
||||
|
||||
for (const webhook of webhooks) {
|
||||
if (webhook.clientConfig.service?.name === serviceName && webhook.clientConfig.service?.namespace === serviceNamespace) {
|
||||
return webhook.clientConfig;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export class MutatingWebhookConfigurationApi extends KubeApi<MutatingWebhookConfiguration> {
|
||||
constructor(deps: KubeApiDependencies, opts?: DerivedKubeApiOptions) {
|
||||
|
||||
@@ -5,47 +5,7 @@
|
||||
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { ClusterScopedMetadata, KubeObjectStatus } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
|
||||
export enum NamespaceStatusKind {
|
||||
ACTIVE = "Active",
|
||||
TERMINATING = "Terminating",
|
||||
}
|
||||
|
||||
export interface NamespaceSpec {
|
||||
finalizers?: string[];
|
||||
}
|
||||
|
||||
export interface NamespaceStatus extends KubeObjectStatus {
|
||||
phase?: string;
|
||||
}
|
||||
|
||||
export class Namespace extends KubeObject<
|
||||
ClusterScopedMetadata,
|
||||
NamespaceStatus,
|
||||
NamespaceSpec
|
||||
> {
|
||||
static readonly kind = "Namespace";
|
||||
static readonly namespaced = false;
|
||||
static readonly apiBase = "/api/v1/namespaces";
|
||||
|
||||
getStatus() {
|
||||
return this.status?.phase ?? "-";
|
||||
}
|
||||
|
||||
isSubnamespace() {
|
||||
return this.getAnnotations().find(annotation => annotation.includes("hnc.x-k8s.io/subnamespace-of"));
|
||||
}
|
||||
|
||||
isChildOf(parentName: string) {
|
||||
return this.getLabels().find(label => label === `${parentName}.tree.hnc.x-k8s.io/depth=1`);
|
||||
}
|
||||
|
||||
isControlledByHNC() {
|
||||
return this.getLabels().includes("hnc.x-k8s.io/included-namespace=true");
|
||||
}
|
||||
}
|
||||
import { Namespace } from "@k8slens/kube-object";
|
||||
|
||||
export class NamespaceApi extends KubeApi<Namespace> {
|
||||
constructor(deps: KubeApiDependencies, opts?: DerivedKubeApiOptions) {
|
||||
|
||||
@@ -3,126 +3,10 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { LabelSelector, NamespaceScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { NetworkPolicy } from "@k8slens/kube-object";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
|
||||
export interface IPolicyIpBlock {
|
||||
cidr: string;
|
||||
except?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `LabelSelector` instead
|
||||
*/
|
||||
export type IPolicySelector = LabelSelector;
|
||||
|
||||
export interface NetworkPolicyPort {
|
||||
/**
|
||||
* The protocol which network traffic must match.
|
||||
*
|
||||
* One of:
|
||||
* - `"TCP"`
|
||||
* - `"UDP"`
|
||||
* - `"SCTP"`
|
||||
*
|
||||
* @default "TCP"
|
||||
*/
|
||||
protocol?: string;
|
||||
|
||||
/**
|
||||
* The port on the given protocol. This can either be a numerical or named
|
||||
* port on a pod. If this field is not provided, this matches all port names and
|
||||
* numbers.
|
||||
*
|
||||
* If present, only traffic on the specified protocol AND port will be matched.
|
||||
*/
|
||||
port?: number | string;
|
||||
|
||||
/**
|
||||
* If set, indicates that the range of ports from port to endPort, inclusive,
|
||||
* should be allowed by the policy. This field cannot be defined if the port field
|
||||
* is not defined or if the port field is defined as a named (string) port.
|
||||
*
|
||||
* The endPort must be equal or greater than port.
|
||||
*/
|
||||
endPort?: number;
|
||||
}
|
||||
|
||||
export interface NetworkPolicyPeer {
|
||||
/**
|
||||
* IPBlock defines policy on a particular IPBlock. If this field is set then
|
||||
* neither of the other fields can be.
|
||||
*/
|
||||
ipBlock?: IPolicyIpBlock;
|
||||
|
||||
/**
|
||||
* Selects Namespaces using cluster-scoped labels. This field follows standard label
|
||||
* selector semantics; if present but empty, it selects all namespaces.
|
||||
*
|
||||
* If PodSelector is also set, then the NetworkPolicyPeer as a whole selects
|
||||
* the Pods matching PodSelector in the Namespaces selected by NamespaceSelector.
|
||||
*
|
||||
* Otherwise it selects all Pods in the Namespaces selected by NamespaceSelector.
|
||||
*/
|
||||
namespaceSelector?: LabelSelector;
|
||||
|
||||
/**
|
||||
* This is a label selector which selects Pods. This field follows standard label
|
||||
* selector semantics; if present but empty, it selects all pods.
|
||||
*
|
||||
* If NamespaceSelector is also set, then the NetworkPolicyPeer as a whole selects
|
||||
* the Pods matching PodSelector in the Namespaces selected by NamespaceSelector.
|
||||
*
|
||||
* Otherwise it selects the Pods matching PodSelector in the policy's own Namespace.
|
||||
*/
|
||||
podSelector?: LabelSelector;
|
||||
}
|
||||
|
||||
export interface IPolicyIngress {
|
||||
from?: NetworkPolicyPeer[];
|
||||
ports?: NetworkPolicyPort[];
|
||||
}
|
||||
|
||||
export interface IPolicyEgress {
|
||||
to?: NetworkPolicyPeer[];
|
||||
ports?: NetworkPolicyPort[];
|
||||
}
|
||||
|
||||
export type PolicyType = "Ingress" | "Egress";
|
||||
|
||||
export interface NetworkPolicySpec {
|
||||
podSelector: LabelSelector;
|
||||
policyTypes?: PolicyType[];
|
||||
ingress?: IPolicyIngress[];
|
||||
egress?: IPolicyEgress[];
|
||||
}
|
||||
|
||||
export class NetworkPolicy extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
void,
|
||||
NetworkPolicySpec
|
||||
> {
|
||||
static readonly kind = "NetworkPolicy";
|
||||
static readonly namespaced = true;
|
||||
static readonly apiBase = "/apis/networking.k8s.io/v1/networkpolicies";
|
||||
|
||||
getMatchLabels(): string[] {
|
||||
if (!this.spec.podSelector || !this.spec.podSelector.matchLabels) return [];
|
||||
|
||||
return Object
|
||||
.entries(this.spec.podSelector.matchLabels)
|
||||
.map(data => data.join(":"));
|
||||
}
|
||||
|
||||
getTypes(): string[] {
|
||||
if (!this.spec.policyTypes) return [];
|
||||
|
||||
return this.spec.policyTypes;
|
||||
}
|
||||
}
|
||||
|
||||
export class NetworkPolicyApi extends KubeApi<NetworkPolicy> {
|
||||
constructor(deps: KubeApiDependencies, opts: DerivedKubeApiOptions = {}) {
|
||||
super(deps, {
|
||||
|
||||
@@ -3,12 +3,9 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { BaseKubeObjectCondition, ClusterScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { cpuUnitsToNumber, unitsToBytes, isObject } from "@k8slens/utilities";
|
||||
import { Node } from "@k8slens/kube-object";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { TypedRegEx } from "typed-regex";
|
||||
|
||||
export class NodeApi extends KubeApi<Node> {
|
||||
constructor(deps: KubeApiDependencies, opts?: DerivedKubeApiOptions) {
|
||||
@@ -18,246 +15,3 @@ export class NodeApi extends KubeApi<Node> {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export interface NodeTaint {
|
||||
key: string;
|
||||
value?: string;
|
||||
effect: string;
|
||||
timeAdded: string;
|
||||
}
|
||||
|
||||
export function formatNodeTaint(taint: NodeTaint): string {
|
||||
if (taint.value) {
|
||||
return `${taint.key}=${taint.value}:${taint.effect}`;
|
||||
}
|
||||
|
||||
return `${taint.key}:${taint.effect}`;
|
||||
}
|
||||
|
||||
export interface NodeCondition extends BaseKubeObjectCondition {
|
||||
/**
|
||||
* Last time we got an update on a given condition.
|
||||
*/
|
||||
lastHeartbeatTime?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* These role label prefixs are the ones that are for master nodes
|
||||
*
|
||||
* The `master` label has been deprecated in Kubernetes 1.20, and will be removed in 1.25 so we
|
||||
* have to also use the newer `control-plane` label
|
||||
*/
|
||||
const masterNodeLabels = [
|
||||
"master",
|
||||
"control-plane",
|
||||
];
|
||||
|
||||
/**
|
||||
* This regex is used in the `getRoleLabels()` method bellow, but placed here
|
||||
* as factoring out regexes is best practice.
|
||||
*/
|
||||
const nodeRoleLabelKeyMatcher = TypedRegEx("^.*node-role.kubernetes.io/+(?<role>.+)$");
|
||||
|
||||
export interface NodeSpec {
|
||||
podCIDR?: string;
|
||||
podCIDRs?: string[];
|
||||
providerID?: string;
|
||||
/**
|
||||
* @deprecated see https://issues.k8s.io/61966
|
||||
*/
|
||||
externalID?: string;
|
||||
taints?: NodeTaint[];
|
||||
unschedulable?: boolean;
|
||||
}
|
||||
|
||||
export interface NodeAddress {
|
||||
type: "Hostname" | "ExternalIP" | "InternalIP";
|
||||
address: string;
|
||||
}
|
||||
|
||||
export interface NodeStatusResources extends Partial<Record<string, string>> {
|
||||
cpu?: string;
|
||||
"ephemeral-storage"?: string;
|
||||
"hugepages-1Gi"?: string;
|
||||
"hugepages-2Mi"?: string;
|
||||
memory?: string;
|
||||
pods?: string;
|
||||
}
|
||||
|
||||
export interface ConfigMapNodeConfigSource {
|
||||
kubeletConfigKey: string;
|
||||
name: string;
|
||||
namespace: string;
|
||||
resourceVersion?: string;
|
||||
uid?: string;
|
||||
}
|
||||
|
||||
export interface NodeConfigSource {
|
||||
configMap?: ConfigMapNodeConfigSource;
|
||||
}
|
||||
|
||||
export interface NodeConfigStatus {
|
||||
active?: NodeConfigSource;
|
||||
assigned?: NodeConfigSource;
|
||||
lastKnownGood?: NodeConfigSource;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface DaemonEndpoint {
|
||||
Port: number; //it must be uppercase for backwards compatibility
|
||||
}
|
||||
|
||||
export interface NodeDaemonEndpoints {
|
||||
kubeletEndpoint?: DaemonEndpoint;
|
||||
}
|
||||
|
||||
export interface ContainerImage {
|
||||
names?: string[];
|
||||
sizeBytes?: number;
|
||||
}
|
||||
|
||||
export interface NodeSystemInfo {
|
||||
architecture: string;
|
||||
bootID: string;
|
||||
containerRuntimeVersion: string;
|
||||
kernelVersion: string;
|
||||
kubeProxyVersion: string;
|
||||
kubeletVersion: string;
|
||||
machineID: string;
|
||||
operatingSystem: string;
|
||||
osImage: string;
|
||||
systemUUID: string;
|
||||
}
|
||||
|
||||
export interface AttachedVolume {
|
||||
name: string;
|
||||
devicePath: string;
|
||||
}
|
||||
|
||||
export interface NodeStatus {
|
||||
capacity?: NodeStatusResources;
|
||||
allocatable?: NodeStatusResources;
|
||||
conditions?: NodeCondition[];
|
||||
addresses?: NodeAddress[];
|
||||
config?: NodeConfigStatus;
|
||||
daemonEndpoints?: NodeDaemonEndpoints;
|
||||
images?: ContainerImage[];
|
||||
nodeInfo?: NodeSystemInfo;
|
||||
phase?: string;
|
||||
volumesInUse?: string[];
|
||||
volumesAttached?: AttachedVolume[];
|
||||
}
|
||||
|
||||
export class Node extends KubeObject<
|
||||
ClusterScopedMetadata,
|
||||
NodeStatus,
|
||||
NodeSpec
|
||||
> {
|
||||
static readonly kind = "Node";
|
||||
static readonly namespaced = false;
|
||||
static readonly apiBase = "/api/v1/nodes";
|
||||
|
||||
/**
|
||||
* Returns the concatination of all current condition types which have a status
|
||||
* of `"True"`
|
||||
*/
|
||||
getNodeConditionText(): string {
|
||||
if (!this.status?.conditions) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return this.status.conditions
|
||||
.filter(condition => condition.status === "True")
|
||||
.map(condition => condition.type)
|
||||
.join(" ");
|
||||
}
|
||||
|
||||
getTaints() {
|
||||
return this.spec.taints || [];
|
||||
}
|
||||
|
||||
isMasterNode(): boolean {
|
||||
return this.getRoleLabelItems()
|
||||
.some(roleLabel => masterNodeLabels.includes(roleLabel));
|
||||
}
|
||||
|
||||
getRoleLabelItems(): string[] {
|
||||
const { labels } = this.metadata;
|
||||
const roleLabels: string[] = [];
|
||||
|
||||
if (!isObject(labels)) {
|
||||
return roleLabels;
|
||||
}
|
||||
|
||||
for (const labelKey of Object.keys(labels)) {
|
||||
const match = nodeRoleLabelKeyMatcher.match(labelKey);
|
||||
|
||||
if (match?.groups) {
|
||||
roleLabels.push(match.groups.role);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof labels["kubernetes.io/role"] === "string") {
|
||||
roleLabels.push(labels["kubernetes.io/role"]);
|
||||
}
|
||||
|
||||
if (typeof labels["node.kubernetes.io/role"] === "string") {
|
||||
roleLabels.push(labels["node.kubernetes.io/role"]);
|
||||
}
|
||||
|
||||
return roleLabels;
|
||||
}
|
||||
|
||||
getRoleLabels(): string {
|
||||
return this.getRoleLabelItems().join(", ");
|
||||
}
|
||||
|
||||
getCpuCapacity() {
|
||||
if (!this.status?.capacity || !this.status.capacity.cpu) return 0;
|
||||
|
||||
return cpuUnitsToNumber(this.status.capacity.cpu);
|
||||
}
|
||||
|
||||
getMemoryCapacity() {
|
||||
if (!this.status?.capacity || !this.status.capacity.memory) return 0;
|
||||
|
||||
return unitsToBytes(this.status.capacity.memory);
|
||||
}
|
||||
|
||||
getConditions(): NodeCondition[] {
|
||||
const conditions = this.status?.conditions || [];
|
||||
|
||||
if (this.isUnschedulable()) {
|
||||
return [{ type: "SchedulingDisabled", status: "True" }, ...conditions];
|
||||
}
|
||||
|
||||
return conditions;
|
||||
}
|
||||
|
||||
getActiveConditions() {
|
||||
return this.getConditions().filter(c => c.status === "True");
|
||||
}
|
||||
|
||||
getWarningConditions() {
|
||||
const goodConditions = ["Ready", "HostUpgrades", "SchedulingDisabled"];
|
||||
|
||||
return this.getActiveConditions().filter(condition => {
|
||||
return !goodConditions.includes(condition.type);
|
||||
});
|
||||
}
|
||||
|
||||
getKubeletVersion() {
|
||||
return this.status?.nodeInfo?.kubeletVersion ?? "<unknown>";
|
||||
}
|
||||
|
||||
getOperatingSystem(): string {
|
||||
return this.metadata?.labels?.["kubernetes.io/os"]
|
||||
|| this.metadata?.labels?.["beta.kubernetes.io/os"]
|
||||
|| this.status?.nodeInfo?.operatingSystem
|
||||
|| "linux";
|
||||
}
|
||||
|
||||
isUnschedulable() {
|
||||
return this.spec.unschedulable;
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,9 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { LabelSelector, NamespaceScopedMetadata, TypedLocalObjectReference } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { Pod } from "./pod.api";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { object } from "@k8slens/utilities";
|
||||
import type { ResourceRequirements } from "./types/resource-requirements";
|
||||
import { PersistentVolumeClaim } from "@k8slens/kube-object";
|
||||
|
||||
export class PersistentVolumeClaimApi extends KubeApi<PersistentVolumeClaim> {
|
||||
constructor(deps: KubeApiDependencies, opts?: DerivedKubeApiOptions) {
|
||||
@@ -20,54 +16,3 @@ export class PersistentVolumeClaimApi extends KubeApi<PersistentVolumeClaim> {
|
||||
}
|
||||
}
|
||||
|
||||
export interface PersistentVolumeClaimSpec {
|
||||
accessModes?: string[];
|
||||
dataSource?: TypedLocalObjectReference;
|
||||
dataSourceRef?: TypedLocalObjectReference;
|
||||
resources?: ResourceRequirements;
|
||||
selector?: LabelSelector;
|
||||
storageClassName?: string;
|
||||
volumeMode?: string;
|
||||
volumeName?: string;
|
||||
}
|
||||
|
||||
export interface PersistentVolumeClaimStatus {
|
||||
phase: string; // Pending
|
||||
}
|
||||
|
||||
export class PersistentVolumeClaim extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
PersistentVolumeClaimStatus,
|
||||
PersistentVolumeClaimSpec
|
||||
> {
|
||||
static readonly kind = "PersistentVolumeClaim";
|
||||
static readonly namespaced = true;
|
||||
static readonly apiBase = "/api/v1/persistentvolumeclaims";
|
||||
|
||||
getPods(pods: Pod[]): Pod[] {
|
||||
return pods
|
||||
.filter(pod => pod.getNs() === this.getNs())
|
||||
.filter(pod => (
|
||||
pod.getVolumes()
|
||||
.filter(volume => volume.persistentVolumeClaim?.claimName === this.getName())
|
||||
.length > 0
|
||||
));
|
||||
}
|
||||
|
||||
getStorage(): string {
|
||||
return this.spec.resources?.requests?.storage ?? "-";
|
||||
}
|
||||
|
||||
getMatchLabels(): string[] {
|
||||
return object.entries(this.spec.selector?.matchLabels)
|
||||
.map(([name, val]) => `${name}:${val}`);
|
||||
}
|
||||
|
||||
getMatchExpressions() {
|
||||
return this.spec.selector?.matchExpressions ?? [];
|
||||
}
|
||||
|
||||
getStatus(): string {
|
||||
return this.status?.phase ?? "-";
|
||||
}
|
||||
}
|
||||
@@ -3,104 +3,9 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { ClusterScopedMetadata, LabelSelector, ObjectReference, TypedLocalObjectReference } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { unitsToBytes } from "@k8slens/utilities";
|
||||
import { PersistentVolume } from "@k8slens/kube-object";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { ResourceRequirements } from "./types/resource-requirements";
|
||||
|
||||
export interface PersistentVolumeSpec {
|
||||
/**
|
||||
* AccessModes contains the desired access modes the volume should have.
|
||||
*
|
||||
* More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1
|
||||
*/
|
||||
accessModes?: string[];
|
||||
dataSource?: TypedLocalObjectReference;
|
||||
dataSourceRef?: TypedLocalObjectReference;
|
||||
resources?: ResourceRequirements;
|
||||
selector?: LabelSelector;
|
||||
|
||||
/**
|
||||
* Name of the StorageClass required by the claim.
|
||||
*
|
||||
* More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1
|
||||
*/
|
||||
storageClassName?: string;
|
||||
|
||||
/**
|
||||
* Defines what type of volume is required by the claim. Value of Filesystem is implied when not
|
||||
* included in claim spec.
|
||||
*/
|
||||
volumeMode?: string;
|
||||
|
||||
/**
|
||||
* A description of the persistent volume\'s resources and capacity.
|
||||
*
|
||||
* More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#capacity
|
||||
*/
|
||||
capacity?: Partial<Record<string, string>>;
|
||||
flexVolume?: {
|
||||
driver: string; // ceph.rook.io/rook-ceph-system,
|
||||
options?: {
|
||||
clusterNamespace: string; // rook-ceph,
|
||||
image: string; // pvc-c5d7c485-9f1b-11e8-b0ea-9600000e54fb,
|
||||
pool: string; // replicapool,
|
||||
storageClass: string; // rook-ceph-block
|
||||
};
|
||||
};
|
||||
mountOptions?: string[];
|
||||
claimRef?: ObjectReference;
|
||||
persistentVolumeReclaimPolicy?: string; // Delete,
|
||||
nfs?: {
|
||||
path: string;
|
||||
server: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface PersistentVolumeStatus {
|
||||
phase: string;
|
||||
reason?: string;
|
||||
}
|
||||
|
||||
export class PersistentVolume extends KubeObject<
|
||||
ClusterScopedMetadata,
|
||||
PersistentVolumeStatus,
|
||||
PersistentVolumeSpec
|
||||
> {
|
||||
static kind = "PersistentVolume";
|
||||
static namespaced = false;
|
||||
static apiBase = "/api/v1/persistentvolumes";
|
||||
|
||||
getCapacity(inBytes = false) {
|
||||
const capacity = this.spec.capacity;
|
||||
|
||||
if (capacity?.storage) {
|
||||
if (inBytes) return unitsToBytes(capacity.storage);
|
||||
|
||||
return capacity.storage;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
getStatus() {
|
||||
return this.status?.phase || "-";
|
||||
}
|
||||
|
||||
getStorageClass(): string {
|
||||
return this.spec.storageClassName ?? "";
|
||||
}
|
||||
|
||||
getClaimRefName(): string {
|
||||
return this.spec.claimRef?.name ?? "";
|
||||
}
|
||||
|
||||
getStorageClassName() {
|
||||
return this.spec.storageClassName || "";
|
||||
}
|
||||
}
|
||||
|
||||
export class PersistentVolumeApi extends KubeApi<PersistentVolume> {
|
||||
constructor(deps: KubeApiDependencies, opts: DerivedKubeApiOptions = {}) {
|
||||
|
||||
@@ -3,78 +3,9 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { LabelSelector, NamespaceScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { PodDisruptionBudget } from "@k8slens/kube-object";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { Condition } from "./types/condition";
|
||||
|
||||
export interface V1Beta1PodDisruptionBudgetSpec {
|
||||
minAvailable: string;
|
||||
maxUnavailable: string;
|
||||
selector: LabelSelector;
|
||||
}
|
||||
|
||||
export interface V1PodDisruptionBudgetSpec {
|
||||
maxUnavailable?: string | number;
|
||||
minAvailable?: string | number;
|
||||
selector?: LabelSelector;
|
||||
}
|
||||
|
||||
export type PodDisruptionBudgetSpec =
|
||||
| V1Beta1PodDisruptionBudgetSpec
|
||||
| V1PodDisruptionBudgetSpec;
|
||||
|
||||
export interface V1Beta1PodDisruptionBudgetStatus {
|
||||
currentHealthy: number;
|
||||
desiredHealthy: number;
|
||||
disruptionsAllowed: number;
|
||||
expectedPods: number;
|
||||
}
|
||||
|
||||
export interface V1PodDisruptionBudgetStatus {
|
||||
conditions?: Condition[];
|
||||
currentHealthy: number;
|
||||
desiredHealthy: number;
|
||||
disruptedPods?: Partial<Record<string, string>>;
|
||||
disruptionsAllowed: number;
|
||||
expectedPods: number;
|
||||
observedGeneration?: number;
|
||||
}
|
||||
|
||||
export type PodDisruptionBudgetStatus =
|
||||
| V1Beta1PodDisruptionBudgetStatus
|
||||
| V1PodDisruptionBudgetStatus;
|
||||
|
||||
export class PodDisruptionBudget extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
PodDisruptionBudgetStatus,
|
||||
PodDisruptionBudgetSpec
|
||||
> {
|
||||
static readonly kind = "PodDisruptionBudget";
|
||||
static readonly namespaced = true;
|
||||
static readonly apiBase = "/apis/policy/v1beta1/poddisruptionbudgets";
|
||||
|
||||
getSelectors() {
|
||||
return KubeObject.stringifyLabels(this.spec.selector?.matchLabels);
|
||||
}
|
||||
|
||||
getMinAvailable() {
|
||||
return this.spec.minAvailable ?? "N/A";
|
||||
}
|
||||
|
||||
getMaxUnavailable() {
|
||||
return this.spec.maxUnavailable ?? "N/A";
|
||||
}
|
||||
|
||||
getCurrentHealthy() {
|
||||
return this.status?.currentHealthy ?? 0;
|
||||
}
|
||||
|
||||
getDesiredHealthy() {
|
||||
return this.status?.desiredHealthy ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
export class PodDisruptionBudgetApi extends KubeApi<PodDisruptionBudget> {
|
||||
constructor(deps: KubeApiDependencies, opts: DerivedKubeApiOptions = {}) {
|
||||
|
||||
@@ -3,53 +3,10 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { KubeObjectMetadata, KubeObjectScope, NamespaceScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { PodMetricsData } from "@k8slens/kube-object";
|
||||
import { PodMetrics } from "@k8slens/kube-object";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
|
||||
export interface PodMetricsData extends KubeJsonApiData<KubeObjectMetadata<KubeObjectScope.Namespace>, void, void> {
|
||||
timestamp: string;
|
||||
window: string;
|
||||
containers: PodMetricsContainer[];
|
||||
}
|
||||
|
||||
export interface PodMetricsContainerUsage {
|
||||
cpu: string;
|
||||
memory: string;
|
||||
}
|
||||
|
||||
export interface PodMetricsContainer {
|
||||
name: string;
|
||||
usage: PodMetricsContainerUsage;
|
||||
}
|
||||
|
||||
export class PodMetrics extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
void,
|
||||
void
|
||||
> {
|
||||
static readonly kind = "PodMetrics";
|
||||
static readonly namespaced = true;
|
||||
static readonly apiBase = "/apis/metrics.k8s.io/v1beta1/pods";
|
||||
|
||||
timestamp: string;
|
||||
window: string;
|
||||
containers: PodMetricsContainer[];
|
||||
|
||||
constructor({
|
||||
timestamp,
|
||||
window,
|
||||
containers,
|
||||
...rest
|
||||
}: PodMetricsData) {
|
||||
super(rest);
|
||||
this.timestamp = timestamp;
|
||||
this.window = window;
|
||||
this.containers = containers;
|
||||
}
|
||||
}
|
||||
|
||||
export class PodMetricsApi extends KubeApi<PodMetrics, PodMetricsData> {
|
||||
constructor(deps: KubeApiDependencies, opts: DerivedKubeApiOptions = {}) {
|
||||
|
||||
@@ -3,113 +3,10 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { ClusterScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { PodSecurityPolicy } from "@k8slens/kube-object";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
|
||||
export interface PodSecurityPolicySpec {
|
||||
allowPrivilegeEscalation?: boolean;
|
||||
allowedCSIDrivers?: {
|
||||
name: string;
|
||||
}[];
|
||||
allowedCapabilities: string[];
|
||||
allowedFlexVolumes?: {
|
||||
driver: string;
|
||||
}[];
|
||||
allowedHostPaths?: {
|
||||
pathPrefix: string;
|
||||
readOnly: boolean;
|
||||
}[];
|
||||
allowedProcMountTypes?: string[];
|
||||
allowedUnsafeSysctls?: string[];
|
||||
defaultAddCapabilities?: string[];
|
||||
defaultAllowPrivilegeEscalation?: boolean;
|
||||
forbiddenSysctls?: string[];
|
||||
fsGroup?: {
|
||||
rule: string;
|
||||
ranges: {
|
||||
max: number;
|
||||
min: number;
|
||||
}[];
|
||||
};
|
||||
hostIPC?: boolean;
|
||||
hostNetwork?: boolean;
|
||||
hostPID?: boolean;
|
||||
hostPorts?: {
|
||||
max: number;
|
||||
min: number;
|
||||
}[];
|
||||
privileged?: boolean;
|
||||
readOnlyRootFilesystem?: boolean;
|
||||
requiredDropCapabilities?: string[];
|
||||
runAsGroup?: {
|
||||
ranges: {
|
||||
max: number;
|
||||
min: number;
|
||||
}[];
|
||||
rule: string;
|
||||
};
|
||||
runAsUser?: {
|
||||
rule: string;
|
||||
ranges: {
|
||||
max: number;
|
||||
min: number;
|
||||
}[];
|
||||
};
|
||||
runtimeClass?: {
|
||||
allowedRuntimeClassNames: string[];
|
||||
defaultRuntimeClassName: string;
|
||||
};
|
||||
seLinux?: {
|
||||
rule: string;
|
||||
seLinuxOptions: {
|
||||
level: string;
|
||||
role: string;
|
||||
type: string;
|
||||
user: string;
|
||||
};
|
||||
};
|
||||
supplementalGroups?: {
|
||||
rule: string;
|
||||
ranges: {
|
||||
max: number;
|
||||
min: number;
|
||||
}[];
|
||||
};
|
||||
volumes?: string[];
|
||||
}
|
||||
|
||||
export class PodSecurityPolicy extends KubeObject<
|
||||
ClusterScopedMetadata,
|
||||
void,
|
||||
PodSecurityPolicySpec
|
||||
> {
|
||||
static readonly kind = "PodSecurityPolicy";
|
||||
static readonly namespaced = false;
|
||||
static readonly apiBase = "/apis/policy/v1beta1/podsecuritypolicies";
|
||||
|
||||
isPrivileged() {
|
||||
return !!this.spec.privileged;
|
||||
}
|
||||
|
||||
getVolumes() {
|
||||
return this.spec.volumes || [];
|
||||
}
|
||||
|
||||
getRules() {
|
||||
const { fsGroup, runAsGroup, runAsUser, supplementalGroups, seLinux } = this.spec;
|
||||
|
||||
return {
|
||||
fsGroup: fsGroup ? fsGroup.rule : "",
|
||||
runAsGroup: runAsGroup ? runAsGroup.rule : "",
|
||||
runAsUser: runAsUser ? runAsUser.rule : "",
|
||||
supplementalGroups: supplementalGroups ? supplementalGroups.rule : "",
|
||||
seLinux: seLinux ? seLinux.rule : "",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class PodSecurityPolicyApi extends KubeApi<PodSecurityPolicy> {
|
||||
constructor(deps: KubeApiDependencies, opts: DerivedKubeApiOptions = {}) {
|
||||
super(deps, {
|
||||
|
||||
@@ -10,22 +10,9 @@ import type {
|
||||
ResourceDescriptor,
|
||||
} from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { RequireExactlyOne } from "type-fest";
|
||||
import type {
|
||||
Affinity,
|
||||
KubeObjectMetadata, KubeStatusData,
|
||||
LocalObjectReference,
|
||||
NamespaceScopedMetadata,
|
||||
Toleration,
|
||||
} from "../kube-object";
|
||||
import { isKubeStatusData, KubeObject, KubeStatus } from "../kube-object";
|
||||
import type { SecretReference } from "./secret.api";
|
||||
import type { PersistentVolumeClaimSpec } from "./persistent-volume-claim.api";
|
||||
import { isDefined } from "@k8slens/utilities";
|
||||
import type { PodSecurityContext } from "./types/pod-security-context";
|
||||
import type { Probe } from "./types/probe";
|
||||
import type { Container } from "./types/container";
|
||||
import type { ObjectFieldSelector, ResourceFieldSelector } from "./types";
|
||||
import type { KubeStatusData, PodLogsQuery } from "@k8slens/kube-object";
|
||||
import { isKubeStatusData, KubeStatus, Pod } from "@k8slens/kube-object";
|
||||
|
||||
|
||||
export class PodApi extends KubeApi<Pod> {
|
||||
constructor(deps: KubeApiDependencies, opts?: DerivedKubeApiOptions) {
|
||||
@@ -73,826 +60,3 @@ export class PodApi extends KubeApi<Pod> {
|
||||
return this.request.get(path, { query });
|
||||
}
|
||||
}
|
||||
|
||||
// Reference: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#read-log-pod-v1-core
|
||||
export interface PodLogsQuery {
|
||||
container?: string;
|
||||
tailLines?: number;
|
||||
timestamps?: boolean;
|
||||
sinceTime?: string; // Date.toISOString()-format
|
||||
follow?: boolean;
|
||||
previous?: boolean;
|
||||
}
|
||||
|
||||
export enum PodStatusPhase {
|
||||
TERMINATED = "Terminated",
|
||||
FAILED = "Failed",
|
||||
PENDING = "Pending",
|
||||
RUNNING = "Running",
|
||||
SUCCEEDED = "Succeeded",
|
||||
EVICTED = "Evicted",
|
||||
}
|
||||
|
||||
export interface ContainerStateRunning {
|
||||
startedAt: string;
|
||||
}
|
||||
|
||||
export interface ContainerStateWaiting {
|
||||
reason: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface ContainerStateTerminated {
|
||||
startedAt: string;
|
||||
finishedAt: string;
|
||||
exitCode: number;
|
||||
reason: string;
|
||||
containerID?: string;
|
||||
message?: string;
|
||||
signal?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* ContainerState holds a possible state of container. Only one of its members
|
||||
* may be specified. If none of them is specified, the default one is
|
||||
* `ContainerStateWaiting`.
|
||||
*/
|
||||
export interface ContainerState {
|
||||
running?: ContainerStateRunning;
|
||||
waiting?: ContainerStateWaiting;
|
||||
terminated?: ContainerStateTerminated;
|
||||
}
|
||||
|
||||
export type ContainerStateValues = Partial<ContainerState[keyof ContainerState]>;
|
||||
|
||||
export interface PodContainerStatus {
|
||||
name: string;
|
||||
state?: ContainerState;
|
||||
lastState?: ContainerState;
|
||||
ready: boolean;
|
||||
restartCount: number;
|
||||
image: string;
|
||||
imageID: string;
|
||||
containerID?: string;
|
||||
started?: boolean;
|
||||
}
|
||||
|
||||
export interface AwsElasticBlockStoreSource {
|
||||
volumeID: string;
|
||||
fsType: string;
|
||||
}
|
||||
|
||||
export interface AzureDiskSource {
|
||||
/**
|
||||
* The name of the VHD blob object OR the name of an Azure managed data disk if `kind` is `"Managed"`.
|
||||
*/
|
||||
diskName: string;
|
||||
/**
|
||||
* The URI of the vhd blob object OR the `resourceID` of an Azure managed data disk if `kind` is `"Managed"`.
|
||||
*/
|
||||
diskURI: string;
|
||||
/**
|
||||
* Kind of disk
|
||||
* @default "Shared"
|
||||
*/
|
||||
kind?: "Shared" | "Dedicated" | "Managed";
|
||||
/**
|
||||
* Disk caching mode.
|
||||
* @default "None"
|
||||
*/
|
||||
cachingMode?: "None" | "ReadOnly" | "ReadWrite";
|
||||
/**
|
||||
* The filesystem type to mount.
|
||||
* @default "ext4"
|
||||
*/
|
||||
fsType?: string;
|
||||
/**
|
||||
* Whether the filesystem is used as readOnly.
|
||||
* @default false
|
||||
*/
|
||||
readonly?: boolean;
|
||||
}
|
||||
|
||||
export interface AzureFileSource {
|
||||
/**
|
||||
* The name of the secret that contains both Azure storage account name and key.
|
||||
*/
|
||||
secretName: string;
|
||||
/**
|
||||
* The share name to be used.
|
||||
*/
|
||||
shareName: string;
|
||||
/**
|
||||
* In case the secret is stored in a different namespace.
|
||||
* @default "default"
|
||||
*/
|
||||
secretNamespace?: string;
|
||||
/**
|
||||
* Whether the filesystem is used as readOnly.
|
||||
*/
|
||||
readOnly: boolean;
|
||||
}
|
||||
|
||||
export interface CephfsSource {
|
||||
/**
|
||||
* List of Ceph monitors
|
||||
*/
|
||||
monitors: string[];
|
||||
/**
|
||||
* Used as the mounted root, rather than the full Ceph tree.
|
||||
* @default "/"
|
||||
*/
|
||||
path?: string;
|
||||
/**
|
||||
* The RADOS user name.
|
||||
* @default "admin"
|
||||
*/
|
||||
user?: string;
|
||||
/**
|
||||
* The path to the keyring file.
|
||||
* @default "/etc/ceph/user.secret"
|
||||
*/
|
||||
secretFile?: string;
|
||||
/**
|
||||
* Reference to Ceph authentication secrets. If provided, then the secret overrides `secretFile`
|
||||
*/
|
||||
secretRef?: SecretReference;
|
||||
/**
|
||||
* Whether the filesystem is used as readOnly.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
readOnly?: boolean;
|
||||
}
|
||||
|
||||
export interface CinderSource {
|
||||
volumeID: string;
|
||||
fsType: string;
|
||||
/**
|
||||
* @default false
|
||||
*/
|
||||
readOnly?: boolean;
|
||||
secretRef?: SecretReference;
|
||||
}
|
||||
|
||||
export interface ConfigMapSource {
|
||||
name: string;
|
||||
items: {
|
||||
key: string;
|
||||
path: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface DownwardApiSource {
|
||||
items: {
|
||||
path: string;
|
||||
fieldRef: {
|
||||
fieldPath: string;
|
||||
};
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface EphemeralSource {
|
||||
volumeClaimTemplate: {
|
||||
/**
|
||||
* All the rest of the fields are ignored and rejected during validation
|
||||
*/
|
||||
metadata?: Pick<KubeObjectMetadata, "labels" | "annotations">;
|
||||
spec: PersistentVolumeClaimSpec;
|
||||
};
|
||||
}
|
||||
|
||||
export interface EmptyDirSource {
|
||||
medium?: string;
|
||||
sizeLimit?: string;
|
||||
}
|
||||
|
||||
export interface FiberChannelSource {
|
||||
/**
|
||||
* A list of World Wide Names
|
||||
*/
|
||||
targetWWNs: string[];
|
||||
/**
|
||||
* Logical Unit number
|
||||
*/
|
||||
lun: number;
|
||||
/**
|
||||
* The type of filesystem
|
||||
* @default "ext4"
|
||||
*/
|
||||
fsType?: string;
|
||||
readOnly: boolean;
|
||||
}
|
||||
|
||||
export interface FlockerSource {
|
||||
datasetName: string;
|
||||
}
|
||||
|
||||
export interface FlexVolumeSource {
|
||||
driver: string;
|
||||
fsType?: string;
|
||||
secretRef?: LocalObjectReference;
|
||||
/**
|
||||
* @default false
|
||||
*/
|
||||
readOnly?: boolean;
|
||||
options?: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface GcePersistentDiskSource {
|
||||
pdName: string;
|
||||
fsType: string;
|
||||
}
|
||||
|
||||
export interface GitRepoSource {
|
||||
repository: string;
|
||||
revision: string;
|
||||
}
|
||||
|
||||
export interface GlusterFsSource {
|
||||
/**
|
||||
* The name of the Endpoints object that represents a Gluster cluster configuration.
|
||||
*/
|
||||
endpoints: string;
|
||||
/**
|
||||
* The Glusterfs volume name.
|
||||
*/
|
||||
path: string;
|
||||
/**
|
||||
* The boolean that sets the mountpoint readOnly or readWrite.
|
||||
*/
|
||||
readOnly: boolean;
|
||||
}
|
||||
|
||||
export interface HostPathSource {
|
||||
path: string;
|
||||
/**
|
||||
* Determines the sorts of checks that will be done
|
||||
* @default ""
|
||||
*/
|
||||
type?: "" | "DirectoryOrCreate" | "Directory" | "FileOrCreate" | "File" | "Socket" | "CharDevice" | "BlockDevice";
|
||||
}
|
||||
|
||||
export interface IScsiSource {
|
||||
targetPortal: string;
|
||||
iqn: string;
|
||||
lun: number;
|
||||
fsType: string;
|
||||
readOnly: boolean;
|
||||
chapAuthDiscovery?: boolean;
|
||||
chapAuthSession?: boolean;
|
||||
secretRef?: SecretReference;
|
||||
}
|
||||
|
||||
export interface LocalSource {
|
||||
path: string;
|
||||
}
|
||||
|
||||
export interface NetworkFsSource {
|
||||
server: string;
|
||||
path: string;
|
||||
readOnly?: boolean;
|
||||
}
|
||||
|
||||
export interface PersistentVolumeClaimSource {
|
||||
claimName: string;
|
||||
}
|
||||
|
||||
export interface PhotonPersistentDiskSource {
|
||||
pdID: string;
|
||||
/**
|
||||
* @default "ext4"
|
||||
*/
|
||||
fsType?: string;
|
||||
}
|
||||
|
||||
export interface PortworxVolumeSource {
|
||||
volumeID: string;
|
||||
fsType?: string;
|
||||
readOnly?: boolean;
|
||||
}
|
||||
|
||||
export interface KeyToPath {
|
||||
key: string;
|
||||
path: string;
|
||||
mode?: number;
|
||||
}
|
||||
|
||||
export interface ConfigMapProjection {
|
||||
name: string;
|
||||
items?: KeyToPath[];
|
||||
optional?: boolean;
|
||||
}
|
||||
|
||||
export interface DownwardAPIVolumeFile {
|
||||
path: string;
|
||||
fieldRef?: ObjectFieldSelector;
|
||||
resourceFieldRef?: ResourceFieldSelector;
|
||||
mode?: number;
|
||||
}
|
||||
|
||||
export interface DownwardAPIProjection {
|
||||
items?: DownwardAPIVolumeFile[];
|
||||
}
|
||||
|
||||
export interface SecretProjection {
|
||||
name: string;
|
||||
items?: KeyToPath[];
|
||||
optional?: boolean;
|
||||
}
|
||||
|
||||
export interface ServiceAccountTokenProjection {
|
||||
audience?: string;
|
||||
expirationSeconds?: number;
|
||||
path: string;
|
||||
}
|
||||
|
||||
export interface VolumeProjection {
|
||||
secret?: SecretProjection;
|
||||
downwardAPI?: DownwardAPIProjection;
|
||||
configMap?: ConfigMapProjection;
|
||||
serviceAccountToken?: ServiceAccountTokenProjection;
|
||||
}
|
||||
|
||||
export interface ProjectedSource {
|
||||
sources?: VolumeProjection[];
|
||||
defaultMode?: number;
|
||||
}
|
||||
|
||||
export interface QuobyteSource {
|
||||
registry: string;
|
||||
volume: string;
|
||||
/**
|
||||
* @default false
|
||||
*/
|
||||
readOnly?: boolean;
|
||||
/**
|
||||
* @default "serivceaccount"
|
||||
*/
|
||||
user?: string;
|
||||
group?: string;
|
||||
tenant?: string;
|
||||
}
|
||||
|
||||
export interface RadosBlockDeviceSource {
|
||||
monitors: string[];
|
||||
image: string;
|
||||
/**
|
||||
* @default "ext4"
|
||||
*/
|
||||
fsType?: string;
|
||||
/**
|
||||
* @default "rbd"
|
||||
*/
|
||||
pool?: string;
|
||||
/**
|
||||
* @default "admin"
|
||||
*/
|
||||
user?: string;
|
||||
/**
|
||||
* @default "/etc/ceph/keyring"
|
||||
*/
|
||||
keyring?: string;
|
||||
secretRef?: SecretReference;
|
||||
/**
|
||||
* @default false
|
||||
*/
|
||||
readOnly?: boolean;
|
||||
}
|
||||
|
||||
export interface ScaleIoSource {
|
||||
gateway: string;
|
||||
system: string;
|
||||
secretRef?: LocalObjectReference;
|
||||
/**
|
||||
* @default false
|
||||
*/
|
||||
sslEnabled?: boolean;
|
||||
protectionDomain?: string;
|
||||
storagePool?: string;
|
||||
/**
|
||||
* @default "ThinProvisioned"
|
||||
*/
|
||||
storageMode?: "ThickProvisioned" | "ThinProvisioned";
|
||||
volumeName: string;
|
||||
/**
|
||||
* @default "xfs"
|
||||
*/
|
||||
fsType?: string;
|
||||
/**
|
||||
* @default false
|
||||
*/
|
||||
readOnly?: boolean;
|
||||
}
|
||||
|
||||
export interface SecretSource {
|
||||
secretName: string;
|
||||
items?: {
|
||||
key: string;
|
||||
path: string;
|
||||
mode?: number;
|
||||
}[];
|
||||
defaultMode?: number;
|
||||
optional?: boolean;
|
||||
}
|
||||
|
||||
export interface StorageOsSource {
|
||||
volumeName: string;
|
||||
/**
|
||||
* @default Pod.metadata.namespace
|
||||
*/
|
||||
volumeNamespace?: string;
|
||||
/**
|
||||
* @default "ext4"
|
||||
*/
|
||||
fsType?: string;
|
||||
/**
|
||||
* @default false
|
||||
*/
|
||||
readOnly?: boolean;
|
||||
secretRef?: LocalObjectReference;
|
||||
}
|
||||
|
||||
export interface VsphereVolumeSource {
|
||||
volumePath: string;
|
||||
/**
|
||||
* @default "ext4"
|
||||
*/
|
||||
fsType?: string;
|
||||
storagePolicyName?: string;
|
||||
storagePolicyID?: string;
|
||||
}
|
||||
|
||||
export interface ContainerStorageInterfaceSource {
|
||||
driver: string;
|
||||
/**
|
||||
* @default false
|
||||
*/
|
||||
readOnly?: boolean;
|
||||
/**
|
||||
* @default "ext4"
|
||||
*/
|
||||
fsType?: string;
|
||||
volumeAttributes?: Record<string, string>;
|
||||
controllerPublishSecretRef?: SecretReference;
|
||||
nodeStageSecretRef?: SecretReference;
|
||||
nodePublishSecretRef?: SecretReference;
|
||||
controllerExpandSecretRef?: SecretReference;
|
||||
}
|
||||
|
||||
export interface PodVolumeVariants {
|
||||
awsElasticBlockStore: AwsElasticBlockStoreSource;
|
||||
azureDisk: AzureDiskSource;
|
||||
azureFile: AzureFileSource;
|
||||
cephfs: CephfsSource;
|
||||
cinder: CinderSource;
|
||||
configMap: ConfigMapSource;
|
||||
csi: ContainerStorageInterfaceSource;
|
||||
downwardAPI: DownwardApiSource;
|
||||
emptyDir: EmptyDirSource;
|
||||
ephemeral: EphemeralSource;
|
||||
fc: FiberChannelSource;
|
||||
flexVolume: FlexVolumeSource;
|
||||
flocker: FlockerSource;
|
||||
gcePersistentDisk: GcePersistentDiskSource;
|
||||
gitRepo: GitRepoSource;
|
||||
glusterfs: GlusterFsSource;
|
||||
hostPath: HostPathSource;
|
||||
iscsi: IScsiSource;
|
||||
local: LocalSource;
|
||||
nfs: NetworkFsSource;
|
||||
persistentVolumeClaim: PersistentVolumeClaimSource;
|
||||
photonPersistentDisk: PhotonPersistentDiskSource;
|
||||
portworxVolume: PortworxVolumeSource;
|
||||
projected: ProjectedSource;
|
||||
quobyte: QuobyteSource;
|
||||
rbd: RadosBlockDeviceSource;
|
||||
scaleIO: ScaleIoSource;
|
||||
secret: SecretSource;
|
||||
storageos: StorageOsSource;
|
||||
vsphereVolume: VsphereVolumeSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* The valid kinds of volume
|
||||
*/
|
||||
export type PodVolumeKind = keyof PodVolumeVariants;
|
||||
|
||||
export type PodSpecVolume = RequireExactlyOne<PodVolumeVariants> & {
|
||||
name: string;
|
||||
};
|
||||
|
||||
|
||||
export interface HostAlias {
|
||||
ip: string;
|
||||
hostnames: string[];
|
||||
}
|
||||
|
||||
export interface Sysctl {
|
||||
name: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface TopologySpreadConstraint {
|
||||
|
||||
}
|
||||
|
||||
export interface PodSpec {
|
||||
activeDeadlineSeconds?: number;
|
||||
affinity?: Affinity;
|
||||
automountServiceAccountToken?: boolean;
|
||||
containers?: Container[];
|
||||
dnsPolicy?: string;
|
||||
enableServiceLinks?: boolean;
|
||||
ephemeralContainers?: unknown[];
|
||||
hostAliases?: HostAlias[];
|
||||
hostIPC?: boolean;
|
||||
hostname?: string;
|
||||
hostNetwork?: boolean;
|
||||
hostPID?: boolean;
|
||||
imagePullSecrets?: LocalObjectReference[];
|
||||
initContainers?: Container[];
|
||||
nodeName?: string;
|
||||
nodeSelector?: Partial<Record<string, string>>;
|
||||
overhead?: Partial<Record<string, string>>;
|
||||
preemptionPolicy?: string;
|
||||
priority?: number;
|
||||
priorityClassName?: string;
|
||||
readinessGates?: unknown[];
|
||||
restartPolicy?: string;
|
||||
runtimeClassName?: string;
|
||||
schedulerName?: string;
|
||||
securityContext?: PodSecurityContext;
|
||||
serviceAccount?: string;
|
||||
serviceAccountName?: string;
|
||||
setHostnameAsFQDN?: boolean;
|
||||
shareProcessNamespace?: boolean;
|
||||
subdomain?: string;
|
||||
terminationGracePeriodSeconds?: number;
|
||||
tolerations?: Toleration[];
|
||||
topologySpreadConstraints?: TopologySpreadConstraint[];
|
||||
volumes?: PodSpecVolume[];
|
||||
}
|
||||
|
||||
export interface PodCondition {
|
||||
lastProbeTime?: number;
|
||||
lastTransitionTime?: string;
|
||||
message?: string;
|
||||
reason?: string;
|
||||
type: string;
|
||||
status: string;
|
||||
}
|
||||
|
||||
export interface PodStatus {
|
||||
phase: string;
|
||||
conditions: PodCondition[];
|
||||
hostIP: string;
|
||||
podIP: string;
|
||||
podIPs?: {
|
||||
ip: string;
|
||||
}[];
|
||||
startTime: string;
|
||||
initContainerStatuses?: PodContainerStatus[];
|
||||
containerStatuses?: PodContainerStatus[];
|
||||
qosClass?: string;
|
||||
reason?: string;
|
||||
}
|
||||
|
||||
export class Pod extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
PodStatus,
|
||||
PodSpec
|
||||
> {
|
||||
static kind = "Pod";
|
||||
static namespaced = true;
|
||||
static apiBase = "/api/v1/pods";
|
||||
|
||||
getAffinityNumber() {
|
||||
return Object.keys(this.getAffinity()).length;
|
||||
}
|
||||
|
||||
getInitContainers() {
|
||||
return this.spec?.initContainers ?? [];
|
||||
}
|
||||
|
||||
getContainers() {
|
||||
return this.spec?.containers ?? [];
|
||||
}
|
||||
|
||||
getAllContainers() {
|
||||
return [...this.getContainers(), ...this.getInitContainers()];
|
||||
}
|
||||
|
||||
getRunningContainers() {
|
||||
const runningContainerNames = new Set(
|
||||
this.getContainerStatuses()
|
||||
.filter(({ state }) => state?.running)
|
||||
.map(({ name }) => name),
|
||||
);
|
||||
|
||||
return this.getAllContainers()
|
||||
.filter(({ name }) => runningContainerNames.has(name));
|
||||
}
|
||||
|
||||
getContainerStatuses(includeInitContainers = true): PodContainerStatus[] {
|
||||
const { containerStatuses = [], initContainerStatuses = [] } = this.status ?? {};
|
||||
|
||||
if (includeInitContainers) {
|
||||
return [...containerStatuses, ...initContainerStatuses];
|
||||
}
|
||||
|
||||
return [...containerStatuses];
|
||||
}
|
||||
|
||||
getRestartsCount(): number {
|
||||
const { containerStatuses = [] } = this.status ?? {};
|
||||
|
||||
return containerStatuses.reduce((totalCount, { restartCount }) => totalCount + restartCount, 0);
|
||||
}
|
||||
|
||||
getQosClass() {
|
||||
return this.status?.qosClass || "";
|
||||
}
|
||||
|
||||
getReason() {
|
||||
return this.status?.reason || "";
|
||||
}
|
||||
|
||||
getPriorityClassName() {
|
||||
return this.spec?.priorityClassName || "";
|
||||
}
|
||||
|
||||
getRuntimeClassName() {
|
||||
return this.spec?.runtimeClassName || "";
|
||||
}
|
||||
|
||||
getServiceAccountName() {
|
||||
return this.spec?.serviceAccountName || "";
|
||||
}
|
||||
|
||||
getStatus(): PodStatusPhase {
|
||||
const phase = this.getStatusPhase();
|
||||
const reason = this.getReason();
|
||||
const trueConditionTypes = new Set(this.getConditions()
|
||||
.filter(({ status }) => status === "True")
|
||||
.map(({ type }) => type));
|
||||
const isInGoodCondition = ["Initialized", "Ready"].every(condition => trueConditionTypes.has(condition));
|
||||
|
||||
if (reason === PodStatusPhase.EVICTED) {
|
||||
return PodStatusPhase.EVICTED;
|
||||
}
|
||||
|
||||
if (phase === PodStatusPhase.FAILED) {
|
||||
return PodStatusPhase.FAILED;
|
||||
}
|
||||
|
||||
if (phase === PodStatusPhase.SUCCEEDED) {
|
||||
return PodStatusPhase.SUCCEEDED;
|
||||
}
|
||||
|
||||
if (phase === PodStatusPhase.RUNNING && isInGoodCondition) {
|
||||
return PodStatusPhase.RUNNING;
|
||||
}
|
||||
|
||||
return PodStatusPhase.PENDING;
|
||||
}
|
||||
|
||||
// Returns pod phase or container error if occurred
|
||||
getStatusMessage(): string {
|
||||
if (this.getReason() === PodStatusPhase.EVICTED) {
|
||||
return "Evicted";
|
||||
}
|
||||
|
||||
if (this.metadata.deletionTimestamp) {
|
||||
return "Terminating";
|
||||
}
|
||||
|
||||
return this.getStatusPhase() || "Waiting";
|
||||
}
|
||||
|
||||
getStatusPhase() {
|
||||
return this.status?.phase;
|
||||
}
|
||||
|
||||
getConditions() {
|
||||
return this.status?.conditions ?? [];
|
||||
}
|
||||
|
||||
getVolumes() {
|
||||
return this.spec?.volumes ?? [];
|
||||
}
|
||||
|
||||
getSecrets(): string[] {
|
||||
return this.getVolumes()
|
||||
.map(vol => vol.secret?.secretName)
|
||||
.filter(isDefined);
|
||||
}
|
||||
|
||||
getNodeSelectors(): string[] {
|
||||
return Object.entries(this.spec?.nodeSelector ?? {})
|
||||
.map(values => values.join(": "));
|
||||
}
|
||||
|
||||
getTolerations() {
|
||||
return this.spec?.tolerations ?? [];
|
||||
}
|
||||
|
||||
getAffinity(): Affinity {
|
||||
return this.spec?.affinity ?? {};
|
||||
}
|
||||
|
||||
hasIssues() {
|
||||
for (const { type, status } of this.getConditions()) {
|
||||
if (type === "Ready" && status !== "True") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (const { state } of this.getContainerStatuses()) {
|
||||
if (state?.waiting?.reason === "CrashLookBackOff") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return this.getStatusPhase() !== "Running";
|
||||
}
|
||||
|
||||
getLivenessProbe(container: Container) {
|
||||
return this.getProbe(container, container.livenessProbe);
|
||||
}
|
||||
|
||||
getReadinessProbe(container: Container) {
|
||||
return this.getProbe(container, container.readinessProbe);
|
||||
}
|
||||
|
||||
getStartupProbe(container: Container) {
|
||||
return this.getProbe(container, container.startupProbe);
|
||||
}
|
||||
|
||||
private getProbe(container: Container, probe: Probe | undefined): string[] {
|
||||
const probeItems: string[] = [];
|
||||
|
||||
if (!probe) {
|
||||
return probeItems;
|
||||
}
|
||||
|
||||
const {
|
||||
httpGet,
|
||||
exec,
|
||||
tcpSocket,
|
||||
initialDelaySeconds = 0,
|
||||
timeoutSeconds = 0,
|
||||
periodSeconds = 0,
|
||||
successThreshold = 0,
|
||||
failureThreshold = 0,
|
||||
} = probe;
|
||||
|
||||
// HTTP Request
|
||||
if (httpGet) {
|
||||
const { path = "", port, host = "", scheme = "HTTP" } = httpGet;
|
||||
const resolvedPort = typeof port === "number"
|
||||
? port
|
||||
// Try and find the port number associated witht the name or fallback to the name itself
|
||||
: container.ports?.find(containerPort => containerPort.name === port)?.containerPort || port;
|
||||
|
||||
probeItems.push(
|
||||
"http-get",
|
||||
`${scheme.toLowerCase()}://${host}:${resolvedPort}${path}`,
|
||||
);
|
||||
}
|
||||
|
||||
// Command
|
||||
if (exec?.command) {
|
||||
probeItems.push(`exec [${exec.command.join(" ")}]`);
|
||||
}
|
||||
|
||||
// TCP Probe
|
||||
if (tcpSocket?.port) {
|
||||
probeItems.push(`tcp-socket :${tcpSocket.port}`);
|
||||
}
|
||||
|
||||
probeItems.push(
|
||||
`delay=${initialDelaySeconds}s`,
|
||||
`timeout=${timeoutSeconds}s`,
|
||||
`period=${periodSeconds}s`,
|
||||
`#success=${successThreshold}`,
|
||||
`#failure=${failureThreshold}`,
|
||||
);
|
||||
|
||||
return probeItems;
|
||||
}
|
||||
|
||||
getNodeName(): string | undefined {
|
||||
return this.spec?.nodeName;
|
||||
}
|
||||
|
||||
getSelectedNodeOs(): string | undefined {
|
||||
return this.spec?.nodeSelector?.["kubernetes.io/os"] || this.spec?.nodeSelector?.["beta.kubernetes.io/os"];
|
||||
}
|
||||
|
||||
getIPs(): string[] {
|
||||
const podIPs = this.status?.podIPs ?? [];
|
||||
|
||||
return podIPs.map(value => value.ip);
|
||||
}
|
||||
}
|
||||
@@ -5,56 +5,9 @@
|
||||
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import type { ClusterScopedMetadata, KubeObjectMetadata, KubeObjectScope } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { PreemptionPolicy } from "./types/preemption-policy";
|
||||
import type { PriorityClassData } from "@k8slens/kube-object";
|
||||
import { PriorityClass } from "@k8slens/kube-object";
|
||||
|
||||
export interface PriorityClassData extends KubeJsonApiData<KubeObjectMetadata<KubeObjectScope.Cluster>, void, void> {
|
||||
description?: string;
|
||||
globalDefault?: boolean;
|
||||
preemptionPolicy?: PreemptionPolicy;
|
||||
value: number;
|
||||
}
|
||||
|
||||
export class PriorityClass extends KubeObject<
|
||||
ClusterScopedMetadata,
|
||||
void,
|
||||
void
|
||||
> {
|
||||
static readonly kind = "PriorityClass";
|
||||
static readonly namespaced = false;
|
||||
static readonly apiBase = "/apis/scheduling.k8s.io/v1/priorityclasses";
|
||||
|
||||
description?: string;
|
||||
globalDefault?: boolean;
|
||||
preemptionPolicy?: PreemptionPolicy;
|
||||
value?: number;
|
||||
|
||||
constructor({ description, globalDefault, preemptionPolicy, value, ...rest }: PriorityClassData) {
|
||||
super(rest);
|
||||
this.description = description;
|
||||
this.globalDefault = globalDefault;
|
||||
this.preemptionPolicy = preemptionPolicy;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return this.description || "";
|
||||
}
|
||||
|
||||
getGlobalDefault() {
|
||||
return (this.globalDefault || false).toString();
|
||||
}
|
||||
|
||||
getPreemptionPolicy() {
|
||||
return this.preemptionPolicy || "PreemptLowerPriority";
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
export class PriorityClassApi extends KubeApi<PriorityClass, PriorityClassData> {
|
||||
constructor(deps: KubeApiDependencies, opts: DerivedKubeApiOptions = {}) {
|
||||
|
||||
@@ -3,11 +3,9 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies, NamespacedResourceDescriptor } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeObjectStatus, LabelSelector, NamespaceScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { PodTemplateSpec } from "./types/pod-template-spec";
|
||||
import { ReplicaSet } from "@k8slens/kube-object";
|
||||
|
||||
export class ReplicaSetApi extends KubeApi<ReplicaSet> {
|
||||
constructor(deps: KubeApiDependencies, opts?: DerivedKubeApiOptions) {
|
||||
@@ -17,17 +15,17 @@ export class ReplicaSetApi extends KubeApi<ReplicaSet> {
|
||||
});
|
||||
}
|
||||
|
||||
protected getScaleApiUrl(params: { namespace: string; name: string }) {
|
||||
return `${this.getUrl(params)}/scale`;
|
||||
protected getScaleApiUrl(params: NamespacedResourceDescriptor) {
|
||||
return `${this.formatUrlForNotListing(params)}/scale`;
|
||||
}
|
||||
|
||||
async getReplicas(params: { namespace: string; name: string }): Promise<number> {
|
||||
async getReplicas(params: NamespacedResourceDescriptor): Promise<number> {
|
||||
const { status } = await this.request.get(this.getScaleApiUrl(params));
|
||||
|
||||
return (status as { replicas: number })?.replicas;
|
||||
}
|
||||
|
||||
scale(params: { namespace: string; name: string }, replicas: number) {
|
||||
scale(params: NamespacedResourceDescriptor, replicas: number) {
|
||||
return this.request.put(this.getScaleApiUrl(params), {
|
||||
data: {
|
||||
metadata: params,
|
||||
@@ -38,70 +36,3 @@ export class ReplicaSetApi extends KubeApi<ReplicaSet> {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export interface ReplicaSetSpec {
|
||||
replicas?: number;
|
||||
selector: LabelSelector;
|
||||
template?: PodTemplateSpec;
|
||||
minReadySeconds?: number;
|
||||
}
|
||||
|
||||
export interface ReplicaSetStatus extends KubeObjectStatus {
|
||||
replicas: number;
|
||||
fullyLabeledReplicas?: number;
|
||||
readyReplicas?: number;
|
||||
availableReplicas?: number;
|
||||
observedGeneration?: number;
|
||||
}
|
||||
|
||||
export class ReplicaSet extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
ReplicaSetStatus,
|
||||
ReplicaSetSpec
|
||||
> {
|
||||
static kind = "ReplicaSet";
|
||||
static namespaced = true;
|
||||
static apiBase = "/apis/apps/v1/replicasets";
|
||||
|
||||
getSelectors(): string[] {
|
||||
return KubeObject.stringifyLabels(this.spec.selector.matchLabels);
|
||||
}
|
||||
|
||||
getNodeSelectors(): string[] {
|
||||
return KubeObject.stringifyLabels(this.spec.template?.spec?.nodeSelector);
|
||||
}
|
||||
|
||||
getTemplateLabels(): string[] {
|
||||
return KubeObject.stringifyLabels(this.spec.template?.metadata?.labels);
|
||||
}
|
||||
|
||||
getTolerations() {
|
||||
return this.spec.template?.spec?.tolerations ?? [];
|
||||
}
|
||||
|
||||
getAffinity() {
|
||||
return this.spec.template?.spec?.affinity;
|
||||
}
|
||||
|
||||
getAffinityNumber() {
|
||||
return Object.keys(this.getAffinity() ?? {}).length;
|
||||
}
|
||||
|
||||
getDesired() {
|
||||
return this.spec.replicas ?? 0;
|
||||
}
|
||||
|
||||
getCurrent() {
|
||||
return this.status?.availableReplicas ?? 0;
|
||||
}
|
||||
|
||||
getReady() {
|
||||
return this.status?.readyReplicas ?? 0;
|
||||
}
|
||||
|
||||
getImages() {
|
||||
const containers = this.spec.template?.spec?.containers ?? [];
|
||||
|
||||
return containers.map(container => container.image);
|
||||
}
|
||||
}
|
||||
@@ -3,15 +3,10 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies, NamespacedResourceDescriptor } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type {
|
||||
BaseKubeObjectCondition, KubeObjectMetadata,
|
||||
KubeObjectStatus,
|
||||
NamespaceScopedMetadata,
|
||||
} from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { PodTemplateSpec } from "./types";
|
||||
import { ReplicationController } from "@k8slens/kube-object";
|
||||
import type { Scale } from "@k8slens/kube-object";
|
||||
|
||||
export class ReplicationControllerApi extends KubeApi<ReplicationController> {
|
||||
constructor(deps: KubeApiDependencies, opts?: DerivedKubeApiOptions) {
|
||||
@@ -21,15 +16,15 @@ export class ReplicationControllerApi extends KubeApi<ReplicationController> {
|
||||
});
|
||||
}
|
||||
|
||||
protected getScaleApiUrl(params: { namespace: string; name: string }) {
|
||||
protected getScaleApiUrl(params: NamespacedResourceDescriptor) {
|
||||
return `${this.formatUrlForNotListing(params)}/scale`;
|
||||
}
|
||||
|
||||
getScale(params: { namespace: string; name: string }): Promise<Scale> {
|
||||
getScale(params: NamespacedResourceDescriptor): Promise<Scale> {
|
||||
return this.request.get(this.getScaleApiUrl(params));
|
||||
}
|
||||
|
||||
scale(params: { namespace: string; name: string }, replicas: number): Promise<Scale> {
|
||||
scale(params: NamespacedResourceDescriptor, replicas: number): Promise<Scale> {
|
||||
return this.request.patch(this.getScaleApiUrl(params), {
|
||||
data: {
|
||||
metadata: params,
|
||||
@@ -44,106 +39,3 @@ export class ReplicationControllerApi extends KubeApi<ReplicationController> {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export interface Scale {
|
||||
apiVersion: "autoscaling/v1";
|
||||
kind: "Scale";
|
||||
metadata: KubeObjectMetadata;
|
||||
spec: {
|
||||
replicas: number;
|
||||
};
|
||||
status: {
|
||||
replicas: number;
|
||||
selector: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ReplicationControllerSpec {
|
||||
/**
|
||||
* Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available.
|
||||
* Defaults to 0 (pod will be considered available as soon as it is ready)
|
||||
*/
|
||||
minReadySeconds?: number;
|
||||
/**
|
||||
* Replicas is the number of desired replicas. This is a pointer to distinguish between explicit zero and unspecified.
|
||||
* Defaults to 1. More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#what-is-a-replicationcontroller
|
||||
*/
|
||||
replicas?: number;
|
||||
/**
|
||||
* Selector is a label query over pods that should match the Replicas count. If Selector is empty, it is defaulted to the labels present on the Pod template.
|
||||
* Label keys and values that must match in order to be controlled by this replication controller, if empty defaulted to labels on Pod template.
|
||||
* More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors
|
||||
*/
|
||||
selector?: Record<string, string>;
|
||||
/**
|
||||
* Template is the object that describes the pod that will be created if insufficient replicas are detected. This takes precedence over a TemplateRef.
|
||||
* More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#pod-template
|
||||
*/
|
||||
template: PodTemplateSpec;
|
||||
}
|
||||
|
||||
export interface ReplicationControllerStatus extends KubeObjectStatus {
|
||||
/**
|
||||
* The number of available replicas (ready for at least minReadySeconds) for this replication controller.
|
||||
*/
|
||||
availableReplicas: number;
|
||||
/**
|
||||
* The number of pods that have labels matching the labels of the pod template of the replication controller.
|
||||
*/
|
||||
fullyLabeledReplicas: number;
|
||||
/**
|
||||
* ObservedGeneration reflects the generation of the most recently observed replication controller.
|
||||
*/
|
||||
observedGeneration: number;
|
||||
/**
|
||||
* The number of ready replicas for this replication controller.
|
||||
*/
|
||||
readyReplicas: number;
|
||||
/**
|
||||
* Replicas is the most recently observed number of replicas.
|
||||
* More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#what-is-a-replicationcontroller
|
||||
*/
|
||||
replicas: number;
|
||||
}
|
||||
|
||||
export class ReplicationController extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
ReplicationControllerStatus,
|
||||
ReplicationControllerSpec
|
||||
> {
|
||||
static kind = "ReplicationController";
|
||||
static namespaced = true;
|
||||
static apiBase = "/api/v1/replicationcontrollers";
|
||||
|
||||
getMinReadySeconds(): number {
|
||||
return this.spec?.minReadySeconds ?? 0;
|
||||
}
|
||||
|
||||
getGeneration() {
|
||||
return this.status?.observedGeneration;
|
||||
}
|
||||
|
||||
getSelectorLabels(): string[] {
|
||||
return KubeObject.stringifyLabels(this.spec.selector);
|
||||
}
|
||||
|
||||
getReplicas(): number | undefined {
|
||||
return this.status?.replicas;
|
||||
}
|
||||
|
||||
getDesiredReplicas(): number {
|
||||
return this.spec?.replicas ?? 0;
|
||||
}
|
||||
|
||||
getAvailableReplicas(): number | undefined {
|
||||
return this.status?.availableReplicas;
|
||||
}
|
||||
|
||||
getLabeledReplicas(): number | undefined {
|
||||
return this.status?.fullyLabeledReplicas;
|
||||
}
|
||||
|
||||
getConditions(): BaseKubeObjectCondition[] {
|
||||
return this.status?.conditions ?? [];
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -6,7 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { Patch } from "rfc6902";
|
||||
import apiBaseInjectable from "../../api-base.injectable";
|
||||
import type { AsyncResult, Result } from "@k8slens/utilities";
|
||||
import type { KubeJsonApiData } from "../../kube-json-api";
|
||||
import type { KubeJsonApiData } from "@k8slens/kube-object";
|
||||
|
||||
export type RequestKubeObjectPatch = (name: string, kind: string, ns: string | undefined, patch: Patch) => AsyncResult<KubeJsonApiData, string>;
|
||||
|
||||
@@ -16,21 +16,21 @@ const requestKubeObjectPatchInjectable = getInjectable({
|
||||
const apiBase = di.inject(apiBaseInjectable);
|
||||
|
||||
return async (name, kind, ns, patch) => {
|
||||
const result = await apiBase.patch("/stack", {
|
||||
const result = (await apiBase.patch("/stack", {
|
||||
data: {
|
||||
name,
|
||||
kind,
|
||||
ns,
|
||||
patch,
|
||||
},
|
||||
}) as Result<string, string>;
|
||||
})) as Result<string, string>;
|
||||
|
||||
if (!result.callWasSuccessful) {
|
||||
return result;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = JSON.parse(result.response);
|
||||
const response = JSON.parse(result.response) as KubeJsonApiData;
|
||||
|
||||
return {
|
||||
callWasSuccessful: true,
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import apiBaseInjectable from "../../api-base.injectable";
|
||||
import type { AsyncResult, Result } from "@k8slens/utilities";
|
||||
import type { KubeJsonApiData } from "../../kube-json-api";
|
||||
import type { KubeJsonApiData } from "@k8slens/kube-object";
|
||||
|
||||
export type RequestKubeObjectCreation = (resourceDescriptor: string) => AsyncResult<KubeJsonApiData, string>;
|
||||
|
||||
|
||||
@@ -3,67 +3,10 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { NamespaceScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { ResourceQuota } from "@k8slens/kube-object";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
|
||||
export type IResourceQuotaValues = Partial<Record<string, string>> & {
|
||||
// Compute Resource Quota
|
||||
"limits.cpu"?: string;
|
||||
"limits.memory"?: string;
|
||||
"requests.cpu"?: string;
|
||||
"requests.memory"?: string;
|
||||
|
||||
// Storage Resource Quota
|
||||
"requests.storage"?: string;
|
||||
"persistentvolumeclaims"?: string;
|
||||
|
||||
// Object Count Quota
|
||||
"count/pods"?: string;
|
||||
"count/persistentvolumeclaims"?: string;
|
||||
"count/services"?: string;
|
||||
"count/secrets"?: string;
|
||||
"count/configmaps"?: string;
|
||||
"count/replicationcontrollers"?: string;
|
||||
"count/deployments.apps"?: string;
|
||||
"count/replicasets.apps"?: string;
|
||||
"count/statefulsets.apps"?: string;
|
||||
"count/jobs.batch"?: string;
|
||||
"count/cronjobs.batch"?: string;
|
||||
"count/deployments.extensions"?: string;
|
||||
};
|
||||
|
||||
export interface ResourceQuotaSpec {
|
||||
hard: IResourceQuotaValues;
|
||||
scopeSelector?: {
|
||||
matchExpressions: {
|
||||
operator: string;
|
||||
scopeName: string;
|
||||
values: string[];
|
||||
}[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface ResourceQuotaStatus {
|
||||
hard: IResourceQuotaValues;
|
||||
used: IResourceQuotaValues;
|
||||
}
|
||||
|
||||
export class ResourceQuota extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
ResourceQuotaStatus,
|
||||
ResourceQuotaSpec
|
||||
> {
|
||||
static readonly kind = "ResourceQuota";
|
||||
static readonly namespaced = true;
|
||||
static readonly apiBase = "/api/v1/resourcequotas";
|
||||
|
||||
getScopeSelector() {
|
||||
return this.spec.scopeSelector?.matchExpressions ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
export class ResourceQuotaApi extends KubeApi<ResourceQuota> {
|
||||
constructor(deps: KubeApiDependencies, opts: DerivedKubeApiOptions = {}) {
|
||||
super(deps, {
|
||||
|
||||
@@ -3,45 +3,11 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { KubeObjectMetadata, KubeObjectScope, NamespaceScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { RoleBindingData } from "@k8slens/kube-object";
|
||||
import { RoleBinding } from "@k8slens/kube-object";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import type { RoleRef } from "./types/role-ref";
|
||||
import type { Subject } from "./types/subject";
|
||||
|
||||
export interface RoleBindingData extends KubeJsonApiData<KubeObjectMetadata<KubeObjectScope.Namespace>, void, void> {
|
||||
subjects?: Subject[];
|
||||
roleRef: RoleRef;
|
||||
}
|
||||
|
||||
export class RoleBinding extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
void,
|
||||
void
|
||||
> {
|
||||
static readonly kind = "RoleBinding";
|
||||
static readonly namespaced = true;
|
||||
static readonly apiBase = "/apis/rbac.authorization.k8s.io/v1/rolebindings";
|
||||
|
||||
subjects?: Subject[];
|
||||
roleRef: RoleRef;
|
||||
|
||||
constructor({ subjects, roleRef, ...rest }: RoleBindingData) {
|
||||
super(rest);
|
||||
this.subjects = subjects;
|
||||
this.roleRef = roleRef;
|
||||
}
|
||||
|
||||
getSubjects() {
|
||||
return this.subjects || [];
|
||||
}
|
||||
|
||||
getSubjectNames(): string {
|
||||
return this.getSubjects().map(subject => subject.name).join(", ");
|
||||
}
|
||||
}
|
||||
|
||||
export class RoleBindingApi extends KubeApi<RoleBinding, RoleBindingData> {
|
||||
constructor(deps: KubeApiDependencies, opts: DerivedKubeApiOptions = {}) {
|
||||
|
||||
@@ -3,36 +3,10 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { KubeObjectMetadata, KubeObjectScope, NamespaceScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { RoleData } from "@k8slens/kube-object";
|
||||
import { Role } from "@k8slens/kube-object";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import type { PolicyRule } from "./types/policy-rule";
|
||||
|
||||
export interface RoleData extends KubeJsonApiData<KubeObjectMetadata<KubeObjectScope.Namespace>, void, void> {
|
||||
rules?: PolicyRule[];
|
||||
}
|
||||
|
||||
export class Role extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
void,
|
||||
void
|
||||
> {
|
||||
static readonly kind = "Role";
|
||||
static readonly namespaced = true;
|
||||
static readonly apiBase = "/apis/rbac.authorization.k8s.io/v1/roles";
|
||||
rules?: PolicyRule[];
|
||||
|
||||
constructor({ rules, ...rest }: RoleData) {
|
||||
super(rest);
|
||||
this.rules = rules;
|
||||
}
|
||||
|
||||
getRules() {
|
||||
return this.rules || [];
|
||||
}
|
||||
}
|
||||
|
||||
export class RoleApi extends KubeApi<Role, RoleData> {
|
||||
constructor(deps: KubeApiDependencies, opts: DerivedKubeApiOptions = {}) {
|
||||
|
||||
@@ -5,62 +5,8 @@
|
||||
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import type { ClusterScopedMetadata, KubeObjectMetadata, KubeObjectScope, Toleration } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
|
||||
export interface RuntimeClassData extends KubeJsonApiData<KubeObjectMetadata<KubeObjectScope.Cluster>, void, void> {
|
||||
handler: string;
|
||||
overhead?: RuntimeClassOverhead;
|
||||
scheduling?: RuntimeClassScheduling;
|
||||
}
|
||||
|
||||
export interface RuntimeClassOverhead {
|
||||
podFixed?: string;
|
||||
}
|
||||
|
||||
export interface RuntimeClassScheduling {
|
||||
nodeSelector?: Partial<Record<string, string>>;
|
||||
tolerations?: Toleration[];
|
||||
}
|
||||
|
||||
export class RuntimeClass extends KubeObject<
|
||||
ClusterScopedMetadata,
|
||||
void,
|
||||
void
|
||||
> {
|
||||
static readonly kind = "RuntimeClass";
|
||||
static readonly namespaced = false;
|
||||
static readonly apiBase = "/apis/node.k8s.io/v1/runtimeclasses";
|
||||
|
||||
handler: string;
|
||||
overhead?: RuntimeClassOverhead;
|
||||
scheduling?: RuntimeClassScheduling;
|
||||
|
||||
constructor({ handler, overhead, scheduling, ...rest }: RuntimeClassData) {
|
||||
super(rest);
|
||||
this.handler = handler;
|
||||
this.overhead = overhead;
|
||||
this.scheduling = scheduling;
|
||||
}
|
||||
|
||||
getHandler() {
|
||||
return this.handler;
|
||||
}
|
||||
|
||||
getPodFixed() {
|
||||
return this.overhead?.podFixed ?? "";
|
||||
}
|
||||
|
||||
getNodeSelectors(): string[] {
|
||||
return Object.entries(this.scheduling?.nodeSelector ?? {})
|
||||
.map(values => values.join(": "));
|
||||
}
|
||||
|
||||
getTolerations() {
|
||||
return this.scheduling?.tolerations ?? [];
|
||||
}
|
||||
}
|
||||
import type { RuntimeClassData } from "@k8slens/kube-object";
|
||||
import { RuntimeClass } from "@k8slens/kube-object";
|
||||
|
||||
export class RuntimeClassApi extends KubeApi<RuntimeClass, RuntimeClassData> {
|
||||
constructor(deps: KubeApiDependencies, opts: DerivedKubeApiOptions = {}) {
|
||||
|
||||
@@ -3,73 +3,10 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { KubeObjectMetadata, KubeObjectScope, NamespaceScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import autoBind from "auto-bind";
|
||||
|
||||
export enum SecretType {
|
||||
Opaque = "Opaque",
|
||||
ServiceAccountToken = "kubernetes.io/service-account-token",
|
||||
Dockercfg = "kubernetes.io/dockercfg",
|
||||
DockerConfigJson = "kubernetes.io/dockerconfigjson",
|
||||
BasicAuth = "kubernetes.io/basic-auth",
|
||||
SSHAuth = "kubernetes.io/ssh-auth",
|
||||
TLS = "kubernetes.io/tls",
|
||||
BootstrapToken = "bootstrap.kubernetes.io/token",
|
||||
}
|
||||
|
||||
export const reverseSecretTypeMap = {
|
||||
[SecretType.Opaque]: "Opaque",
|
||||
[SecretType.ServiceAccountToken]: "ServiceAccountToken",
|
||||
[SecretType.Dockercfg]: "Dockercfg",
|
||||
[SecretType.DockerConfigJson]: "DockerConfigJson",
|
||||
[SecretType.BasicAuth]: "BasicAuth",
|
||||
[SecretType.SSHAuth]: "SSHAuth",
|
||||
[SecretType.TLS]: "TLS",
|
||||
[SecretType.BootstrapToken]: "BootstrapToken",
|
||||
};
|
||||
|
||||
export interface SecretReference {
|
||||
name: string;
|
||||
namespace?: string;
|
||||
}
|
||||
|
||||
export interface SecretData extends KubeJsonApiData<KubeObjectMetadata<KubeObjectScope.Namespace>, void, void> {
|
||||
type: SecretType;
|
||||
data?: Partial<Record<string, string>>;
|
||||
}
|
||||
|
||||
export class Secret extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
void,
|
||||
void
|
||||
> {
|
||||
static readonly kind = "Secret";
|
||||
static readonly namespaced = true;
|
||||
static readonly apiBase = "/api/v1/secrets";
|
||||
|
||||
type: SecretType;
|
||||
data: Partial<Record<string, string>>;
|
||||
|
||||
constructor({ data = {}, type, ...rest }: SecretData) {
|
||||
super(rest);
|
||||
autoBind(this);
|
||||
|
||||
this.data = data;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
getKeys(): string[] {
|
||||
return Object.keys(this.data);
|
||||
}
|
||||
|
||||
getToken() {
|
||||
return this.data.token;
|
||||
}
|
||||
}
|
||||
import { Secret } from "@k8slens/kube-object";
|
||||
import type { SecretData } from "@k8slens/kube-object";
|
||||
|
||||
export class SecretApi extends KubeApi<Secret, SecretData> {
|
||||
constructor(deps: KubeApiDependencies, options: DerivedKubeApiOptions = {}) {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { SelfSubjectRulesReview } from "@k8slens/kube-object";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
|
||||
@@ -23,58 +23,3 @@ export class SelfSubjectRulesReviewApi extends KubeApi<SelfSubjectRulesReview> {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export interface ISelfSubjectReviewRule {
|
||||
verbs: string[];
|
||||
apiGroups?: string[];
|
||||
resources?: string[];
|
||||
resourceNames?: string[];
|
||||
nonResourceURLs?: string[];
|
||||
}
|
||||
|
||||
export interface SelfSubjectRulesReview {
|
||||
spec: {
|
||||
namespace?: string;
|
||||
};
|
||||
status: {
|
||||
resourceRules: ISelfSubjectReviewRule[];
|
||||
nonResourceRules: ISelfSubjectReviewRule[];
|
||||
incomplete: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export class SelfSubjectRulesReview extends KubeObject {
|
||||
static kind = "SelfSubjectRulesReview";
|
||||
static namespaced = false;
|
||||
static apiBase = "/apis/authorization.k8s.io/v1/selfsubjectrulesreviews";
|
||||
|
||||
getResourceRules() {
|
||||
const rules = this.status && this.status.resourceRules || [];
|
||||
|
||||
return rules.map(rule => this.normalize(rule));
|
||||
}
|
||||
|
||||
getNonResourceRules() {
|
||||
const rules = this.status && this.status.nonResourceRules || [];
|
||||
|
||||
return rules.map(rule => this.normalize(rule));
|
||||
}
|
||||
|
||||
protected normalize(rule: ISelfSubjectReviewRule): ISelfSubjectReviewRule {
|
||||
const { apiGroups = [], resourceNames = [], verbs = [], nonResourceURLs = [], resources = [] } = rule;
|
||||
|
||||
return {
|
||||
apiGroups,
|
||||
nonResourceURLs,
|
||||
resourceNames,
|
||||
verbs,
|
||||
resources: resources.map((resource, index) => {
|
||||
const apiGroup = apiGroups.length >= index + 1 ? apiGroups[index] : apiGroups.slice(-1)[0];
|
||||
const separator = apiGroup == "" ? "" : ".";
|
||||
|
||||
return resource + separator + apiGroup;
|
||||
}),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,51 +3,10 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { KubeObjectMetadata, KubeObjectScope, LocalObjectReference, NamespaceScopedMetadata, ObjectReference } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { ServiceAccountData } from "@k8slens/kube-object";
|
||||
import { ServiceAccount } from "@k8slens/kube-object";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
|
||||
export interface ServiceAccountData extends KubeJsonApiData<KubeObjectMetadata<KubeObjectScope.Namespace>, void, void> {
|
||||
automountServiceAccountToken?: boolean;
|
||||
imagePullSecrets?: LocalObjectReference[];
|
||||
secrets?: ObjectReference[];
|
||||
}
|
||||
|
||||
export class ServiceAccount extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
void,
|
||||
void
|
||||
> {
|
||||
static readonly kind = "ServiceAccount";
|
||||
static readonly namespaced = true;
|
||||
static readonly apiBase = "/api/v1/serviceaccounts";
|
||||
|
||||
automountServiceAccountToken?: boolean;
|
||||
imagePullSecrets?: LocalObjectReference[];
|
||||
secrets?: ObjectReference[];
|
||||
|
||||
constructor({
|
||||
automountServiceAccountToken,
|
||||
imagePullSecrets,
|
||||
secrets,
|
||||
...rest
|
||||
}: ServiceAccountData) {
|
||||
super(rest);
|
||||
this.automountServiceAccountToken = automountServiceAccountToken;
|
||||
this.imagePullSecrets = imagePullSecrets;
|
||||
this.secrets = secrets;
|
||||
}
|
||||
|
||||
getSecrets() {
|
||||
return this.secrets || [];
|
||||
}
|
||||
|
||||
getImagePullSecrets() {
|
||||
return this.imagePullSecrets || [];
|
||||
}
|
||||
}
|
||||
|
||||
export class ServiceAccountApi extends KubeApi<ServiceAccount, ServiceAccountData> {
|
||||
constructor(deps: KubeApiDependencies, opts: DerivedKubeApiOptions = {}) {
|
||||
|
||||
@@ -3,131 +3,10 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { NamespaceScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import { Service } from "@k8slens/kube-object";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
|
||||
export interface ServicePort {
|
||||
name?: string;
|
||||
protocol: string;
|
||||
port: number;
|
||||
targetPort: number;
|
||||
nodePort?: number;
|
||||
}
|
||||
|
||||
export class ServicePort {
|
||||
constructor(data: ServicePort) {
|
||||
Object.assign(this, data);
|
||||
}
|
||||
|
||||
toString() {
|
||||
if (this.nodePort) {
|
||||
return `${this.port}:${this.nodePort}/${this.protocol}`;
|
||||
} else {
|
||||
return `${this.port}${this.port === this.targetPort ? "" : `:${this.targetPort}`}/${this.protocol}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface ServiceSpec {
|
||||
type: string;
|
||||
clusterIP: string;
|
||||
clusterIPs?: string[];
|
||||
externalTrafficPolicy?: string;
|
||||
externalName?: string;
|
||||
loadBalancerIP?: string;
|
||||
loadBalancerSourceRanges?: string[];
|
||||
sessionAffinity: string;
|
||||
selector: Partial<Record<string, string>>;
|
||||
ports: ServicePort[];
|
||||
healthCheckNodePort?: number;
|
||||
externalIPs?: string[]; // https://kubernetes.io/docs/concepts/services-networking/service/#external-ips
|
||||
topologyKeys?: string[];
|
||||
ipFamilies?: string[];
|
||||
ipFamilyPolicy?: string;
|
||||
allocateLoadBalancerNodePorts?: boolean;
|
||||
loadBalancerClass?: string;
|
||||
internalTrafficPolicy?: string;
|
||||
}
|
||||
|
||||
export interface ServiceStatus {
|
||||
loadBalancer?: {
|
||||
ingress?: {
|
||||
ip?: string;
|
||||
hostname?: string;
|
||||
}[];
|
||||
};
|
||||
}
|
||||
|
||||
export class Service extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
ServiceStatus,
|
||||
ServiceSpec
|
||||
> {
|
||||
static readonly kind = "Service";
|
||||
static readonly namespaced = true;
|
||||
static readonly apiBase = "/api/v1/services";
|
||||
|
||||
getClusterIp() {
|
||||
return this.spec.clusterIP;
|
||||
}
|
||||
|
||||
getClusterIps() {
|
||||
return this.spec.clusterIPs || [];
|
||||
}
|
||||
|
||||
getExternalIps() {
|
||||
const lb = this.getLoadBalancer();
|
||||
|
||||
if (lb?.ingress) {
|
||||
return lb.ingress.map(val => val.ip || val.hostname);
|
||||
}
|
||||
|
||||
if (Array.isArray(this.spec?.externalIPs)) {
|
||||
return this.spec.externalIPs;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
getType() {
|
||||
return this.spec.type || "-";
|
||||
}
|
||||
|
||||
getSelector(): string[] {
|
||||
if (!this.spec.selector) return [];
|
||||
|
||||
return Object.entries(this.spec.selector).map(val => val.join("="));
|
||||
}
|
||||
|
||||
getPorts(): ServicePort[] {
|
||||
const ports = this.spec.ports || [];
|
||||
|
||||
return ports.map(p => new ServicePort(p));
|
||||
}
|
||||
|
||||
getLoadBalancer() {
|
||||
return this.status?.loadBalancer;
|
||||
}
|
||||
|
||||
isActive() {
|
||||
return this.getType() !== "LoadBalancer" || this.getExternalIps().length > 0;
|
||||
}
|
||||
|
||||
getStatus() {
|
||||
return this.isActive() ? "Active" : "Pending";
|
||||
}
|
||||
|
||||
getIpFamilies() {
|
||||
return this.spec.ipFamilies || [];
|
||||
}
|
||||
|
||||
getIpFamilyPolicy() {
|
||||
return this.spec.ipFamilyPolicy || "";
|
||||
}
|
||||
}
|
||||
|
||||
export class ServiceApi extends KubeApi<Service> {
|
||||
constructor(deps: KubeApiDependencies, opts: DerivedKubeApiOptions = {}) {
|
||||
super(deps, {
|
||||
|
||||
@@ -5,12 +5,9 @@
|
||||
|
||||
import moment from "moment";
|
||||
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies, NamespacedResourceDescriptor } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { LabelSelector, NamespaceScopedMetadata } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { PodTemplateSpec } from "./types/pod-template-spec";
|
||||
import type { PersistentVolumeClaimTemplateSpec } from "./types/persistent-volume-claim-template-spec";
|
||||
import { StatefulSet } from "@k8slens/kube-object";
|
||||
|
||||
export class StatefulSetApi extends KubeApi<StatefulSet> {
|
||||
constructor(deps: KubeApiDependencies, opts?: DerivedKubeApiOptions) {
|
||||
@@ -20,109 +17,34 @@ export class StatefulSetApi extends KubeApi<StatefulSet> {
|
||||
});
|
||||
}
|
||||
|
||||
protected getScaleApiUrl(params: { namespace: string; name: string }) {
|
||||
return `${this.getUrl(params)}/scale`;
|
||||
protected getScaleApiUrl(params: NamespacedResourceDescriptor) {
|
||||
return `${this.formatUrlForNotListing(params)}/scale`;
|
||||
}
|
||||
|
||||
getReplicas(params: { namespace: string; name: string }): Promise<number> {
|
||||
return this.request
|
||||
.get(this.getScaleApiUrl(params))
|
||||
.then(({ status }: any) => status?.replicas);
|
||||
async getReplicas(params: NamespacedResourceDescriptor): Promise<number> {
|
||||
const apiUrl = this.getScaleApiUrl(params);
|
||||
const { status = 0 } = await this.request.get(apiUrl) as { status?: number };
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
scale(params: { namespace: string; name: string }, replicas: number) {
|
||||
return this.request.patch(this.getScaleApiUrl(params), {
|
||||
data: {
|
||||
spec: {
|
||||
replicas,
|
||||
},
|
||||
scale(params: NamespacedResourceDescriptor, replicas: number) {
|
||||
return this.patch(params, {
|
||||
spec: {
|
||||
replicas,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"content-type": "application/merge-patch+json",
|
||||
},
|
||||
});
|
||||
}, "merge");
|
||||
}
|
||||
|
||||
restart(params: { namespace: string; name: string }) {
|
||||
return this.request.patch(this.getUrl(params), {
|
||||
data: {
|
||||
spec: {
|
||||
template: {
|
||||
metadata: {
|
||||
annotations: { "kubectl.kubernetes.io/restartedAt" : moment.utc().format() },
|
||||
},
|
||||
restart(params: NamespacedResourceDescriptor) {
|
||||
return this.patch(params, {
|
||||
spec: {
|
||||
template: {
|
||||
metadata: {
|
||||
annotations: { "kubectl.kubernetes.io/restartedAt" : moment.utc().format() },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"content-type": "application/strategic-merge-patch+json",
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export interface StatefulSetSpec {
|
||||
serviceName: string;
|
||||
replicas: number;
|
||||
selector: LabelSelector;
|
||||
template: PodTemplateSpec;
|
||||
volumeClaimTemplates: PersistentVolumeClaimTemplateSpec[];
|
||||
}
|
||||
|
||||
export interface StatefulSetStatus {
|
||||
observedGeneration: number;
|
||||
replicas: number;
|
||||
currentReplicas: number;
|
||||
readyReplicas: number;
|
||||
currentRevision: string;
|
||||
updateRevision: string;
|
||||
collisionCount: number;
|
||||
}
|
||||
|
||||
export class StatefulSet extends KubeObject<
|
||||
NamespaceScopedMetadata,
|
||||
StatefulSetStatus,
|
||||
StatefulSetSpec
|
||||
> {
|
||||
static readonly kind = "StatefulSet";
|
||||
static readonly namespaced = true;
|
||||
static readonly apiBase = "/apis/apps/v1/statefulsets";
|
||||
|
||||
getSelectors(): string[] {
|
||||
return KubeObject.stringifyLabels(this.spec.selector.matchLabels);
|
||||
}
|
||||
|
||||
getNodeSelectors(): string[] {
|
||||
return KubeObject.stringifyLabels(this.spec.template.spec?.nodeSelector);
|
||||
}
|
||||
|
||||
getTemplateLabels(): string[] {
|
||||
return KubeObject.stringifyLabels(this.spec.template.metadata?.labels);
|
||||
}
|
||||
|
||||
getTolerations() {
|
||||
return this.spec.template.spec?.tolerations ?? [];
|
||||
}
|
||||
|
||||
getAffinity() {
|
||||
return this.spec.template.spec?.affinity ?? {};
|
||||
}
|
||||
|
||||
getAffinityNumber() {
|
||||
return Object.keys(this.getAffinity()).length;
|
||||
}
|
||||
|
||||
getReplicas() {
|
||||
return this.spec.replicas || 0;
|
||||
}
|
||||
|
||||
getImages() {
|
||||
const containers = this.spec.template?.spec?.containers ?? [];
|
||||
|
||||
return containers.map(container => container.image);
|
||||
}, "strategic");
|
||||
}
|
||||
}
|
||||
@@ -3,87 +3,11 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { ClusterScopedMetadata, KubeObjectMetadata, KubeObjectScope } from "../kube-object";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { StorageClassData } from "@k8slens/kube-object";
|
||||
import { StorageClass } from "@k8slens/kube-object";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import type { KubeJsonApiData } from "../kube-json-api";
|
||||
import autoBind from "auto-bind";
|
||||
|
||||
export interface TopologySelectorLabelRequirement {
|
||||
key: string;
|
||||
values: string[];
|
||||
}
|
||||
|
||||
export interface TopologySelectorTerm {
|
||||
matchLabelExpressions?: TopologySelectorLabelRequirement[];
|
||||
}
|
||||
|
||||
export interface StorageClassData extends KubeJsonApiData<KubeObjectMetadata<KubeObjectScope.Cluster>, void, void> {
|
||||
allowVolumeExpansion?: boolean;
|
||||
allowedTopologies?: TopologySelectorTerm[];
|
||||
mountOptions?: string[];
|
||||
parameters?: Partial<Record<string, string>>;
|
||||
provisioner: string;
|
||||
reclaimPolicy?: string;
|
||||
volumeBindingMode?: string;
|
||||
}
|
||||
|
||||
export class StorageClass extends KubeObject<
|
||||
ClusterScopedMetadata,
|
||||
void,
|
||||
void
|
||||
> {
|
||||
static readonly kind = "StorageClass";
|
||||
static readonly namespaced = false;
|
||||
static readonly apiBase = "/apis/storage.k8s.io/v1/storageclasses";
|
||||
|
||||
allowVolumeExpansion?: boolean;
|
||||
allowedTopologies: TopologySelectorTerm[];
|
||||
mountOptions: string[];
|
||||
parameters: Partial<Record<string, string>>;
|
||||
provisioner: string;
|
||||
reclaimPolicy: string;
|
||||
volumeBindingMode?: string;
|
||||
|
||||
constructor({
|
||||
allowVolumeExpansion,
|
||||
allowedTopologies = [],
|
||||
mountOptions = [],
|
||||
parameters = {},
|
||||
provisioner,
|
||||
reclaimPolicy = "Delete",
|
||||
volumeBindingMode,
|
||||
...rest
|
||||
}: StorageClassData) {
|
||||
super(rest);
|
||||
autoBind(this);
|
||||
this.allowVolumeExpansion = allowVolumeExpansion;
|
||||
this.allowedTopologies = allowedTopologies;
|
||||
this.mountOptions = mountOptions;
|
||||
this.parameters = parameters;
|
||||
this.provisioner = provisioner;
|
||||
this.reclaimPolicy = reclaimPolicy;
|
||||
this.volumeBindingMode = volumeBindingMode;
|
||||
}
|
||||
|
||||
isDefault() {
|
||||
const annotations = this.metadata.annotations || {};
|
||||
|
||||
return (
|
||||
annotations["storageclass.kubernetes.io/is-default-class"] === "true" ||
|
||||
annotations["storageclass.beta.kubernetes.io/is-default-class"] === "true"
|
||||
);
|
||||
}
|
||||
|
||||
getVolumeBindingMode() {
|
||||
return this.volumeBindingMode || "-";
|
||||
}
|
||||
|
||||
getReclaimPolicy() {
|
||||
return this.reclaimPolicy || "-";
|
||||
}
|
||||
}
|
||||
|
||||
export class StorageClassApi extends KubeApi<StorageClass, StorageClassData> {
|
||||
constructor(deps: KubeApiDependencies, opts: DerivedKubeApiOptions = {}) {
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { LabelSelector } from "../../kube-object";
|
||||
|
||||
export interface AggregationRule {
|
||||
clusterRoleSelectors?: LabelSelector;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adds and removes POSIX capabilities from running containers.
|
||||
*/
|
||||
export interface Capabilities {
|
||||
/**
|
||||
* Added capabilities
|
||||
*/
|
||||
add?: string[];
|
||||
|
||||
/**
|
||||
* Removed capabilities
|
||||
*/
|
||||
drop?: string[];
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
export interface Condition {
|
||||
lastTransitionTime: string;
|
||||
message: string;
|
||||
observedGeneration?: number;
|
||||
reason: string;
|
||||
status: string;
|
||||
type: string;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
export interface ContainerPort {
|
||||
containerPort: number;
|
||||
hostIP?: string;
|
||||
hostPort?: number;
|
||||
name?: string;
|
||||
protocol?: "UDP" | "TCP" | "SCTP";
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { Lifecycle } from "./lifecycle";
|
||||
import type { ResourceRequirements } from "./resource-requirements";
|
||||
import type { SecurityContext } from "./security-context";
|
||||
import type { Probe } from "./probe";
|
||||
import type { VolumeDevice } from "./volume-device";
|
||||
import type { VolumeMount } from "./volume-mount";
|
||||
import type { ContainerPort } from "./container-port";
|
||||
import type { EnvFromSource } from "./env-from-source";
|
||||
import type { EnvVar } from "./env-var";
|
||||
|
||||
/**
|
||||
* A single application container that you want to run within a pod.
|
||||
*/
|
||||
export interface Container {
|
||||
/**
|
||||
* Arguments to the entrypoint. The docker image's CMD is used if this is not provided. Variable
|
||||
* references `$(VAR_NAME)` are expanded using the container's environment.
|
||||
*
|
||||
* If a variable cannot be resolved, the reference in the input string will be unchanged.
|
||||
* Double `$$` are reduced to a single `$`, which allows for escaping the `$(VAR_NAME)` syntax:
|
||||
* i.e. `"$$(VAR_NAME)"` will produce the string literal `"$(VAR_NAME)`".
|
||||
*
|
||||
* Escaped references will never be expanded, regardless of whether the variable exists or not.
|
||||
* Cannot be updated.
|
||||
*
|
||||
* More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell
|
||||
*/
|
||||
args?: string[];
|
||||
|
||||
/**
|
||||
* Entrypoint array. Not executed within a shell. The docker image's ENTRYPOINT is used if this
|
||||
* is not provided. Variable references `$(VAR_NAME)` are expanded using the container's
|
||||
* environment.
|
||||
*
|
||||
* If a variable cannot be resolved, the reference in the input string will be unchanged.
|
||||
* Double `$$` are reduced to a single `$`, which allows for escaping the `$(VAR_NAME)` syntax:
|
||||
* i.e. `"$$(VAR_NAME)"` will produce the string literal `"$(VAR_NAME)`".
|
||||
*
|
||||
* Escaped references will never be expanded, regardless of whether the variable exists or not.
|
||||
* Cannot be updated.
|
||||
*
|
||||
* More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell
|
||||
*/
|
||||
command?: string[];
|
||||
|
||||
/**
|
||||
* List of environment variables to set in the container. Cannot be updated.
|
||||
*/
|
||||
env?: EnvVar[];
|
||||
|
||||
/**
|
||||
* List of sources to populate environment variables in the container. The keys defined within a
|
||||
* source must be a C_IDENTIFIER. All invalid keys will be reported as an event when the
|
||||
* container is starting.
|
||||
*
|
||||
* When a key exists in multiple sources, the value associated with the last source will take
|
||||
* precedence. Values defined by an Env with a duplicate key will take precedence. Cannot be
|
||||
* updated.
|
||||
*/
|
||||
envFrom?: EnvFromSource[];
|
||||
|
||||
/**
|
||||
* Docker image name.
|
||||
*
|
||||
* More info: https://kubernetes.io/docs/concepts/containers/images
|
||||
*/
|
||||
image?: string;
|
||||
|
||||
/**
|
||||
* Image pull policy. Defaults to `"Always"` if :latest tag is specified, or `"IfNotPresent"`
|
||||
* otherwise. Cannot be updated.
|
||||
*
|
||||
* More info: https://kubernetes.io/docs/concepts/containers/images#updating-images
|
||||
*/
|
||||
imagePullPolicy?: "Always" | "Never" | "IfNotPresent";
|
||||
|
||||
lifecycle?: Lifecycle;
|
||||
livenessProbe?: Probe;
|
||||
|
||||
/**
|
||||
* Name of the container specified as a DNS_LABEL. Each container in a pod must have a unique
|
||||
* name. Cannot be updated.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* List of ports to expose from the container. Exposing a port here gives the system additional
|
||||
* information about the network connections a container uses, but is primarily informational.
|
||||
* Not specifying a port here DOES NOT prevent that port from being exposed. Any port which is
|
||||
* listening on the default `"0.0.0.0"` address inside a container will be accessible from the
|
||||
* network. Cannot be updated.
|
||||
*/
|
||||
ports?: ContainerPort[];
|
||||
|
||||
readinessProbe?: Probe;
|
||||
resources?: ResourceRequirements;
|
||||
securityContext?: SecurityContext;
|
||||
startupProbe?: Probe;
|
||||
|
||||
/**
|
||||
* Whether this container should allocate a buffer for stdin in the container runtime. If this is
|
||||
* not set, reads from stdin in the container will always result in EOF.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
stdin?: boolean;
|
||||
|
||||
/**
|
||||
* Whether the container runtime should close the stdin channel after it has been opened by a
|
||||
* single attach. When stdin is true the stdin stream will remain open across multiple attach
|
||||
* sessions.
|
||||
*
|
||||
* If stdinOnce is set to true, stdin is opened on container start, is empty until the first
|
||||
* client attaches to stdin, and then remains open and accepts data until the client disconnects,
|
||||
* at which time stdin is closed and remains closed until the container is restarted.
|
||||
*
|
||||
* If this flag is false, a container processes that reads from stdin will never receive an EOF.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
stdinOnce?: boolean;
|
||||
|
||||
/**
|
||||
* Path at which the file to which the container's termination message will be written
|
||||
* is mounted into the container's filesystem. Message written is intended to be brief final
|
||||
* status, such as an assertion failure message.
|
||||
*
|
||||
* Will be truncated by the node if greater than 4096 bytes.
|
||||
* The total message length across all containers will be limited to 12kb. Cannot be updated.
|
||||
*
|
||||
* @default "/dev/termination-log"
|
||||
*/
|
||||
terminationMessagePath?: string;
|
||||
|
||||
/**
|
||||
* Indicate how the termination message should be populated.
|
||||
*
|
||||
* - `File`: will use the contents of {@link terminationMessagePath} to populate the container
|
||||
* status message on both success and failure.
|
||||
*
|
||||
* - `FallbackToLogsOnError`: will use the last chunk of container log output if the
|
||||
* termination message file is empty and the container exited with an error.
|
||||
*
|
||||
* The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Cannot be updated.
|
||||
*
|
||||
* @default "File"
|
||||
*/
|
||||
terminationMessagePolicy?: "File" | "FallbackToLogsOnError";
|
||||
|
||||
/**
|
||||
* Whether this container should allocate a TTY for itself, also requires 'stdin' to be true.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
tty?: boolean;
|
||||
|
||||
/**
|
||||
* volumeDevices is the list of block devices to be used by the container.
|
||||
*/
|
||||
volumeDevices?: VolumeDevice[];
|
||||
|
||||
/**
|
||||
* Pod volumes to mount into the container's filesystem. Cannot be updated.
|
||||
*/
|
||||
volumeMounts?: VolumeMount[];
|
||||
|
||||
/**
|
||||
* Container's working directory. If not specified, the container runtime's default will be used,
|
||||
* which might be configured in the container image. Cannot be updated.
|
||||
*/
|
||||
workingDir?: string;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
export interface CrossVersionObjectReference {
|
||||
kind: string;
|
||||
name: string;
|
||||
apiVersion: string;
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { EnvSource } from "./env-source";
|
||||
|
||||
export interface EnvFromSource {
|
||||
configMapRef?: EnvSource;
|
||||
/**
|
||||
* An identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER.
|
||||
*/
|
||||
prefix?: string;
|
||||
secretRef?: EnvSource;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { LocalObjectReference } from "../../kube-object";
|
||||
|
||||
export interface EnvSource extends LocalObjectReference {
|
||||
/**
|
||||
* Whether the object must be defined
|
||||
*/
|
||||
optional?: boolean;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
export interface EnvVarKeySelector {
|
||||
key: string;
|
||||
name?: string;
|
||||
optional?: boolean;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { EnvVarKeySelector } from "./env-var-key-selector";
|
||||
import type { ObjectFieldSelector } from "./object-field-selector";
|
||||
import type { ResourceFieldSelector } from "./resource-field-selector";
|
||||
|
||||
export interface EnvVarSource {
|
||||
configMapKeyRef?: EnvVarKeySelector;
|
||||
fieldRef?: ObjectFieldSelector;
|
||||
resourceFieldRef?: ResourceFieldSelector;
|
||||
secretKeyRef?: EnvVarKeySelector;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { EnvVarSource } from "./env-var-source";
|
||||
|
||||
export interface EnvVar {
|
||||
name: string;
|
||||
value?: string;
|
||||
valueFrom?: EnvVarSource;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ExecAction describes a "run in container" action.
|
||||
*/
|
||||
export interface ExecAction {
|
||||
/**
|
||||
* Command is the command line to execute inside the container, the working directory for the
|
||||
* command is root ('\\') in the container's filesystem. The command is simply exec'd, it is not
|
||||
* run inside a shell, so traditional shell instructions ('|', etc) won't work. To use a shell,
|
||||
* you need to explicitly call out to that shell.
|
||||
*
|
||||
* Exit status of 0 is treated as live/healthy and non-zero is unhealthy.
|
||||
*/
|
||||
command?: string[];
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
export interface ExternalDocumentation {
|
||||
description?: string;
|
||||
url?: string;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { ExecAction } from "./exec-action";
|
||||
import type { HttpGetAction } from "./http-get-action";
|
||||
import type { TcpSocketAction } from "./tcp-socket-action";
|
||||
|
||||
/**
|
||||
* Handler defines a specific action that should be taken.
|
||||
*/
|
||||
export interface Handler {
|
||||
exec?: ExecAction;
|
||||
httpGet?: HttpGetAction;
|
||||
tcpSocket?: TcpSocketAction;
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { HttpHeader } from "./http-header";
|
||||
|
||||
/**
|
||||
* An action based on HTTP Get requests.
|
||||
*/
|
||||
export interface HttpGetAction {
|
||||
/**
|
||||
* Host name to connect to, defaults to the pod IP. You probably want to set \"Host\" in httpHeaders instead.
|
||||
*/
|
||||
host?: string;
|
||||
|
||||
/**
|
||||
* Custom headers to set in the request. HTTP allows repeated headers.
|
||||
*/
|
||||
httpHeaders?: HttpHeader[];
|
||||
|
||||
/**
|
||||
* Path to access on the HTTP server.
|
||||
*/
|
||||
path?: string;
|
||||
|
||||
/**
|
||||
* The PORT to request from.
|
||||
*/
|
||||
port: string | number;
|
||||
|
||||
/**
|
||||
* Scheme to use for connecting to the host.
|
||||
*
|
||||
* @default "HTTP"
|
||||
*/
|
||||
scheme?: string;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A custom header to be used in HTTP probes and get actions
|
||||
*/
|
||||
export interface HttpHeader {
|
||||
/**
|
||||
* Field name
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* The value of the field
|
||||
*/
|
||||
value: string;
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
export * from "./aggregation-rule";
|
||||
export * from "./capabilities";
|
||||
export * from "./container";
|
||||
export * from "./container-port";
|
||||
export * from "./cross-version-object-reference";
|
||||
export * from "./env-from-source";
|
||||
export * from "./env-source";
|
||||
export * from "./env-var-key-selector";
|
||||
export * from "./env-var-source";
|
||||
export * from "./env-var";
|
||||
export * from "./exec-action";
|
||||
export * from "./handler";
|
||||
export * from "./http-get-action";
|
||||
export * from "./http-header";
|
||||
export * from "./job-template-spec";
|
||||
export * from "./lifecycle";
|
||||
export * from "./object-field-selector";
|
||||
export * from "./persistent-volume-claim-template-spec";
|
||||
export * from "./pod-security-context";
|
||||
export * from "./pod-template-spec";
|
||||
export * from "./policy-rule";
|
||||
export * from "./probe";
|
||||
export * from "./resource-field-selector";
|
||||
export * from "./resource-requirements";
|
||||
export * from "./role-ref";
|
||||
export * from "./se-linux-options";
|
||||
export * from "./seccomp-profile";
|
||||
export * from "./subject";
|
||||
export * from "./tcp-socket-action";
|
||||
export * from "./volume-device";
|
||||
export * from "./volume-mount";
|
||||
export * from "./windows-security-context-options";
|
||||
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { KubeObjectScope, KubeTemplateObjectMetadata } from "../../kube-object";
|
||||
import type { JobSpec } from "../job.api";
|
||||
|
||||
export interface JobTemplateSpec {
|
||||
metadata?: KubeTemplateObjectMetadata<KubeObjectScope.Namespace>;
|
||||
spec?: JobSpec;
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { JsonValue } from "type-fest";
|
||||
import type { ExternalDocumentation } from "./external-documentation";
|
||||
|
||||
export interface JSONSchemaProps {
|
||||
$ref?: string;
|
||||
$schema?: string;
|
||||
additionalItems?: JSONSchemaProps | boolean;
|
||||
additionalProperties?: JSONSchemaProps | boolean;
|
||||
allOf?: JSONSchemaProps[];
|
||||
anyOf?: JSONSchemaProps[];
|
||||
|
||||
/**
|
||||
* default is a default value for undefined object fields.
|
||||
* Defaulting is a beta feature under the CustomResourceDefaulting feature gate.
|
||||
* Defaulting requires spec.preserveUnknownFields to be false.
|
||||
*/
|
||||
_default?: object;
|
||||
|
||||
definitions?: Partial<Record<string, JSONSchemaProps>>;
|
||||
dependencies?: Partial<Record<string, object>>;
|
||||
description?: string;
|
||||
_enum?: object[];
|
||||
example?: JsonValue;
|
||||
|
||||
exclusiveMaximum?: boolean;
|
||||
exclusiveMinimum?: boolean;
|
||||
externalDocs?: ExternalDocumentation;
|
||||
|
||||
/**
|
||||
* format is an OpenAPI v3 format string.
|
||||
* Unknown formats are ignored.
|
||||
*
|
||||
* The following formats are validated:
|
||||
* - bsonobjectid: a bson object ID, i.e. a 24 characters hex string
|
||||
* - uri: an URI as parsed by Golang net/url.ParseRequestURI
|
||||
* - email: an email address as parsed by Golang net/mail.ParseAddress
|
||||
* - hostname: a valid representation for an Internet host name, as defined by RFC 1034, section 3.1 [RFC1034].
|
||||
* - ipv4: an IPv4 IP as parsed by Golang net.ParseIP
|
||||
* - ipv6: an IPv6 IP as parsed by Golang net.ParseIP
|
||||
* - cidr: a CIDR as parsed by Golang net.ParseCIDR
|
||||
* - mac: a MAC address as parsed by Golang net.ParseMAC
|
||||
* - uuid: an UUID that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$
|
||||
* - uuid3: an UUID3 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?3[0-9a-f]{3}-?[0-9a-f]{4}-?[0-9a-f]{12}$
|
||||
* - uuid4: an UUID4 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?4[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12}$
|
||||
* - uuid5: an UUID5 that allows uppercase defined by the regex (?i)^[0-9a-f]{8}-?[0-9a-f]{4}-?5[0-9a-f]{3}-?[89ab][0-9a-f]{3}-?[0-9a-f]{12}$
|
||||
* - isbn: an ISBN10 or ISBN13 number string like "0321751043" or "978-0321751041"
|
||||
* - isbn10: an ISBN10 number string like "0321751043"
|
||||
* - isbn13: an ISBN13 number string like "978-0321751041"
|
||||
* - creditcard: a credit card number defined by the regex ^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\\d{3})\\d{11})$ with any non digit characters mixed in
|
||||
* - ssn: a U.S. social security number following the regex ^\\d{3}[- ]?\\d{2}[- ]?\\d{4}$
|
||||
* - hexcolor: an hexadecimal color code like "#FFFFFF: following the regex ^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$
|
||||
* - rgbcolor: an RGB color code like rgb like "rgb(255,255,2559"
|
||||
* - byte: base64 encoded binary data
|
||||
* - password: any kind of string
|
||||
* - date: a date string like "2006-01-02" as defined by full-date in RFC3339
|
||||
* - duration: a duration string like "22 ns" as parsed by Golang time.ParseDuration or compatible with Scala duration format
|
||||
* - datetime: a date time string like "2014-12-15T19:30:20.000Z" as defined by date-time in RFC3339.
|
||||
*/
|
||||
format?: string;
|
||||
|
||||
id?: string;
|
||||
items?: JSONSchemaProps | JSONSchemaProps[];
|
||||
maxItems?: number;
|
||||
maxLength?: number;
|
||||
maxProperties?: number;
|
||||
maximum?: number;
|
||||
minItems?: number;
|
||||
minLength?: number;
|
||||
minProperties?: number;
|
||||
minimum?: number;
|
||||
multipleOf?: number;
|
||||
not?: JSONSchemaProps;
|
||||
nullable?: boolean;
|
||||
oneOf?: JSONSchemaProps[];
|
||||
pattern?: string;
|
||||
patternProperties?: Partial<Record<string, JSONSchemaProps>>;
|
||||
properties?: Partial<Record<string, JSONSchemaProps>>;
|
||||
required?: Array<string>;
|
||||
title?: string;
|
||||
type?: string;
|
||||
uniqueItems?: boolean;
|
||||
x_kubernetes_embedded_resource?: boolean;
|
||||
x_kubernetes_int_or_string?: boolean;
|
||||
x_kubernetes_list_map_keys?: string[];
|
||||
x_kubernetes_list_type?: string;
|
||||
x_kubernetes_map_type?: string;
|
||||
x_kubernetes_preserve_unknown_fields?: boolean;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { Handler } from "./handler";
|
||||
|
||||
/**
|
||||
* Lifecycle describes actions that the management system should take in response to container
|
||||
* lifecycle events. For the PostStart and PreStop lifecycle handlers, management of the container
|
||||
* blocks until the action is complete, unless the container process fails, in which case the
|
||||
* handler is aborted.
|
||||
*/
|
||||
export interface Lifecycle {
|
||||
postStart?: Handler;
|
||||
preStop?: Handler;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
export interface ObjectFieldSelector {
|
||||
apiVersion?: string;
|
||||
fieldPath: string;
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { KubeObjectScope, KubeTemplateObjectMetadata } from "../../kube-object";
|
||||
import type { PersistentVolumeSpec } from "../persistent-volume.api";
|
||||
|
||||
export interface PersistentVolumeClaimTemplateSpec {
|
||||
metadata?: KubeTemplateObjectMetadata<KubeObjectScope.Cluster>;
|
||||
spec?: PersistentVolumeSpec;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { SeLinuxOptions } from "./se-linux-options";
|
||||
import type { SeccompProfile } from "./seccomp-profile";
|
||||
import type { WindowsSecurityContextOptions } from "./windows-security-context-options";
|
||||
import type { Sysctl } from "../pod.api";
|
||||
|
||||
|
||||
export interface PodSecurityContext {
|
||||
fsGroup?: number;
|
||||
fsGroupChangePolicy?: string;
|
||||
runAsGroup?: number;
|
||||
runAsNonRoot?: boolean;
|
||||
runAsUser?: number;
|
||||
seLinuxOptions?: SeLinuxOptions;
|
||||
seccompProfile?: SeccompProfile;
|
||||
supplementalGroups?: number[];
|
||||
sysctls?: Sysctl;
|
||||
windowsOptions?: WindowsSecurityContextOptions;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { KubeObjectScope, KubeTemplateObjectMetadata } from "../../kube-object";
|
||||
import type { PodSpec } from "../pod.api";
|
||||
|
||||
export interface PodTemplateSpec {
|
||||
metadata?: KubeTemplateObjectMetadata<KubeObjectScope.Namespace>;
|
||||
spec?: PodSpec;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
export interface PolicyRule {
|
||||
verbs: string[];
|
||||
apiGroups?: string[];
|
||||
resources?: string[];
|
||||
resourceNames?: string[];
|
||||
nonResourceURLs?: string[];
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
export type PreemptionPolicy = "Never" | "PreemptLowerPriority";
|
||||
@@ -1,80 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { ExecAction } from "./exec-action";
|
||||
import type { HttpGetAction } from "./http-get-action";
|
||||
import type { TcpSocketAction } from "./tcp-socket-action";
|
||||
|
||||
/**
|
||||
* Describes a health check to be performed against a container to determine whether it is alive or ready to receive traffic.
|
||||
*/
|
||||
export interface Probe {
|
||||
exec?: ExecAction;
|
||||
|
||||
/**
|
||||
* Minimum consecutive failures for the probe to be considered failed after having succeeded.
|
||||
*
|
||||
* @default 3
|
||||
* @minimum 1
|
||||
*/
|
||||
failureThreshold?: number;
|
||||
|
||||
httpGet?: HttpGetAction;
|
||||
|
||||
/**
|
||||
* Duration after the container has started before liveness probes are initiated.
|
||||
*
|
||||
* More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes
|
||||
*/
|
||||
initialDelaySeconds?: number;
|
||||
|
||||
/**
|
||||
* How often to perform the probe.
|
||||
*
|
||||
* @default 10
|
||||
* @minimum 1
|
||||
*/
|
||||
periodSeconds?: number;
|
||||
|
||||
/**
|
||||
* Minimum consecutive successes for the probe to be considered successful after having failed.
|
||||
*
|
||||
* Must be 1 for liveness and startup.
|
||||
*
|
||||
* @default 1
|
||||
* @minimum 1
|
||||
*/
|
||||
successThreshold?: number;
|
||||
|
||||
tcpSocket?: TcpSocketAction;
|
||||
|
||||
/**
|
||||
* Duration the pod needs to terminate gracefully upon probe failure.
|
||||
*
|
||||
* The grace period is the duration in seconds after the processes running in the pod are sent a
|
||||
* termination signal and the time when the processes are forcibly halted with a kill signal.
|
||||
*
|
||||
* Set this value longer than the expected cleanup time for your process.
|
||||
*
|
||||
* If this value is not set, the pod's terminationGracePeriodSeconds will be used. Otherwise,
|
||||
* this value overrides the value provided by the pod spec. Value must be non-negative integer.
|
||||
* The value zero indicates stop immediately via the kill signal (no opportunity to shut down).
|
||||
*
|
||||
* This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate.
|
||||
*
|
||||
* @minimum 1
|
||||
*/
|
||||
terminationGracePeriodSeconds?: number;
|
||||
|
||||
/**
|
||||
* Duration after which the probe times out.
|
||||
*
|
||||
* More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes
|
||||
*
|
||||
* @default 1
|
||||
* @minimum 1
|
||||
*/
|
||||
timeoutSeconds?: number;
|
||||
}
|
||||
Loaded 100 of 466 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user