diff --git a/packages/ui/certd-server/src/plugins/plugin-demo/access.ts b/packages/ui/certd-server/src/plugins/plugin-demo/access.ts index fc4f6d147..4124654a5 100644 --- a/packages/ui/certd-server/src/plugins/plugin-demo/access.ts +++ b/packages/ui/certd-server/src/plugins/plugin-demo/access.ts @@ -1,5 +1,5 @@ -import { AccessInput, BaseAccess, IsAccess } from '@certd/pipeline'; -import { isDev } from '../../utils/env.js'; +import { AccessInput, BaseAccess, IsAccess, Pager, PageRes, PageSearch } from '@certd/pipeline'; +import { DomainRecord } from '@certd/plugin-lib'; /** * 这个注解将注册一个授权配置 @@ -8,42 +8,125 @@ import { isDev } from '../../utils/env.js'; @IsAccess({ name: 'demo', title: '授权插件示例', - icon: 'clarity:plugin-line', - desc: '', + icon: 'clarity:plugin-line', //插件图标 + desc: '这是一个示例授权插件,用于演示如何实现一个授权插件', }) export class DemoAccess extends BaseAccess { + + /** + * 授权属性配置 + */ + @AccessInput({ + title: '授权方式', + value: 'apiKey', //默认值 + component: { + name: "a-select", //基于antdv的输入组件 + vModel: "value", // v-model绑定的属性名 + options: [ //组件参数 + { label: "API密钥(推荐)", value: "apiKey" }, + { label: "账号密码", value: "account" }, + ], + placeholder: 'demoKeyId', + }, + required: true, + }) + apiType = ''; + /** * 授权属性配置 */ @AccessInput({ title: '密钥Id', component: { + name:"a-input", + allowClear: true, placeholder: 'demoKeyId', }, required: true, }) demoKeyId = ''; - /** - * 授权属性配置 - */ @AccessInput({ - //标题 - title: '密钥串', - component: { - //input组件的placeholder - placeholder: 'demoKeySecret', - }, - //是否必填 - required: true, - //改属性是否需要加密 - encrypt: true, + title: '密钥',//标题 + required: true, //text组件可以省略 + encrypt: true, //该属性是否需要加密 }) - //属性名称 demoKeySecret = ''; -} -if (isDev()) { - //你的实现 要去掉这个if,不然生产环境将不会显示 - new DemoAccess(); + + @AccessInput({ + title: "测试", + component: { + name: "api-test", + action: "TestRequest" + }, + helper: "点击测试接口是否正常" + }) + testRequest = true; + + /** + * 会通过上面的testRequest参数在ui界面上生成测试按钮,供用户测试接口调用是否正常 + */ + async onTestRequest() { + await this.GetDomainList({}); + return "ok" + } + + /** + * 获api接口示例 取域名列表, + */ + async GetDomainList(req: PageSearch): Promise> { + //输出日志必须使用ctx.logger + this.ctx.logger.info(`获取域名列表,req:${JSON.stringify(req)}`); + const pager = new Pager(req); + const resp = await this.doRequest({ + action: "ListDomains", + data: { + domain: req.searchKey, + offset: pager.getOffset(), + limit: pager.pageSize, + } + }); + const total = resp?.TotalCount || 0; + let list = resp?.DomainList?.map((item) => { + item.domain = item.Domain; + item.id = item.DomainId; + return item; + }) + return { + total, + list + }; + } + + // 还可以继续编写API + + /** + * 通用api调用方法, 具体如何构造请求体,需参考对应应用的API文档 + */ + async doRequest(req: { action: string, data?: any }) { + /** + this.ctx中包含很多有用的工具类 + type AccessContext = { + http: HttpClient; + logger: ILogger; + utils: typeof utils; + accessService: IAccessService; + } + */ + const res = await this.ctx.http.request({ + url: "https://api.demo.cn/api/", + method: "POST", + data: { + Action: req.action, + Body: req.data + } + }); + + if (res.Code !== 0) { + //异常处理 + throw new Error(res.Message || "请求失败"); + } + return res.Resp; + } } diff --git a/packages/ui/certd-server/src/plugins/plugin-demo/plugins/plugin-test.ts b/packages/ui/certd-server/src/plugins/plugin-demo/plugins/plugin-test.ts index f08f39c8c..b18183af5 100644 --- a/packages/ui/certd-server/src/plugins/plugin-demo/plugins/plugin-test.ts +++ b/packages/ui/certd-server/src/plugins/plugin-demo/plugins/plugin-test.ts @@ -1,4 +1,4 @@ -import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; +import { AbstractTaskPlugin, IsTaskPlugin, PageSearch, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline'; import { CertInfo, CertReader } from '@certd/plugin-cert'; import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib'; import { optionsUtils } from '@certd/basic'; @@ -171,7 +171,7 @@ export class DemoTest extends AbstractTaskPlugin { } //此方法演示,如何让前端在添加插件时可以从后端获取选项,这里是后端返回选项的方法 - async onGetSiteList() { + async onGetSiteList(req: PageSearch) { if (!this.accessId) { throw new Error('请选择Access授权'); } @@ -179,13 +179,7 @@ export class DemoTest extends AbstractTaskPlugin { // @ts-ignore const access = await this.getAccess(this.accessId); - // const siteRes = await this.ctx.http.request({ - // url: '你的服务端获取选项的请求地址', - // method: 'GET', - // data: { - // token:access.xxxx - // }, //请求参数 - // }); + // const siteRes = await access.GetDomainList(req); //以下是模拟数据 const siteRes = [ { id: 1, siteName: 'site1.com' }, @@ -204,5 +198,3 @@ export class DemoTest extends AbstractTaskPlugin { return optionsUtils.buildGroupOptions(options, this.certDomains); } } -//实例化一下,注册插件 -new DemoTest(); diff --git a/packages/ui/certd-server/src/plugins/plugin-ucloud/plugins/index.ts b/packages/ui/certd-server/src/plugins/plugin-ucloud/plugins/index.ts index 9b736e406..b42432d30 100644 --- a/packages/ui/certd-server/src/plugins/plugin-ucloud/plugins/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-ucloud/plugins/index.ts @@ -1,3 +1,4 @@ export * from './plugin-deploy-to-cdn.js'; export * from './plugin-upload-to-ussl.js'; export * from './plugin-deploy-to-waf.js'; +export * from './plugin-deploy-to-alb.js'; diff --git a/packages/ui/certd-server/src/plugins/plugin-ucloud/plugins/plugin-deploy-to-alb.ts b/packages/ui/certd-server/src/plugins/plugin-ucloud/plugins/plugin-deploy-to-alb.ts new file mode 100644 index 000000000..b37bfda95 --- /dev/null +++ b/packages/ui/certd-server/src/plugins/plugin-ucloud/plugins/plugin-deploy-to-alb.ts @@ -0,0 +1,199 @@ +import { AbstractTaskPlugin, IsTaskPlugin, PageSearch, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline"; +import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert"; +import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib"; +import { UCloudAccess } from "../access.js"; + +@IsTaskPlugin({ + name: "UCloudDeployToALB", + title: "UCloud-部署到ALB", + desc: "将证书部署到UCloud ALB(应用负载均衡)", + icon: "svg:icon-ucloud", + group: pluginGroups.ucloud.key, + needPlus: false, + default: { + strategy: { + runStrategy: RunStrategy.SkipWhenSucceed + } + } +}) +export class UCloudDeployToALB extends AbstractTaskPlugin { + @TaskInput({ + title: "域名证书", + helper: "请选择前置任务输出的域名证书", + component: { + name: "output-selector", + from: [...CertApplyPluginNames, ":UCloudCertId:"] + } + }) + cert!: CertInfo | { type: string, id: number, name: string }; + + @TaskInput(createCertDomainGetterInputDefine({ props: { required: false } })) + certDomains!: string[]; + + @TaskInput({ + title: "UCloud授权", + component: { + name: "access-selector", + type: "ucloud" + }, + required: true + }) + accessId!: string; + + @TaskInput( + createRemoteSelectInputDefine({ + title: "负载均衡实例", + helper: "选择ULB负载均衡实例", + action: UCloudDeployToALB.prototype.onGetULBList.name + }) + ) + ulbId!: string; + + @TaskInput( + createRemoteSelectInputDefine({ + title: "监听器列表", + helper: "要更新的ALB监听器列表", + action: UCloudDeployToALB.prototype.onGetVServerList.name + }) + ) + vServerList!: string[]; + + async onInstance() { + } + + async execute(): Promise { + const access = await this.getAccess(this.accessId); + let certType = "ussl" + let certId = 0 + + if (this.cert && typeof this.cert === 'object' && 'id' in this.cert) { + certId = this.cert.id + } else { + const cert = await access.SslUploadCert({ + cert: this.cert as CertInfo + }); + certId = cert.id + } + + for (const item of this.vServerList) { + this.logger.info(`----------- 开始更新监听器:${item}`); + await this.deployToAlb({ + access: access, + ulbId: this.ulbId, + vServerId: item, + certId: certId, + certType: certType + }); + this.logger.info(`----------- 更新监听器证书${item}成功`); + } + + this.logger.info("部署完成"); + } + + async deployToAlb(req: { access: any, ulbId: string, vServerId: string, certId: number, certType: string }) { + const { access, ulbId, vServerId, certId, certType } = req + + this.logger.info(`----------- 获取监听器${vServerId}配置`); + const vServerRes = await access.invoke({ + "Action": "DescribeVServer", + "ProjectId": access.projectId, + "ULBId": ulbId, + "VServerId": vServerId + }); + + const vServer = vServerRes.VServerSet?.[0]; + if (!vServer) { + throw new Error(`没有找到监听器${vServerId}`); + } + + this.logger.info(`----------- 更新ALB监听器HTTPS配置${vServerId}`); + const resp = await access.invoke({ + "Action": "UpdateVServerAttribute", + "ProjectId": access.projectId, + "ULBId": ulbId, + "VServerId": vServerId, + "SSLMode": "port", + "CertificateId": certId, + "CertificateType": certType + }); + this.logger.info(`----------- 部署ALB证书${vServerId}成功,${JSON.stringify(resp)}`); + } + + async onGetULBList(req: PageSearch = {}) { + const access = await this.getAccess(this.accessId); + + const pageNo = req.pageNo ?? 1; + const pageSize = req.pageSize ?? 100; + + const res = await access.invoke({ + "Action": "DescribeULB", + "ProjectId": access.projectId, + "Offset": (pageNo - 1) * pageSize, + "Limit": pageSize + }); + + const total = res.TotalCount || 0; + const list = res.Dataset || []; + + if (!list || list.length === 0) { + throw new Error("没有找到ULB实例,请先在控制台创建ULB实例"); + } + + const options = list.map((item: any) => { + return { + label: `${item.Name || item.ULBId}<${item.ULBId}>`, + value: `${item.ULBId}` + }; + }); + + return { + list: options, + total: total, + pageNo: pageNo, + pageSize: pageSize + }; + } + + async onGetVServerList(req: PageSearch = {}) { + const access = await this.getAccess(this.accessId); + + if (!this.ulbId) { + throw new Error("请先选择ULB负载均衡实例"); + } + + const pageNo = req.pageNo ?? 1; + const pageSize = req.pageSize ?? 100; + + const res = await access.invoke({ + "Action": "DescribeVServer", + "ProjectId": access.projectId, + "ULBId": this.ulbId, + "Offset": (pageNo - 1) * pageSize, + "Limit": pageSize + }); + + const total = res.TotalCount || 0; + const list = res.VServerSet || []; + + if (!list || list.length === 0) { + throw new Error("没有找到ALB监听器,请先在控制台创建ALB实例和监听器"); + } + + const options = list.map((item: any) => { + return { + label: `${item.VServerName || item.VServerId}<${item.VServerId}>`, + value: `${item.VServerId}`, + domain: item.VServerName || item.VServerId + }; + }); + + return { + list: this.ctx.utils.options.buildGroupOptions(options, this.certDomains), + total: total, + pageNo: pageNo, + pageSize: pageSize + }; + } +} + +new UCloudDeployToALB();