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

309 lines
9.7 KiB
TypeScript
Raw Normal View History

import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert";
import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib";
import { AliyunAccess } from "../../../plugin-lib/aliyun/access/index.js";
import { AliyunSslClient } from "../../../plugin-lib/aliyun/lib/ssl-client.js";
@IsTaskPlugin({
name: "AliyunDeployCertToAll",
title: "阿里云-部署至任意云资源",
icon: "svg:icon-aliyun",
group: pluginGroups.aliyun.key,
desc: "【不建议使用】需要消耗阿里云自动部署次数,支持SLB、LIVE、webHosting、VOD、CR、DCDN、DDoS、CDN、ALB、APIGateway、FC、GA、MSE、NLB、OSS、SAE、WAF等云产品",
needPlus: false,
default: {
strategy: {
runStrategy: RunStrategy.SkipWhenSucceed,
},
},
})
export class AliyunDeployCertToAll extends AbstractTaskPlugin {
@TaskInput({
title: "域名证书",
helper: "请选择证书申请任务输出的域名证书\n或者选择前置任务“上传证书到阿里云”任务的证书ID,可以减少上传到阿里云的证书数量",
component: {
name: "output-selector",
from: [...CertApplyPluginNames, "uploadCertToAliyun"],
},
required: true,
})
cert!: CertInfo | number;
@TaskInput(createCertDomainGetterInputDefine({ props: { required: false } }))
certDomains!: string[];
@TaskInput({
title: "接入点",
helper: "不会选就按默认",
value: "cas.aliyuncs.com",
component: {
name: "a-select",
options: [
{ value: "cas.aliyuncs.com", label: "中国大陆" },
{ value: "cas.ap-southeast-1.aliyuncs.com", label: "新加坡" },
{ value: "cas.eu-central-1.aliyuncs.com", label: "德国(法兰克福)" },
],
},
required: true,
})
endpoint!: string;
@TaskInput({
title: "Access授权",
helper: "阿里云授权AccessKeyId、AccessKeySecret",
component: {
name: "access-selector",
type: "aliyun",
},
required: true,
})
accessId!: string;
/**
* SLB:传统型负载均衡 CLB(仅中国站)
* LIVE:视频直播(仅中国站)
* webHosting:云虚拟主机(仅中国站)
* VOD:视频点播(仅中国站)
* CR:容器镜像服务(仅中国站)
* DCDN:全站加速
* DDoSDDos 防护
* CDN:内容分发网络
* ALB:应用负载均衡
* APIGatewayAPI 网关
* FC:函数计算
* GA:全球加速
* MSE:微服务引擎
* NLB:网络型负载均衡
* OSS:对象存储
* SAEServerless 应用引擎
* WAFWeb 应用防火墙
*/
@TaskInput({
title: "云产品类型",
helper: "请选择云产品类型",
component: {
name: "a-select",
vModel: "value",
options: [
{ value: "SLB", label: "SLB-传统型负载均衡 CLB(仅中国站)" },
{ value: "LIVE", label: "LIVE-视频直播(仅中国站)" },
{ value: "webHosting", label: "webHosting-云虚拟主机(仅中国站)" },
{ value: "VOD", label: "VOD-视频点播(仅中国站)" },
{ value: "CR", label: "CR-容器镜像服务(仅中国站)" },
{ value: "DCDN", label: "DCDN-全站加速" },
{ value: "DDoS", label: "DDos 防护" },
{ value: "CDN", label: "CDN-内容分发网络" },
{ value: "ALB", label: "ALB-应用负载均衡" },
{ value: "APIGateway", label: "APIGateway-API 网关" },
{ value: "FC", label: "FC-函数计算" },
{ value: "GA", label: "GA-全球加速" },
{ value: "MSE", label: "MSE-微服务引擎" },
{ value: "NLB", label: "NLB-网络型负载均衡" },
{ value: "OSS", label: "OSS-对象存储" },
{ value: "SAE", label: "SAE-Serverless应用引擎" },
{ value: "WAF", label: "WAF-Web应用防火墙" },
],
},
required: true,
})
cloudProduct!: string;
@TaskInput(
createRemoteSelectInputDefine({
title: "要部署证书的云产品",
helper: "请选择要部署证书的云产品,注意:新创建的云产品资源可能需要过1-2小时才会在此处显示",
typeName: "AliyunDeployCertToAll",
action: AliyunDeployCertToAll.prototype.onGetProductList.name,
watches: ["cloudProduct", "accessId"],
})
)
productIds!: string[];
@TaskInput(
createRemoteSelectInputDefine({
title: "联系人",
helper: "请选择联系人,如果没有,需要先到[阿里云控制台创建联系人](https://yundun.console.aliyun.com/?p=cas#/informationManagement/person/)",
typeName: "AliyunDeployCertToAll",
action: AliyunDeployCertToAll.prototype.onGetContactList.name,
})
)
contactIds!: string[];
@TaskInput({
title: "检查超时时间",
helper: "检查部署任务超时时间,单位分钟",
value: 10,
component: {
name: "a-input-number",
vModel: "value",
},
required: true,
})
checkTimeout!: number;
async onInstance() {}
async execute(): Promise<void> {
this.logger.info("开始部署证书到阿里云");
const access = await this.getAccess<AliyunAccess>(this.accessId);
const sslClient = new AliyunSslClient({
access,
logger: this.logger,
endpoint: this.endpoint,
});
//
let certId: any = this.cert;
if (typeof this.cert === "object") {
2026-01-31 19:30:20 +08:00
const certIdRes = await sslClient.uploadCert({
name: this.appendTimeSuffix("certd"),
cert: this.cert,
});
2026-01-31 19:30:20 +08:00
certId = certIdRes.certId;
}
const jobId = await this.createDeployJob(sslClient, certId);
await this.updateJobStatus(sslClient, jobId, "scheduling");
this.logger.info("开始检查部署任务执行结果");
const startTime = Date.now();
while (Date.now() < startTime + this.checkTimeout * 60 * 1000) {
this.checkSignal();
await this.ctx.utils.sleep(10000);
let res: any = {};
try {
res = await this.getJobDetail(sslClient, jobId);
} catch (e: any) {
this.logger.error(e);
break;
}
const status = res.Status;
if (status == "success") {
this.logger.info("部署任务执行成功:", status);
return;
} else if (status == "error") {
this.logger.error(`部署任务执行失败,请前往 https://yundun.console.aliyun.com/?p=cas#/deployDetail/user/${jobId} 查看失败原因: `, res);
throw new Error("部署任务执行失败,");
} else {
/**
* pending:待执行
* editing:编辑中
* scheduling:调度中
* processing:部署中
* error:部署失败
* success:部署成功
*/
this.logger.info("部署任务正在执行中: ", status);
}
}
throw new Error("部署任务执行超时,请手动检查任务状态");
}
async updateJobStatus(sslClient: AliyunSslClient, jobId: string, status: string) {
const params = {
JobId: jobId,
Status: status,
};
const requestOption = {
method: "POST",
formatParams: false,
};
const res = await sslClient.doRequest("UpdateDeploymentJobStatus", params, requestOption);
this.logger.info("部署任务开始执行,部署需要时间,RequestId=", res.RequestId);
}
async onGetProductList(data: any) {
if (!this.accessId) {
throw new Error("请选择Access授权");
}
const access = await this.getAccess<AliyunAccess>(this.accessId);
const sslClient = new AliyunSslClient({
access,
logger: this.logger,
endpoint: this.endpoint,
});
if (!this.cloudProduct) {
throw new Error("请选择云产品类型");
}
const res = await sslClient.getResourceList({
cloudProduct: this.cloudProduct,
});
if (!res?.Data || res?.Data.length === 0) {
throw new Error("没有找到对应类型的云资源");
}
const options = res.Data.map((item: any) => {
return {
label: `${item.Domain}<${item.Id}>`,
value: item.Id,
title: `${item.CloudProduct}:${item.CertName || "证书未命名"}`,
domain: item.Domain,
};
});
return this.ctx.utils.options.buildGroupOptions(options, this.certDomains);
}
async onGetContactList(data: any) {
if (!this.accessId) {
throw new Error("请选择Access授权");
}
const access = await this.getAccess<AliyunAccess>(this.accessId);
const sslClient = new AliyunSslClient({
access,
logger: this.logger,
endpoint: this.endpoint,
});
const res = await sslClient.getContactList();
/*
"Email": "@qq.com",
"EmailStatus": 0,
"MobileStatus": 0,
"ContactId": 378992,
"Mobile": "",
"Name": ""
*/
if (!res?.ContactList || res?.ContactList.length === 0) {
throw new Error("没有找到联系人");
}
return res.ContactList.map((item: any) => {
return {
label: `${item.Name}<${item.Email}:${item.ContactId}>`,
value: item.ContactId,
};
});
}
async getJobDetail(sslClient: AliyunSslClient, jobId: number) {
const params = {
JobId: jobId,
};
const requestOption = {
method: "POST",
formatParams: false,
};
return await sslClient.doRequest("DescribeDeploymentJob", params, requestOption);
}
private async createDeployJob(sslClient: AliyunSslClient, certId: any) {
const res = await sslClient.createDeploymentJob({
name: "自动部署证书(By Certd)",
jobType: "user",
contactIds: this.contactIds,
resourceIds: this.productIds,
certIds: [certId],
});
const jobId = res.JobId;
this.logger.info("部署任务创建成功: jobId=", jobId);
return jobId;
}
}
new AliyunDeployCertToAll();