diff --git a/packages/core/pipeline/src/plugin/api.ts b/packages/core/pipeline/src/plugin/api.ts index 3436bd41..d28725f5 100644 --- a/packages/core/pipeline/src/plugin/api.ts +++ b/packages/core/pipeline/src/plugin/api.ts @@ -8,6 +8,7 @@ import { IContext } from "../core/index.js"; import { ILogger, logger } from "../utils/index.js"; import { HttpClient } from "../utils/util.request"; import { utils } from "../utils/index.js"; +import dayjs from "dayjs"; export enum ContextScope { global, pipeline, @@ -138,6 +139,13 @@ export abstract class AbstractTaskPlugin implements ITaskPlugin { } abstract execute(): Promise; + + appendTimeSuffix(name?: string) { + if (name == null) { + name = "certd"; + } + return name + "_" + dayjs().format("YYYYMMDDHHmmss"); + } } export type OutputVO = { diff --git a/packages/core/pipeline/src/utils/util.request.ts b/packages/core/pipeline/src/utils/util.request.ts index b2ad890a..12e841fd 100644 --- a/packages/core/pipeline/src/utils/util.request.ts +++ b/packages/core/pipeline/src/utils/util.request.ts @@ -33,9 +33,11 @@ export class HttpError extends Error { delete error.response; delete error.config; delete error.request; - logger.error(error); + // logger.error(error); } } + +export const HttpCommonError = HttpError; /** * @description 创建请求实例 */ @@ -118,7 +120,7 @@ export function createAxiosService({ logger }: { logger: Logger }) { logger.error("返回数据:", JSON.stringify(error.response?.data)); if (error instanceof AggregateError) { - logger.error(error); + logger.error("AggregateError", error); } const err = new HttpError(error); return Promise.reject(err); diff --git a/packages/libs/lib-k8s/src/index.ts b/packages/libs/lib-k8s/src/index.ts index 8cadfafd..965d515b 100644 --- a/packages/libs/lib-k8s/src/index.ts +++ b/packages/libs/lib-k8s/src/index.ts @@ -1 +1 @@ -export * from "./lib/k8s.client.js"; +export * from './lib/k8s.client.js'; diff --git a/packages/libs/lib-k8s/src/lib/k8s.client.ts b/packages/libs/lib-k8s/src/lib/k8s.client.ts index 6af30be2..5e4e7d4a 100644 --- a/packages/libs/lib-k8s/src/lib/k8s.client.ts +++ b/packages/libs/lib-k8s/src/lib/k8s.client.ts @@ -1,6 +1,7 @@ -import { KubeConfig, CoreV1Api, V1Secret, NetworkingV1Api, V1Ingress } from '@kubernetes/client-node'; +import { CoreV1Api, KubeConfig, NetworkingV1Api, V1Ingress, V1Secret } from '@kubernetes/client-node'; import dns from 'dns'; import { ILogger } from '@certd/pipeline'; +import _ from 'lodash-es'; export type K8sClientOpts = { kubeConfigStr: string; @@ -74,7 +75,7 @@ export class K8sClient { async createSecret(opts: { namespace: string; body: V1Secret }) { const namespace = opts.namespace || 'default'; const created = await this.client.createNamespacedSecret(namespace, opts.body); - this.logger.info('new secrets:', created.body); + this.logger.info('new secrets:', opts.body); return created.body; } @@ -93,8 +94,11 @@ export class K8sClient { if (secretName == null) { throw new Error('secretName 不能为空'); } - const res = await this.client.patchNamespacedSecret(secretName, namespace, opts.body); - this.logger.info('secret patched:', res.body); + this.logger.info('patch secret:', secretName, namespace); + const oldSecret = await this.client.readNamespacedSecret(secretName, namespace); + const newSecret = _.merge(oldSecret.body, opts.body); + const res = await this.client.replaceNamespacedSecret(secretName, namespace, newSecret); + this.logger.info('secret updated'); return res.body; } @@ -123,9 +127,12 @@ export class K8sClient { if (!ingressName) { throw new Error('ingressName 不能为空'); } + this.logger.info('patch ingress:', ingressName, namespace); const client = this.kubeconfig.makeApiClient(NetworkingV1Api); - const res = await client.patchNamespacedIngress(ingressName, namespace, opts.body); - this.logger.info('ingress patched:', res.body); + const oldIngress = await client.readNamespacedIngress(ingressName, namespace); + const newIngress = _.merge(oldIngress.body, opts.body); + const res = await client.replaceNamespacedIngress(ingressName, namespace, newIngress); + this.logger.info('ingress patched', opts.body); return res; } } diff --git a/packages/ui/certd-server/src/plugins/plugin-other/access/index.ts b/packages/ui/certd-server/src/plugins/plugin-other/access/index.ts index e4a8d690..e69de29b 100644 --- a/packages/ui/certd-server/src/plugins/plugin-other/access/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-other/access/index.ts @@ -1 +0,0 @@ -export * from './k8s-access.js'; 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 deleted file mode 100644 index 2e054fa5..00000000 --- a/packages/ui/certd-server/src/plugins/plugin-other/access/k8s-access.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { IsAccess, AccessInput } from '@certd/pipeline'; - -@IsAccess({ - name: 'k8s', - title: 'k8s授权', - desc: '', -}) -export class K8sAccess { - @AccessInput({ - title: 'kubeconfig', - component: { - name: 'a-textarea', - vModel: 'value', - placeholder: 'kubeconfig', - }, - required: true, - encrypt: true, - }) - kubeconfig = ''; -} - -new K8sAccess(); diff --git a/packages/ui/certd-server/src/plugins/plugin-other/plugins/index.ts b/packages/ui/certd-server/src/plugins/plugin-other/plugins/index.ts index 8f9cc53a..180b1d19 100644 --- a/packages/ui/certd-server/src/plugins/plugin-other/plugins/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-other/plugins/index.ts @@ -1,3 +1,2 @@ -export * from './plugin-k8s.js'; export * from './plugin-restart.js'; export * from './plugin-script.js'; diff --git a/packages/ui/certd-server/src/plugins/plugin-other/plugins/plugin-k8s.ts b/packages/ui/certd-server/src/plugins/plugin-other/plugins/plugin-k8s.ts deleted file mode 100644 index e4b48c24..00000000 --- a/packages/ui/certd-server/src/plugins/plugin-other/plugins/plugin-k8s.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, utils } from '@certd/pipeline'; -import { CertInfo } from '@certd/plugin-cert'; -import { K8sAccess } from '../access/index.js'; -import { appendTimeSuffix } from '../../plugin-aliyun/utils/index.js'; - -@IsTaskPlugin({ - name: 'DeployToK8SIngress', - title: 'K8S Ingress证书部署', - desc: '暂不可用', - group: pluginGroups.other.key, - default: { - strategy: { - runStrategy: RunStrategy.SkipWhenSucceed, - }, - }, -}) -export class K8STestPlugin extends AbstractTaskPlugin { - @TaskInput({ - title: '命名空间', - value: 'default', - component: { - placeholder: '命名空间', - }, - required: true, - }) - namespace!: string; - @TaskInput({ - title: 'ingress名称', - value: '', - component: { - placeholder: 'ingress名称', - }, - required: true, - helper: '可以传入一个数组', - }) - ingressName!: string; - - @TaskInput({ - title: '保密字典Id', - component: { - placeholder: '保密字典Id', - }, - required: true, - }) - secretName!: string | string[]; - - @TaskInput({ - title: 'k8s授权', - helper: 'kubeconfig', - component: { - name: 'pi-access-selector', - type: 'k8s', - }, - required: true, - }) - accessId!: string; - - @TaskInput({ - title: '域名证书', - helper: '请选择前置任务输出的域名证书', - component: { - name: 'pi-output-selector', - from: ['CertApply', 'CertApplyLego'], - }, - required: true, - }) - cert!: CertInfo; - - K8sClient: any; - async onInstance() { - const sdk = await import('@certd/lib-k8s'); - this.K8sClient = sdk.K8sClient; - } - async execute(): Promise { - const access: K8sAccess = await this.accessService.getById(this.accessId); - const k8sClient = new this.K8sClient({ - kubeConfigStr: access.kubeconfig, - logger: this.logger, - }); - await this.patchNginxCertSecret({ cert: this.cert, k8sClient }); - await utils.sleep(3000); // 停留2秒,等待secret部署完成 - } - - async patchNginxCertSecret(options: { cert: CertInfo; k8sClient: any }) { - const { cert, k8sClient } = options; - const crt = cert.crt; - const key = cert.key; - const crtBase64 = Buffer.from(crt).toString('base64'); - const keyBase64 = Buffer.from(key).toString('base64'); - - const { namespace, secretName } = this; - - const body: any = { - data: { - 'tls.crt': crtBase64, - 'tls.key': keyBase64, - }, - metadata: { - labels: { - certd: appendTimeSuffix('certd'), - }, - }, - }; - let secretNames: any = secretName; - if (typeof secretName === 'string') { - secretNames = [secretName]; - } - for (const secret of secretNames) { - await k8sClient.patchSecret({ namespace, secretName: secret, body }); - this.logger.info(`ingress cert Secret已更新:${secret}`); - } - } -} -new K8STestPlugin();