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

309 lines
9.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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") {
const certIdRes = await sslClient.uploadCertificate({
name: this.appendTimeSuffix("certd"),
cert: this.cert,
});
certId = certIdRes.certId as any;
}
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();