Attempt upgrade to @kubernetes/client-node@1.0.0-rc.1

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton committed 2023-03-27 14:52:38 -04:00
1 parent 4f2ba5df48
commit c7218fd909
11 files changed
+405 -210

No files matched your search

+1 -1
View File
@@ -122,7 +122,7 @@
"@hapi/subtext": "^7.1.0",
"@k8slens/cluster-settings": "^6.5.0-alpha.1",
"@k8slens/node-fetch": "^6.5.0-alpha.1",
"@kubernetes/client-node": "^0.18.1",
"@kubernetes/client-node": "^1.0.0-rc1",
"@material-ui/styles": "^4.11.5",
"@ogre-tools/fp": "^15.1.2",
"@ogre-tools/injectable": "^15.1.2",
@@ -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 });
@@ -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 clusterStoreInjectable from "../../common/cluster-store/cluster-store.injectable";
import type { Cluster } from "../../common/cluster/cluster";
import createAuthorizationApiInjectable from "../../common/cluster/create-authorization-api.injectable";
@@ -479,20 +479,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 = {
@@ -587,51 +585,41 @@ 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: [],
},
} as PartialDeep<V1SelfSubjectRulesReview> 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);
}
@@ -52,7 +52,9 @@ export const createPrometheusProvider = ({ getService, ...opts }: CreatePromethe
export async function findFirstNamespacedService(client: CoreV1Api, ...selectors: string[]): Promise<PrometheusServiceInfo> {
try {
for (const selector of selectors) {
const { body: { items: [service] }} = await client.listServiceForAllNamespaces(undefined, undefined, undefined, selector);
const { items: [service] } = await client.listServiceForAllNamespaces({
labelSelector: selector,
});
if (service?.metadata?.namespace && service.metadata.name && service.spec?.ports) {
return {
@@ -71,7 +73,7 @@ export async function findFirstNamespacedService(client: CoreV1Api, ...selectors
export async function findNamespacedService(client: CoreV1Api, name: string, 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`);
@@ -18,16 +18,17 @@ const getServiceAccountRouteInjectable = getRouteInjectable({
instantiate: (di) => clusterRoute({
method: "get",
path: `${apiPrefix}/kubeconfig/service-account/{namespace}/{account}`,
})(async ({ params, cluster }) => {
})(async (args) => {
const { params: { account, namespace }, cluster } = args;
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;
return annotations?.["kubernetes.io/service-account.name"] === account;
});
if (!secret) {
@@ -37,7 +38,7 @@ const getServiceAccountRouteInjectable = getRouteInjectable({
};
}
const kubeconfig = generateKubeConfig(params.account, secret, cluster);
const kubeconfig = generateKubeConfig(account, secret, cluster);
if (!kubeconfig) {
return {
@@ -44,7 +44,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));
});
@@ -110,32 +113,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,
},
},
});
}