From 9b63fb4ee2c6b56139160c5bf63482dab0869c2b Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sat, 16 Aug 2025 01:33:51 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E6=94=AF=E6=8C=81apisix=E8=AF=81?= =?UTF-8?q?=E4=B9=A6=E9=83=A8=E7=BD=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/ui/certd-server/src/plugins/index.ts | 1 + .../src/plugins/plugin-apisix/access.ts | 104 ++++++++++++++++ .../src/plugins/plugin-apisix/index.ts | 2 + .../plugins/plugin-apisix/plugins/index.ts | 1 + .../plugins/plugin-refresh-cert.ts | 115 ++++++++++++++++++ 5 files changed, 223 insertions(+) create mode 100644 packages/ui/certd-server/src/plugins/plugin-apisix/access.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-apisix/index.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-apisix/plugins/index.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-apisix/plugins/plugin-refresh-cert.ts diff --git a/packages/ui/certd-server/src/plugins/index.ts b/packages/ui/certd-server/src/plugins/index.ts index aa4ab492..15ca8925 100644 --- a/packages/ui/certd-server/src/plugins/index.ts +++ b/packages/ui/certd-server/src/plugins/index.ts @@ -32,3 +32,4 @@ export * from './plugin-proxmox/index.js' export * from './plugin-wangsu/index.js' export * from './plugin-admin/index.js' export * from './plugin-ksyun/index.js' +export * from './plugin-apisix/index.js' diff --git a/packages/ui/certd-server/src/plugins/plugin-apisix/access.ts b/packages/ui/certd-server/src/plugins/plugin-apisix/access.ts new file mode 100644 index 00000000..3b917706 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-apisix/access.ts @@ -0,0 +1,104 @@ +import {AccessInput, BaseAccess, IsAccess} from "@certd/pipeline"; +import {HttpRequestConfig} from "@certd/basic"; +import {CertInfo, CertReader} from "@certd/plugin-cert"; + +/** + */ +@IsAccess({ + name: "apisix", + title: "APISIX授权", + desc: "", + icon: "svg:icon-ksyun" +}) +export class ApisixAccess extends BaseAccess { + + @AccessInput({ + title: "Apisix管理地址", + component: { + placeholder: "http://192.168.11.11:9180", + }, + required: true, + }) + endpoint = ''; + + @AccessInput({ + title: 'ApiKey', + component: { + placeholder: 'ApiKey', + }, + helper: "[参考文档](https://apisix.apache.org/docs/apisix/admin-api/#using-environment-variables)在config中配置admin apiKey", + required: true, + encrypt: true, + }) + apiKey = ''; + + + @AccessInput({ + title: "测试", + component: { + name: "api-test", + action: "TestRequest" + }, + helper: "点击测试接口是否正常" + }) + testRequest = true; + + async onTestRequest() { + await this.getCertList(); + return "ok" + } + + async getCertList(){ + const req = { + url :"/apisix/admin/ssls", + method: "get", + } + return await this.doRequest(req); + } + + async createCert(opts:{cert:CertInfo}){ + const certReader = new CertReader(opts.cert) + const req = { + url :"/apisix/admin/ssls", + method: "post", + data:{ + cert: opts.cert.crt, + key: opts.cert.key, + snis: certReader.getAllDomains() + } + } + return await this.doRequest(req); + } + + async updateCert (opts:{cert:CertInfo,id:string}){ + const certReader = new CertReader(opts.cert) + const req = { + url :`/apisix/admin/ssls/${opts.id}`, + method: "put", + data:{ + cert: opts.cert.crt, + key: opts.cert.key, + snis: certReader.getAllDomains() + } + } + return await this.doRequest(req); + } + + async doRequest(req: HttpRequestConfig){ + const headers = { + "X-API-KEY": this.apiKey, + ...req.headers + }; + return await this.ctx.http.request({ + headers, + baseURL: this.endpoint, + ...req, + logRes: true, + }); + } + + +} + + +new ApisixAccess(); diff --git a/packages/ui/certd-server/src/plugins/plugin-apisix/index.ts b/packages/ui/certd-server/src/plugins/plugin-apisix/index.ts new file mode 100644 index 00000000..02dc3945 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-apisix/index.ts @@ -0,0 +1,2 @@ +export * from "./plugins/index.js"; +export * from "./access.js"; diff --git a/packages/ui/certd-server/src/plugins/plugin-apisix/plugins/index.ts b/packages/ui/certd-server/src/plugins/plugin-apisix/plugins/index.ts new file mode 100644 index 00000000..705339de --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-apisix/plugins/index.ts @@ -0,0 +1 @@ +import "./plugin-refresh-cert.js" diff --git a/packages/ui/certd-server/src/plugins/plugin-apisix/plugins/plugin-refresh-cert.ts b/packages/ui/certd-server/src/plugins/plugin-apisix/plugins/plugin-refresh-cert.ts new file mode 100644 index 00000000..66c10e20 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-apisix/plugins/plugin-refresh-cert.ts @@ -0,0 +1,115 @@ +import {IsTaskPlugin, PageSearch, pluginGroups, RunStrategy, TaskInput} from "@certd/pipeline"; +import {CertApplyPluginNames, CertInfo} from "@certd/plugin-cert"; +import {createCertDomainGetterInputDefine, createRemoteSelectInputDefine} from "@certd/plugin-lib"; +import {ApisixAccess} from "../access.js"; +import {AbstractPlusTaskPlugin} from "@certd/plugin-plus"; + +@IsTaskPlugin({ + //命名规范,插件类型+功能(就是目录plugin-demo中的demo),大写字母开头,驼峰命名 + name: "ApisixRefreshCert", + title: "APISIX-更新证书", + desc: "自动更新APISIX证书", + icon: "svg:icon-lucky", + //插件分组 + group: pluginGroups.cdn.key, + needPlus: true, + default: { + //默认值配置照抄即可 + strategy: { + runStrategy: RunStrategy.SkipWhenSucceed + } + } +}) +//类名规范,跟上面插件名称(name)一致 +export class ApisixRefreshCDNCert extends AbstractPlusTaskPlugin { + //证书选择,此项必须要有 + @TaskInput({ + title: "域名证书", + helper: "请选择前置任务输出的域名证书", + component: { + name: "output-selector", + from: [...CertApplyPluginNames] + } + // required: true, // 必填 + }) + cert!: CertInfo; + + @TaskInput(createCertDomainGetterInputDefine({ props: { required: false } })) + certDomains!: string[]; + + //授权选择框 + @TaskInput({ + title: "Apisix授权", + component: { + name: "access-selector", + type: "apisix" //固定授权类型 + }, + required: true //必填 + }) + accessId!: string; + // + + @TaskInput( + createRemoteSelectInputDefine({ + title: "证书Id", + helper: "要更新的证书id,如果这里没有,请先给手动绑定一次证书", + action: ApisixRefreshCDNCert.prototype.onGetCertList.name, + pager: false, + search: false + }) + ) + certList!: string[]; + + //插件实例化时执行的方法 + async onInstance() { + } + + //插件执行方法 + async execute(): Promise { + const access = await this.getAccess(this.accessId); + + // await access.createCert({cert:this.cert}) + + for (const certId of this.certList) { + this.logger.info(`----------- 开始更新证书:${certId}`); + + await access.updateCert({ + id: certId, + cert: this.cert + }); + this.logger.info(`----------- 更新证书${certId}成功`); + } + + this.logger.info("部署完成"); + } + + async onGetCertList(data: PageSearch = {}) { + const access = await this.getAccess(this.accessId); + + const res = await access.getCertList() + const list = res.list + if (!list || list.length === 0) { + throw new Error("没有找到证书,你可以直接手动输入id,如果id不存在将自动创建"); + } + + + /** + * certificate-id + * name + * dns-names + */ + const options = list.map((item: any) => { + return { + label: `${item.value.snis[0]}<${item.value.id}>`, + value: item.value.id, + domain: item.value.snis + }; + }); + return { + list: this.ctx.utils.options.buildGroupOptions(options, this.certDomains), + }; + } +} + +//实例化一下,注册插件 +new ApisixRefreshCDNCert();