mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
chore: Upgrade to @kubernetes/client-node@1.0.0-rc2
- Finally removes dependency on 'request' Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
1 parent
f602ce8f46
commit
2970fb12e8
13 files changed
+319
-558
No files matched your search
@@ -238,7 +238,7 @@
|
||||
"@k8slens/startable-stoppable": "^1.0.0-alpha.1",
|
||||
"@k8slens/tooltip": "^1.0.0-alpha.5",
|
||||
"@k8slens/utilities": "^1.0.0-alpha.1",
|
||||
"@kubernetes/client-node": "^0.18.1",
|
||||
"@kubernetes/client-node": "^1.0.0-rc2",
|
||||
"@material-ui/core": "^4.12.3",
|
||||
"@material-ui/lab": "^4.0.0-alpha.60",
|
||||
"@ogre-tools/fp": "^17.2.0",
|
||||
|
||||
@@ -23,13 +23,15 @@ const createCanIInjectable = getInjectable({
|
||||
|
||||
return (api) => async (resourceAttributes: V1ResourceAttributes): Promise<boolean> => {
|
||||
try {
|
||||
const { body } = await api.createSelfSubjectAccessReview({
|
||||
apiVersion: "authorization.k8s.io/v1",
|
||||
kind: "SelfSubjectAccessReview",
|
||||
spec: { resourceAttributes },
|
||||
const review = await api.createSelfSubjectAccessReview({
|
||||
body: {
|
||||
apiVersion: "authorization.k8s.io/v1",
|
||||
kind: "SelfSubjectAccessReview",
|
||||
spec: { resourceAttributes },
|
||||
},
|
||||
});
|
||||
|
||||
return body.status?.allowed ?? false;
|
||||
return review.status?.allowed ?? false;
|
||||
} catch (error) {
|
||||
logger.error(`[AUTHORIZATION-REVIEW]: failed to create access review: ${error}`, { resourceAttributes });
|
||||
|
||||
|
||||
+6
-4
@@ -25,10 +25,12 @@ const createRequestNamespaceListPermissionsInjectable = getInjectable({
|
||||
|
||||
return (api) => async (namespace) => {
|
||||
try {
|
||||
const { body: { status }} = await api.createSelfSubjectRulesReview({
|
||||
apiVersion: "authorization.k8s.io/v1",
|
||||
kind: "SelfSubjectRulesReview",
|
||||
spec: { namespace },
|
||||
const { status } = await api.createSelfSubjectRulesReview({
|
||||
body: {
|
||||
apiVersion: "authorization.k8s.io/v1",
|
||||
kind: "SelfSubjectRulesReview",
|
||||
spec: { namespace },
|
||||
},
|
||||
});
|
||||
|
||||
if (!status || status.incomplete) {
|
||||
|
||||
@@ -12,7 +12,7 @@ export type CreateListNamespaces = (api: CoreV1Api) => ListNamespaces;
|
||||
const createListNamespacesInjectable = getInjectable({
|
||||
id: "create-list-namespaces",
|
||||
instantiate: (): CreateListNamespaces => (api) => async () => {
|
||||
const { body: { items }} = await api.listNamespace();
|
||||
const { items } = await api.listNamespace();
|
||||
|
||||
return items
|
||||
.map(ns => ns.metadata?.name)
|
||||
|
||||
@@ -7,7 +7,6 @@ import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { AuthorizationV1Api, V1SubjectRulesReviewStatus } from "@kubernetes/client-node";
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import type { IncomingMessage } from "http";
|
||||
import { anyObject } from "jest-mock-extended";
|
||||
import { getDiForUnitTesting } from "../../main/getDiForUnitTesting";
|
||||
import { cast } from "../../test-utils/cast";
|
||||
@@ -46,11 +45,13 @@ describe("requestNamespaceListPermissions", () => {
|
||||
});
|
||||
|
||||
it("should request the creation of a SelfSubjectRulesReview", () => {
|
||||
expect(createSelfSubjectRulesReviewMock).toBeCalledWith(anyObject({
|
||||
spec: {
|
||||
namespace: "irrelevant-namespace",
|
||||
},
|
||||
}));
|
||||
expect(createSelfSubjectRulesReviewMock).toBeCalledWith({
|
||||
body: anyObject({
|
||||
spec: {
|
||||
namespace: "irrelevant-namespace",
|
||||
},
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
([
|
||||
@@ -189,11 +190,8 @@ describe("requestNamespaceListPermissions", () => {
|
||||
describe(`when api returns ${description}`, () => {
|
||||
beforeEach(async () => {
|
||||
await createSelfSubjectRulesReviewMock.resolve({
|
||||
body: {
|
||||
status,
|
||||
spec: {},
|
||||
},
|
||||
response: null as unknown as IncomingMessage,
|
||||
status,
|
||||
spec: {},
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { AuthorizationV1Api, CoreV1Api, V1APIGroupList, V1APIVersions, V1NamespaceList, V1SelfSubjectAccessReview, V1SelfSubjectRulesReview } from "@kubernetes/client-node";
|
||||
import type { AuthorizationV1Api, CoreV1Api, V1APIGroupList, V1APIVersions, V1SelfSubjectAccessReview, V1SelfSubjectRulesReview } from "@kubernetes/client-node";
|
||||
import type { Cluster } from "../../common/cluster/cluster";
|
||||
import createAuthorizationApiInjectable from "../../common/cluster/create-authorization-api.injectable";
|
||||
import writeJsonFileInjectable from "../../common/fs/write-json-file.injectable";
|
||||
@@ -477,20 +477,18 @@ const nonCoreApiResponse = {
|
||||
} as V1APIGroupList;
|
||||
|
||||
const listNamespaceResponse = {
|
||||
body: {
|
||||
items: [
|
||||
{
|
||||
metadata: {
|
||||
name: "default",
|
||||
},
|
||||
items: [
|
||||
{
|
||||
metadata: {
|
||||
name: "default",
|
||||
},
|
||||
{
|
||||
metadata: {
|
||||
name: "my-namespace",
|
||||
},
|
||||
},
|
||||
{
|
||||
metadata: {
|
||||
name: "my-namespace",
|
||||
},
|
||||
],
|
||||
} as PartialDeep<V1NamespaceList>,
|
||||
},
|
||||
],
|
||||
} as Awaited<ReturnType<CoreV1Api["listNamespace"]>>;
|
||||
|
||||
const coreApiKindsResponse = {
|
||||
@@ -585,51 +583,44 @@ const discoveryK8sIoKindsResponse = {
|
||||
],
|
||||
};
|
||||
|
||||
type CreateSelfSubjectRulesReviewRes = Awaited<ReturnType<AuthorizationV1Api["createSelfSubjectRulesReview"]>>;
|
||||
|
||||
const defaultIncompletePermissions = {
|
||||
body: {
|
||||
status: {
|
||||
incomplete: true,
|
||||
},
|
||||
} as PartialDeep<V1SelfSubjectRulesReview>,
|
||||
} as CreateSelfSubjectRulesReviewRes;
|
||||
status: {
|
||||
incomplete: true,
|
||||
},
|
||||
} as V1SelfSubjectRulesReview;
|
||||
|
||||
const emptyPermissions = {
|
||||
body: {
|
||||
status: {
|
||||
resourceRules: [],
|
||||
},
|
||||
} as PartialDeep<V1SelfSubjectRulesReview>,
|
||||
} as CreateSelfSubjectRulesReviewRes;
|
||||
status: {
|
||||
resourceRules: [],
|
||||
incomplete: false,
|
||||
nonResourceRules: [],
|
||||
},
|
||||
spec: {},
|
||||
} as V1SelfSubjectRulesReview;
|
||||
|
||||
const defaultSingleListPermissions = {
|
||||
body: {
|
||||
status: {
|
||||
resourceRules: [{
|
||||
status: {
|
||||
resourceRules: [{
|
||||
apiGroups: [""],
|
||||
resources: ["pods"],
|
||||
verbs: ["list"],
|
||||
}],
|
||||
},
|
||||
} as V1SelfSubjectRulesReview;
|
||||
|
||||
const defaultMultipleListPermissions = {
|
||||
status: {
|
||||
resourceRules: [
|
||||
{
|
||||
apiGroups: [""],
|
||||
resources: ["pods"],
|
||||
verbs: ["get"],
|
||||
},
|
||||
{
|
||||
apiGroups: [""],
|
||||
resources: ["pods"],
|
||||
verbs: ["list"],
|
||||
}],
|
||||
},
|
||||
} as PartialDeep<V1SelfSubjectRulesReview>,
|
||||
} as CreateSelfSubjectRulesReviewRes;
|
||||
|
||||
const defaultMultipleListPermissions = {
|
||||
body: {
|
||||
status: {
|
||||
resourceRules: [
|
||||
{
|
||||
apiGroups: [""],
|
||||
resources: ["pods"],
|
||||
verbs: ["get"],
|
||||
},
|
||||
{
|
||||
apiGroups: [""],
|
||||
resources: ["pods"],
|
||||
verbs: ["list"],
|
||||
},
|
||||
],
|
||||
},
|
||||
} as PartialDeep<V1SelfSubjectRulesReview>,
|
||||
} as CreateSelfSubjectRulesReviewRes;
|
||||
},
|
||||
],
|
||||
},
|
||||
} as V1SelfSubjectRulesReview;
|
||||
@@ -3,7 +3,8 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { type KubeConfig, HttpError } from "@kubernetes/client-node";
|
||||
import type { KubeConfig } from "@kubernetes/client-node";
|
||||
import { ApiException } from "@kubernetes/client-node";
|
||||
import { reaction, comparer, runInAction } from "mobx";
|
||||
import { ClusterStatus } from "../../common/cluster-types";
|
||||
import type { CreateListNamespaces } from "../../common/cluster/list-namespaces.injectable";
|
||||
@@ -375,10 +376,8 @@ class ClusterConnection {
|
||||
const ctx = proxyConfig.getContextObject(this.cluster.contextName.get());
|
||||
const namespaceList = [ctx?.namespace].filter(isDefined);
|
||||
|
||||
if (namespaceList.length === 0 && error instanceof HttpError && error.statusCode === 403) {
|
||||
const { response } = error as HttpError & { response: Response };
|
||||
|
||||
this.dependencies.logger.info("[CLUSTER]: listing namespaces is forbidden, broadcasting", { clusterId: this.cluster.id, error: response.body });
|
||||
if (namespaceList.length === 0 && error instanceof ApiException && error.code === 403) {
|
||||
this.dependencies.logger.info("[CLUSTER]: listing namespaces is forbidden, broadcasting", { clusterId: this.cluster.id, error: error.body || error.message });
|
||||
this.dependencies.broadcastMessage(clusterListNamespaceForbiddenChannel, this.cluster.id);
|
||||
}
|
||||
|
||||
|
||||
+4
-3
@@ -18,12 +18,13 @@ const getServiceAccountRouteInjectable = getRouteInjectable({
|
||||
method: "get",
|
||||
path: `${apiPrefix}/kubeconfig/service-account/{namespace}/{account}`,
|
||||
})(async ({ params, cluster }) => {
|
||||
const { namespace, account } = params;
|
||||
const loadProxyKubeconfig = di.inject(loadProxyKubeconfigInjectable, cluster);
|
||||
const proxyKubeconfig = await loadProxyKubeconfig();
|
||||
const client = proxyKubeconfig.makeApiClient(CoreV1Api);
|
||||
const secretList = await client.listNamespacedSecret(params.namespace);
|
||||
const { items } = await client.listNamespacedSecret({ namespace });
|
||||
|
||||
const secret = secretList.body.items.find(secret => {
|
||||
const secret = items.find(secret => {
|
||||
const { annotations = {}} = secret.metadata ?? {};
|
||||
|
||||
return annotations["kubernetes.io/service-account.name"] === params.account;
|
||||
@@ -63,7 +64,7 @@ const getServiceAccountRouteInjectable = getRouteInjectable({
|
||||
],
|
||||
contexts: [
|
||||
{
|
||||
name: `${contextName}-${params.account}`,
|
||||
name: `${contextName}-${account}`,
|
||||
context: {
|
||||
user: params.account,
|
||||
cluster: contextName,
|
||||
|
||||
@@ -45,7 +45,10 @@ export class NodeShellSession extends ShellSession {
|
||||
|
||||
const cleanup = once(() => {
|
||||
coreApi
|
||||
.deleteNamespacedPod(this.podName, "kube-system")
|
||||
.deleteNamespacedPod({
|
||||
name: this.podName,
|
||||
namespace: "kube-system",
|
||||
})
|
||||
.catch(error => this.dependencies.logger.warn(`[NODE-SHELL]: failed to remove pod shell`, error));
|
||||
});
|
||||
|
||||
@@ -111,32 +114,35 @@ export class NodeShellSession extends ShellSession {
|
||||
: undefined;
|
||||
|
||||
return coreApi
|
||||
.createNamespacedPod("kube-system", {
|
||||
metadata: {
|
||||
name: this.podName,
|
||||
namespace: "kube-system",
|
||||
},
|
||||
spec: {
|
||||
nodeName: this.nodeName,
|
||||
restartPolicy: "Never",
|
||||
terminationGracePeriodSeconds: 0,
|
||||
hostPID: true,
|
||||
hostIPC: true,
|
||||
hostNetwork: true,
|
||||
tolerations: [{
|
||||
operator: "Exists",
|
||||
}],
|
||||
priorityClassName: "system-node-critical",
|
||||
containers: [{
|
||||
name: "shell",
|
||||
image: nodeShellImage || initialNodeShellImage,
|
||||
securityContext: {
|
||||
privileged: true,
|
||||
},
|
||||
command: ["nsenter"],
|
||||
args: ["-t", "1", "-m", "-u", "-i", "-n", "sleep", "14000"],
|
||||
}],
|
||||
imagePullSecrets,
|
||||
.createNamespacedPod({
|
||||
namespace: "kube-system",
|
||||
body: {
|
||||
metadata: {
|
||||
name: this.podName,
|
||||
namespace: "kube-system",
|
||||
},
|
||||
spec: {
|
||||
nodeName: this.nodeName,
|
||||
restartPolicy: "Never",
|
||||
terminationGracePeriodSeconds: 0,
|
||||
hostPID: true,
|
||||
hostIPC: true,
|
||||
hostNetwork: true,
|
||||
tolerations: [{
|
||||
operator: "Exists",
|
||||
}],
|
||||
priorityClassName: "system-node-critical",
|
||||
containers: [{
|
||||
name: "shell",
|
||||
image: nodeShellImage || initialNodeShellImage,
|
||||
securityContext: {
|
||||
privileged: true,
|
||||
},
|
||||
command: ["nsenter"],
|
||||
args: ["-t", "1", "-m", "-u", "-i", "-n", "sleep", "14000"],
|
||||
}],
|
||||
imagePullSecrets,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
"@k8slens/application": "^6.5.0-alpha.2",
|
||||
"@k8slens/feature-core": "^6.5.0-alpha.0",
|
||||
"@k8slens/utilities": "^1.0.0-alpha.7",
|
||||
"@kubernetes/client-node": "^0.18.1",
|
||||
"@kubernetes/client-node": "^1.0.0-rc2",
|
||||
"@ogre-tools/fp": "^17.2.0",
|
||||
"@ogre-tools/injectable": "^17.2.0",
|
||||
"@ogre-tools/injectable-extension-for-auto-registration": "^17.2.0",
|
||||
|
||||
@@ -59,10 +59,10 @@ export async function findFirstNamespacedService(
|
||||
try {
|
||||
for (const selector of selectors) {
|
||||
const {
|
||||
body: {
|
||||
items: [service],
|
||||
},
|
||||
} = await client.listServiceForAllNamespaces(undefined, undefined, undefined, selector);
|
||||
items: [service],
|
||||
} = await client.listServiceForAllNamespaces({
|
||||
labelSelector: selector,
|
||||
});
|
||||
|
||||
if (service?.metadata?.namespace && service.metadata.name && service.spec?.ports) {
|
||||
return {
|
||||
@@ -87,7 +87,7 @@ export async function findNamespacedService(
|
||||
namespace: string,
|
||||
): Promise<PrometheusServiceInfo> {
|
||||
try {
|
||||
const { body: service } = await client.readNamespacedService(name, namespace);
|
||||
const service = await client.readNamespacedService({ name, namespace });
|
||||
|
||||
if (!service.metadata?.namespace || !service.metadata.name || !service.spec?.ports) {
|
||||
throw new Error(`Service found in namespace="${namespace}" did not have required information`);
|
||||
|
||||
Reference in new issue
Block a user