Files
certd/packages/ui/certd-server/src/plugins/plugin-aliyun/plugin/deploy-to-apigateway/index.ts
T

237 lines
6.6 KiB
TypeScript
Raw Normal View History

import { AbstractTaskPlugin, IsTaskPlugin, Pager, PageSearch, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
2026-05-31 01:41:33 +08:00
import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib";
import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert";
import { optionsUtils } from "@certd/basic";
import { AliyunAccess } from "../../../plugin-lib/aliyun/access/index.js";
2025-08-14 11:00:10 +08:00
@IsTaskPlugin({
2026-05-31 01:41:33 +08:00
name: "DeployCertToAliyunApiGateway",
title: "阿里云-部署证书至API网关",
icon: "svg:icon-aliyun",
2025-08-14 11:00:10 +08:00
group: pluginGroups.aliyun.key,
2026-05-31 01:41:33 +08:00
desc: "自动部署域名证书至阿里云API网关(APIGateway",
2025-08-14 11:00:10 +08:00
default: {
strategy: {
runStrategy: RunStrategy.SkipWhenSucceed,
},
},
})
export class DeployCertToAliyunApiGateway extends AbstractTaskPlugin {
@TaskInput({
2026-05-31 01:41:33 +08:00
title: "域名证书",
helper: "请选择前置任务输出的域名证书",
2025-08-14 11:00:10 +08:00
component: {
2026-05-31 01:41:33 +08:00
name: "output-selector",
2025-08-14 11:00:10 +08:00
from: [...CertApplyPluginNames],
},
required: true,
})
cert!: CertInfo;
@TaskInput(createCertDomainGetterInputDefine({ props: { required: false } }))
certDomains!: string[];
@TaskInput({
2026-05-31 01:41:33 +08:00
title: "Access授权",
helper: "阿里云授权AccessKeyId、AccessKeySecret",
2025-08-14 11:00:10 +08:00
component: {
2026-05-31 01:41:33 +08:00
name: "access-selector",
type: "aliyun",
2025-08-14 11:00:10 +08:00
},
required: true,
})
accessId!: string;
@TaskInput({
2026-05-31 01:41:33 +08:00
title: "证书名称",
helper: "上传后将以此名称作为前缀备注",
2025-08-14 11:00:10 +08:00
})
certName!: string;
@TaskInput(
createRemoteSelectInputDefine({
2026-05-31 01:41:33 +08:00
title: "区域",
helper: "请选择区域",
2025-08-14 11:00:10 +08:00
action: DeployCertToAliyunApiGateway.prototype.onGetRegionList.name,
2026-05-31 01:41:33 +08:00
watches: ["certDomains", "accessId"],
2025-08-14 11:00:10 +08:00
required: true,
2026-05-31 01:41:33 +08:00
component: {
name: "remote-auto-complete",
},
2025-08-14 11:00:10 +08:00
})
)
regionEndpoint!: string;
@TaskInput(
createRemoteSelectInputDefine({
2026-05-31 01:41:33 +08:00
title: "API分组",
helper: "请选择API分组",
2025-08-14 11:00:10 +08:00
action: DeployCertToAliyunApiGateway.prototype.onGetGroupList.name,
2026-05-31 01:41:33 +08:00
watches: ["regionEndpoint", "accessId"],
2025-08-14 11:00:10 +08:00
required: true,
2026-06-14 20:59:38 +08:00
single: true,
pager: true,
search: true,
2025-08-14 11:00:10 +08:00
})
)
groupId!: string;
@TaskInput(
createRemoteSelectInputDefine({
2026-05-31 01:41:33 +08:00
title: "绑定域名",
helper: "在API分组上配置的绑定域名",
2025-08-14 11:00:10 +08:00
action: DeployCertToAliyunApiGateway.prototype.onGetDomainList.name,
2026-05-31 01:41:33 +08:00
watches: ["groupId", "regionEndpoint", "accessId"],
2025-08-14 11:00:10 +08:00
required: true,
})
)
customDomains!: string[];
async onInstance() {}
async execute(): Promise<void> {
2026-05-31 01:41:33 +08:00
this.logger.info("开始部署证书到阿里云Api网关");
if (!this.customDomains) {
throw new Error("您还未选择域名");
2025-08-14 11:00:10 +08:00
}
const access = await this.getAccess<AliyunAccess>(this.accessId);
2026-05-31 01:41:33 +08:00
const client = access.getClient(this.regionEndpoint);
2025-08-14 11:00:10 +08:00
2026-05-31 01:41:33 +08:00
for (const domainName of this.customDomains) {
this.logger.info(`[${domainName}]开始部署`);
2025-08-14 11:00:10 +08:00
await this.updateCert(client, domainName);
2026-05-31 01:41:33 +08:00
this.logger.info(`[${domainName}]部署成功`);
2025-08-14 11:00:10 +08:00
}
2026-05-31 01:41:33 +08:00
this.logger.info("部署完成");
2025-08-14 11:00:10 +08:00
}
async updateCert(client: any, domainName: string) {
2026-05-31 01:41:33 +08:00
const ret = await client.doRequest({
2025-08-14 11:00:10 +08:00
// 接口名称
action: "SetDomainCertificate",
// 接口版本
version: "2016-07-14",
2026-05-31 01:41:33 +08:00
data: {
query: {
2025-08-14 11:00:10 +08:00
GroupId: this.groupId,
DomainName: domainName,
CertificateName: this.buildCertName(domainName),
CertificateBody: this.cert.crt,
2026-05-31 01:41:33 +08:00
CertificatePrivateKey: this.cert.key,
},
},
});
2025-08-14 11:00:10 +08:00
this.logger.info(`设置${domainName}证书成功:`, ret.RequestId);
}
async onGetGroupList(data: PageSearch) {
2025-08-14 11:00:10 +08:00
if (!this.accessId) {
2026-05-31 01:41:33 +08:00
throw new Error("请选择Access授权");
2025-08-14 11:00:10 +08:00
}
if (!this.regionEndpoint) {
2026-05-31 01:41:33 +08:00
throw new Error("请选择区域");
2025-08-14 11:00:10 +08:00
}
const access = await this.getAccess<AliyunAccess>(this.accessId);
2026-05-31 01:41:33 +08:00
const client = access.getClient(this.regionEndpoint);
const pager = new Pager(data)
2026-05-31 01:41:33 +08:00
const res = await client.doRequest({
2025-08-14 11:00:10 +08:00
// 接口名称
action: "DescribeApiGroups",
// 接口版本
version: "2016-07-14",
data: {
query: {
GroupName: data.searchKey,
PageNumber: pager.pageNo,
PageSize: pager.pageSize,
},
},
2026-05-31 01:41:33 +08:00
});
2025-08-14 11:00:10 +08:00
const list = res?.ApiGroupAttributes?.ApiGroupAttribute;
if (!list || list.length === 0) {
2026-05-31 01:41:33 +08:00
throw new Error("没有数据,您可以手动输入API网关ID");
2025-08-14 11:00:10 +08:00
}
const records = list.map((item: any) => {
2025-08-14 11:00:10 +08:00
return {
value: item.GroupId,
label: `${item.GroupName}<${item.GroupId}>`,
};
});
return {
list: records,
total: res?.TotalCount || 0,
}
2025-08-14 11:00:10 +08:00
}
async onGetDomainList(data: any) {
if (!this.accessId) {
2026-05-31 01:41:33 +08:00
throw new Error("请选择Access授权");
2025-08-14 11:00:10 +08:00
}
if (!this.regionEndpoint) {
2026-05-31 01:41:33 +08:00
throw new Error("请选择区域");
2025-08-14 11:00:10 +08:00
}
if (!this.groupId) {
2026-05-31 01:41:33 +08:00
throw new Error("请选择分组");
2025-08-14 11:00:10 +08:00
}
const access = await this.getAccess<AliyunAccess>(this.accessId);
2026-05-31 01:41:33 +08:00
const client = access.getClient(this.regionEndpoint);
const res = await client.doRequest({
// 接口名称
action: "DescribeApiGroup",
// 接口版本
version: "2016-07-14",
data: {
query: {
GroupId: this.groupId,
},
},
});
2025-08-14 11:00:10 +08:00
const list = res?.CustomDomains?.DomainItem;
if (!list || list.length === 0) {
2026-05-31 01:41:33 +08:00
throw new Error("没有数据,您可以手动输入");
2025-08-14 11:00:10 +08:00
}
const options = list.map((item: any) => {
return {
value: item.DomainName,
label: `${item.DomainName}<${item.CertificateName}>`,
domain: item.DomainName,
};
});
return optionsUtils.buildGroupOptions(options, this.certDomains);
}
async onGetRegionList(data: any) {
if (!this.accessId) {
2026-05-31 01:41:33 +08:00
throw new Error("请选择Access授权");
2025-08-14 11:00:10 +08:00
}
const access = await this.getAccess<AliyunAccess>(this.accessId);
2026-05-31 01:41:33 +08:00
const client = access.getClient("apigateway.cn-hangzhou.aliyuncs.com");
2025-08-14 11:00:10 +08:00
2026-05-31 01:41:33 +08:00
const res = await client.doRequest({
2025-08-14 11:00:10 +08:00
// 接口名称
action: "DescribeRegions",
// 接口版本
version: "2016-07-14",
2026-05-31 01:41:33 +08:00
data: {},
});
const list = res.Regions.Region;
2025-08-14 11:00:10 +08:00
if (!list || list.length === 0) {
2026-05-31 01:41:33 +08:00
throw new Error("没有数据,您可以手动输入");
2025-08-14 11:00:10 +08:00
}
return list.map((item: any) => {
return {
value: item.RegionEndpoint,
label: item.LocalName,
endpoint: item.RegionEndpoint,
2026-05-31 01:41:33 +08:00
regionId: item.RegionId,
2025-08-14 11:00:10 +08:00
};
});
}
}
new DeployCertToAliyunApiGateway();