From 746bb9d385e2f397daef4976eca1d4782a2f5ebd Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Wed, 14 Aug 2024 15:10:55 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E6=9B=B4=E6=96=B0k8s=E5=BA=95=E5=B1=82?= =?UTF-8?q?api=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/libs/lib-k8s/package.json | 3 +- packages/libs/lib-k8s/src/lib/k8s.client.ts | 122 ++++++++++-------- .../src/plugin/cert-plugin/lego/index.ts | 2 +- .../db/migration-pg/v10007__access_text.sql | 1 + packages/ui/certd-server/src/plugins/index.ts | 1 + .../plugin/deploy-to-ack-ingress/index.ts | 13 +- .../plugins/plugin-other/access/k8s-access.ts | 2 + .../plugin/deploy-to-tke-ingress/index.ts | 5 +- 8 files changed, 85 insertions(+), 64 deletions(-) create mode 100644 packages/ui/certd-server/db/migration-pg/v10007__access_text.sql diff --git a/packages/libs/lib-k8s/package.json b/packages/libs/lib-k8s/package.json index 57514d946..772b42f65 100644 --- a/packages/libs/lib-k8s/package.json +++ b/packages/libs/lib-k8s/package.json @@ -13,8 +13,7 @@ "preview": "vite preview" }, "dependencies": { - "kubernetes-client": "^9.0.0", - "shelljs": "^0.8.5" + "@kubernetes/client-node": "0.21.0" }, "devDependencies": { "@certd/pipeline": "^1.23.1", diff --git a/packages/libs/lib-k8s/src/lib/k8s.client.ts b/packages/libs/lib-k8s/src/lib/k8s.client.ts index cc909e9d7..6af30be29 100644 --- a/packages/libs/lib-k8s/src/lib/k8s.client.ts +++ b/packages/libs/lib-k8s/src/lib/k8s.client.ts @@ -1,32 +1,40 @@ -import kubernetesClient from 'kubernetes-client'; -//@ts-ignore +import { KubeConfig, CoreV1Api, V1Secret, NetworkingV1Api, V1Ingress } from '@kubernetes/client-node'; import dns from 'dns'; import { ILogger } from '@certd/pipeline'; -//@ts-ignore -const { KubeConfig, Client, Request } = kubernetesClient; - -export class K8sClient { +export type K8sClientOpts = { kubeConfigStr: string; - lookup!: any; - client!: any; logger: ILogger; - constructor(kubeConfigStr: string, logger: ILogger) { - this.kubeConfigStr = kubeConfigStr; - this.logger = logger; + //{ [domain]:{ip:'xxx.xx.xxx'} } + //暂时没用 + lookup?: any; +}; +export class K8sClient { + kubeconfig!: KubeConfig; + kubeConfigStr: string; + lookup!: (hostnameReq: any, options: any, callback: any) => void; + client!: CoreV1Api; + logger: ILogger; + constructor(opts: K8sClientOpts) { + this.kubeConfigStr = opts.kubeConfigStr; + this.logger = opts.logger; + this.setLookup(opts.lookup); this.init(); } init() { const kubeconfig = new KubeConfig(); kubeconfig.loadFromString(this.kubeConfigStr); - const reqOpts = { kubeconfig, request: {} } as any; - if (this.lookup) { - reqOpts.request.lookup = this.lookup; - } + this.kubeconfig = kubeconfig; + this.client = kubeconfig.makeApiClient(CoreV1Api); - const backend = new Request(reqOpts); - this.client = new Client({ backend, version: '1.13' }); + // const reqOpts = { kubeconfig, request: {} } as any; + // if (this.lookup) { + // reqOpts.request.lookup = this.lookup; + // } + // + // const backend = new Request(reqOpts); + // this.client = new Client({ backend, version: '1.13' }); } /** @@ -34,6 +42,9 @@ export class K8sClient { * @param localRecords { [domain]:{ip:'xxx.xx.xxx'} } */ setLookup(localRecords: { [key: string]: { ip: string } }) { + if (localRecords == null) { + return; + } this.lookup = (hostnameReq: any, options: any, callback: any) => { this.logger.info('custom lookup', hostnameReq, localRecords); if (localRecords[hostnameReq]) { @@ -43,7 +54,6 @@ export class K8sClient { dns.lookup(hostnameReq, options, callback); } }; - this.init(); } /** @@ -51,9 +61,9 @@ export class K8sClient { * @param opts = {namespace:default} * @returns secretsList */ - async getSecret(opts: { namespace: string }) { + async getSecrets(opts: { namespace: string }) { const namespace = opts.namespace || 'default'; - return await this.client.api.v1.namespaces(namespace).secrets.get(); + return await this.client.listNamespacedSecret(namespace); } /** @@ -61,59 +71,61 @@ export class K8sClient { * @param opts {namespace:default, body:yamlStr} * @returns {Promise<*>} */ - async createSecret(opts: any) { + async createSecret(opts: { namespace: string; body: V1Secret }) { const namespace = opts.namespace || 'default'; - const created = await this.client.api.v1.namespaces(namespace).secrets.post({ - body: opts.body, - }); - this.logger.info('new secrets:', created); - return created; + const created = await this.client.createNamespacedSecret(namespace, opts.body); + this.logger.info('new secrets:', created.body); + return created.body; } - async updateSecret(opts: any) { + // async updateSecret(opts: any) { + // const namespace = opts.namespace || 'default'; + // const secretName = opts.secretName; + // if (secretName == null) { + // throw new Error('secretName 不能为空'); + // } + // return await this.client.replaceNamespacedSecret(secretName, namespace, opts.body); + // } + + async patchSecret(opts: { namespace: string; secretName: string; body: V1Secret }) { const namespace = opts.namespace || 'default'; const secretName = opts.secretName; if (secretName == null) { throw new Error('secretName 不能为空'); } - return await this.client.api.v1.namespaces(namespace).secrets(secretName).put({ - body: opts.body, - }); + const res = await this.client.patchNamespacedSecret(secretName, namespace, opts.body); + this.logger.info('secret patched:', res.body); + return res.body; } - async patchSecret(opts: any) { + async getIngressList(opts: { namespace: string }) { const namespace = opts.namespace || 'default'; - const secretName = opts.secretName; - if (secretName == null) { - throw new Error('secretName 不能为空'); - } - return await this.client.api.v1.namespaces(namespace).secrets(secretName).patch({ - body: opts.body, - }); + const client = this.kubeconfig.makeApiClient(NetworkingV1Api); + const res = await client.listNamespacedIngress(namespace); + this.logger.info('ingress list get:', res.body); + return res.body; } - async getIngressList(opts: any) { - const namespace = opts.namespace || 'default'; - return await this.client.apis.extensions.v1beta1.namespaces(namespace).ingresses.get(); - } + // async getIngress(opts: { namespace: string; ingressName: string }) { + // const namespace = opts.namespace || 'default'; + // const ingressName = opts.ingressName; + // if (!ingressName) { + // throw new Error('ingressName 不能为空'); + // } + // const client = this.kubeconfig.makeApiClient(NetworkingV1Api); + // const res = await client.listNamespacedIngress(); + // return await this.client.apis.extensions.v1beta1.namespaces(namespace).ingresses(ingressName).get(); + // } - async getIngress(opts: any) { + async patchIngress(opts: { namespace: string; ingressName: string; body: V1Ingress }) { const namespace = opts.namespace || 'default'; const ingressName = opts.ingressName; if (!ingressName) { throw new Error('ingressName 不能为空'); } - return await this.client.apis.extensions.v1beta1.namespaces(namespace).ingresses(ingressName).get(); - } - - async patchIngress(opts: any) { - const namespace = opts.namespace || 'default'; - const ingressName = opts.ingressName; - if (!ingressName) { - throw new Error('ingressName 不能为空'); - } - return await this.client.apis.extensions.v1beta1.namespaces(namespace).ingresses(ingressName).patch({ - body: opts.body, - }); + const client = this.kubeconfig.makeApiClient(NetworkingV1Api); + const res = await client.patchNamespacedIngress(ingressName, namespace, opts.body); + this.logger.info('ingress patched:', res.body); + return res; } } diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/lego/index.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/lego/index.ts index ac7095562..e1fb6df26 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/lego/index.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/lego/index.ts @@ -97,7 +97,7 @@ export class CertApplyLegoPlugin extends CertApplyBasePlugin { this.http = this.ctx.http; this.lastStatus = this.ctx.lastStatus as Step; if (this.legoEabAccessId) { - this.eab = await this.ctx.accessService.getById(this.legoEabAccessId); + this.eab = await this.accessService.getById(this.legoEabAccessId); } } async onInit(): Promise {} diff --git a/packages/ui/certd-server/db/migration-pg/v10007__access_text.sql b/packages/ui/certd-server/db/migration-pg/v10007__access_text.sql new file mode 100644 index 000000000..2dbecaf7a --- /dev/null +++ b/packages/ui/certd-server/db/migration-pg/v10007__access_text.sql @@ -0,0 +1 @@ +alter table cd_access alter column setting type text using setting::text; diff --git a/packages/ui/certd-server/src/plugins/index.ts b/packages/ui/certd-server/src/plugins/index.ts index 875ae53d6..8cc824c33 100644 --- a/packages/ui/certd-server/src/plugins/index.ts +++ b/packages/ui/certd-server/src/plugins/index.ts @@ -4,3 +4,4 @@ export * from './plugin-tencent/index.js'; export * from './plugin-host/index.js'; export * from './plugin-huawei/index.js'; export * from './plugin-demo/index.js'; +export * from './plugin-other/index.js'; diff --git a/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-ack-ingress/index.ts b/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-ack-ingress/index.ts index 87fbd61ef..1290899a3 100644 --- a/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-ack-ingress/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-ack-ingress/index.ts @@ -115,7 +115,10 @@ export class DeployCertToAliyunAckIngressPlugin extends AbstractTaskPlugin { const kubeConfigStr = await this.getKubeConfig(client, clusterId, isPrivateIpAddress); this.logger.info('kubeconfig已成功获取'); - const k8sClient = new K8sClient(kubeConfigStr, this.logger); + const k8sClient = new K8sClient({ + kubeConfigStr, + logger: this.logger, + }); const ingressType = ingressClass || 'qcloud'; if (ingressType === 'qcloud') { throw new Error('暂未实现'); @@ -128,7 +131,7 @@ export class DeployCertToAliyunAckIngressPlugin extends AbstractTaskPlugin { // await this.restartIngress({ k8sClient, props }) } - async restartIngress(options: { k8sClient: any }) { + async restartIngress(options: { k8sClient: K8sClient }) { const { k8sClient } = options; const { namespace } = this; @@ -141,10 +144,10 @@ export class DeployCertToAliyunAckIngressPlugin extends AbstractTaskPlugin { }; const ingressList = await k8sClient.getIngressList({ namespace }); console.log('ingressList:', ingressList); - if (!ingressList || !ingressList.body || !ingressList.body.items) { + if (!ingressList || !ingressList.items) { return; } - const ingressNames = ingressList.body.items + const ingressNames = ingressList.items .filter((item: any) => { if (!item.spec.tls) { return false; @@ -165,7 +168,7 @@ export class DeployCertToAliyunAckIngressPlugin extends AbstractTaskPlugin { } } - async patchNginxCertSecret(options: { cert: any; k8sClient: any }) { + async patchNginxCertSecret(options: { cert: CertInfo; k8sClient: K8sClient }) { const { cert, k8sClient } = options; const crt = cert.crt; const key = cert.key; diff --git a/packages/ui/certd-server/src/plugins/plugin-other/access/k8s-access.ts b/packages/ui/certd-server/src/plugins/plugin-other/access/k8s-access.ts index 355fc8a9a..70811b24a 100644 --- a/packages/ui/certd-server/src/plugins/plugin-other/access/k8s-access.ts +++ b/packages/ui/certd-server/src/plugins/plugin-other/access/k8s-access.ts @@ -9,6 +9,8 @@ export class K8sAccess { @AccessInput({ title: 'kubeconfig', component: { + name: 'a-textarea', + vModel: 'value', placeholder: 'kubeconfig', }, required: true, diff --git a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-tke-ingress/index.ts b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-tke-ingress/index.ts index 5382a8c27..8b41c38d0 100644 --- a/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-tke-ingress/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-tencent/plugin/deploy-to-tke-ingress/index.ts @@ -97,7 +97,10 @@ export class DeployCertToTencentTKEIngressPlugin extends AbstractTaskPlugin { const kubeConfigStr = await this.getTkeKubeConfig(tkeClient, this.clusterId); this.logger.info('kubeconfig已成功获取'); - const k8sClient = new K8sClient(kubeConfigStr, this.logger); + const k8sClient = new K8sClient({ + kubeConfigStr, + logger: this.logger, + }); if (this.clusterIp != null) { if (!this.clusterDomain) { this.clusterDomain = `${this.clusterId}.ccs.tencent-cloud.com`;