perf: 支持部署到京东云cdn

pull/361/head
xiaojunnuo 2025-04-03 00:19:54 +08:00
parent 04d79f9117
commit 6f17c700b8
10 changed files with 442 additions and 6 deletions

View File

@ -19,14 +19,15 @@ export class PluginGroup {
export const pluginGroups = { export const pluginGroups = {
cert: new PluginGroup("cert", "证书申请", 1, "ph:certificate"), cert: new PluginGroup("cert", "证书申请", 1, "ph:certificate"),
host: new PluginGroup("host", "主机", 2, "clarity:host-line"),
cdn: new PluginGroup("cdn", "CDN", 2, "svg:icon-cdn"),
panel: new PluginGroup("panel", "面板", 2, "fluent:panel-left-header-32-filled"),
aliyun: new PluginGroup("aliyun", "阿里云", 2, "svg:icon-aliyun"), aliyun: new PluginGroup("aliyun", "阿里云", 2, "svg:icon-aliyun"),
huawei: new PluginGroup("huawei", "华为云", 3, "svg:icon-huawei"), huawei: new PluginGroup("huawei", "华为云", 3, "svg:icon-huawei"),
tencent: new PluginGroup("tencent", "腾讯云", 4, "svg:icon-tencentcloud"), tencent: new PluginGroup("tencent", "腾讯云", 4, "svg:icon-tencentcloud"),
volcengine: new PluginGroup("volcengine", "火山引擎", 4, "svg:icon-volcengine"), volcengine: new PluginGroup("volcengine", "火山引擎", 4, "svg:icon-volcengine"),
jdcloud: new PluginGroup("jdcloud", "京东云", 4, "svg:icon-jdcloud"),
qiniu: new PluginGroup("qiniu", "七牛云", 5, "svg:icon-qiniuyun"), qiniu: new PluginGroup("qiniu", "七牛云", 5, "svg:icon-qiniuyun"),
aws: new PluginGroup("aws", "亚马逊云", 6, "svg:icon-aws"), aws: new PluginGroup("aws", "亚马逊云", 6, "svg:icon-aws"),
host: new PluginGroup("host", "主机", 7, "clarity:host-line"),
cdn: new PluginGroup("cdn", "CDN", 8, "svg:icon-cdn"),
panel: new PluginGroup("panel", "面板", 9, "fluent:panel-left-header-32-filled"),
other: new PluginGroup("other", "其他", 10, "clarity:plugin-line"), other: new PluginGroup("other", "其他", 10, "clarity:plugin-line"),
}; };

View File

@ -6,6 +6,7 @@ export type Registrable = {
desc?: string; desc?: string;
group?: string; group?: string;
deprecated?: string; deprecated?: string;
order?: number;
}; };
export type RegistryItem<T> = { export type RegistryItem<T> = {

View File

@ -2,6 +2,10 @@ import jdCloud from "./lib/core.js";
import jdService from './lib/service.js' import jdService from './lib/service.js'
import domainService from './repo/domainservice/v2/domainservice.js' import domainService from './repo/domainservice/v2/domainservice.js'
import cdnService from './repo/cdn/v1/cdn.js'
import sslService from './repo/ssl/v1/ssl.js'
export const JDCloud = jdCloud; export const JDCloud = jdCloud;
export const JDService = jdService; export const JDService = jdService;
export const JDDomainService = domainService; export const JDDomainService = domainService;
export const JDCdnService = cdnService;
export const JDSslService = sslService;

View File

@ -7,7 +7,7 @@ import { cloneDeep } from 'lodash-es';
export class BuiltInPluginService { export class BuiltInPluginService {
getList() { getList() {
const collection = pluginRegistry.storage; const collection = pluginRegistry.storage;
const list = []; let list = [];
for (const key in collection) { for (const key in collection) {
const Plugin = collection[key]; const Plugin = collection[key];
if (Plugin?.define?.deprecated) { if (Plugin?.define?.deprecated) {
@ -15,11 +15,21 @@ export class BuiltInPluginService {
} }
list.push({ ...Plugin.define, key }); list.push({ ...Plugin.define, key });
} }
list = list.sort((a, b) => {
return (a.order ?? 10 )- (b.order ?? 10);
});
return list; return list;
} }
getGroups() { getGroups() {
return cloneDeep(pluginGroups); const groups:any = cloneDeep(pluginGroups);
for (const key in groups) {
const group = groups[key];
group.plugins = group.plugins.sort((a, b) => {
return (a.order ?? 10 )- (b.order ?? 10);
});
}
return groups;
} }
getByType(type: string) { getByType(type: string) {

View File

@ -9,6 +9,7 @@ import { CertApplyPluginNames} from '@certd/plugin-cert';
icon: 'line-md:uploading-loop', icon: 'line-md:uploading-loop',
group: pluginGroups.host.key, group: pluginGroups.host.key,
desc: 'SFTP上传证书到主机然后SSH执行部署脚本命令', desc: 'SFTP上传证书到主机然后SSH执行部署脚本命令',
order: 1,
default: { default: {
strategy: { strategy: {
runStrategy: RunStrategy.SkipWhenSucceed, runStrategy: RunStrategy.SkipWhenSucceed,

View File

@ -1,2 +1,3 @@
export * from './access.js'; export * from './access.js';
export * from './dns-provider.js'; export * from './dns-provider.js';
export * from './plugins/index.js';

View File

@ -0,0 +1,3 @@
export * from './plugin-deploy-to-cdn.js'
export * from './plugin-update-cert.js'
export * from './plugin-upload-cert.js'

View File

@ -0,0 +1,175 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib";
import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert";
import { optionsUtils } from "@certd/basic/dist/utils/util.options.js";
import { JDCloudAccess } from "../access.js";
@IsTaskPlugin({
name: "JDCloudDeployToCDN",
title: "京东云-部署证书至CDN",
icon: "svg:icon-jdcloud",
group: pluginGroups.jdcloud.key,
desc: "京东云内容分发网络",
default: {
strategy: {
runStrategy: RunStrategy.SkipWhenSucceed
}
}
})
export class JDCloudDeployToCDN extends AbstractTaskPlugin {
@TaskInput({
title: "域名证书",
helper: "请选择前置任务输出的域名证书",
component: {
name: "output-selector",
from: [...CertApplyPluginNames, "JDCloudUploadCert"]
},
required: true
})
cert!: CertInfo | number;
@TaskInput(createCertDomainGetterInputDefine({ props: { required: false } }))
certDomains!: string[];
@TaskInput({
title: "Access授权",
helper: "京东云AccessKeyId、AccessKeySecret",
component: {
name: "access-selector",
type: "jdcloud"
},
required: true
})
accessId!: string;
@TaskInput(
createRemoteSelectInputDefine({
title: "CDN加速域名",
helper: "你在京东云上配置的CDN加速域名比如:certd.docmirror.cn",
action: JDCloudDeployToCDN.prototype.onGetDomainList.name,
watches: ["certDomains", "accessId"],
required: true
})
)
domainName!: string | string[];
async onInstance() {
}
async execute(): Promise<void> {
this.logger.info("开始部署证书到京东云CDN");
const access = await this.accessService.getById<JDCloudAccess>(this.accessId);
const service = await this.getClient(access);
let certId = this.cert;
const certName = this.appendTimeSuffix("certd");
if (typeof certId === "object") {
const certInfo = this.cert as CertInfo;
this.logger.info(`开始上传证书`);
const sslService = await this.getSslClient(access);
const res = await sslService.uploadCert({
// certName String True 证书名称
// keyFile String True 私钥
// certFile String True 证书
// aliasName String False 证书别名
certName: certName,
keyFile: certInfo.key,
certFile: certInfo.crt,
aliasName: certName
});
certId = res.result.certId;
}
// const certInfo = this.cert as CertInfo;
for (const domain of this.domainName) {
this.logger.info(`开始部署域名${domain}证书`);
const res = await service.setHttpType({
/**
* @param {string} opts.domain -
* @param {} [opts.httpType] - http,httphttps,http.https, optional
* @param {} [opts.certificate] - ,Typehttps optional
* @param {} [opts.rsaKey] - optional
* @param {} [opts.jumpType] - defaulthttphttps optional
* @param {} [opts.certFrom] - default,ssl optional
* @param {} [opts.sslCertId] - sslid optional
* @param {} [opts.syncToSsl] - ssl,booleantruefalse optional
* @param {} [opts.certName] - syncToSsltruecertName optional
*/
domain,
httpType: "https",
// certificate: certInfo.crt,
// rsaKey: certInfo.key,
jumpType: "default",
certFrom: "ssl",
sslCertId: certId, // 不用certId 方式,会报证书已存在错误,目前还没找到怎么查询重复证书
syncToSsl: false,
certName: certName
});
this.logger.info(`部署域名${domain}证书成功:${JSON.stringify(res)}`);
await this.ctx.utils.sleep(2000);
}
this.logger.info("部署完成");
}
async getClient(access: JDCloudAccess) {
const { JDCdnService } = await import("@certd/jdcloud");
const service = new JDCdnService({
credentials: {
accessKeyId: access.accessKeyId,
secretAccessKey: access.secretAccessKey
},
regionId: "cn-north-1" //地域信息某个api调用可以单独传参regionId如果不传则会使用此配置中的regionId
});
return service;
}
async getSslClient(access: JDCloudAccess) {
const { JDSslService } = await import("@certd/jdcloud");
const service = new JDSslService({
credentials: {
accessKeyId: access.accessKeyId,
secretAccessKey: access.secretAccessKey
},
regionId: "cn-north-1" //地域信息某个api调用可以单独传参regionId如果不传则会使用此配置中的regionId
});
return service;
}
async onGetDomainList(data: any) {
if (!this.accessId) {
throw new Error("请选择Access授权");
}
const access = await this.accessService.getById<JDCloudAccess>(this.accessId);
const service = await this.getClient(access);
/**
* pageNumber Integer False 1 pageNumber,1
* pageSize
*/
const res = await service.getDomainList({
pageNumber: 1,
pageSize: 50
});
// @ts-ignore
const list = res?.result?.domains;
if (!list || list.length === 0) {
throw new Error("找不到加速域名,您可以手动输入");
}
const options = list.map((item: any) => {
return {
value: item.domain,
label: item.domain,
domain: item.domain
};
});
return optionsUtils.buildGroupOptions(options, this.certDomains);
}
}
new JDCloudDeployToCDN();

View File

@ -0,0 +1,148 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib";
import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert";
import { optionsUtils } from "@certd/basic/dist/utils/util.options.js";
import { JDCloudAccess } from "../access.js";
@IsTaskPlugin({
name: 'JDCloudUpdateCert',
title: '京东云-更新已有证书',
icon: 'svg:icon-jdcloud',
group: pluginGroups.jdcloud.key,
desc: '更新SSL数字证书中的证书',
default: {
strategy: {
runStrategy: RunStrategy.SkipWhenSucceed,
},
},
})
export class JDCloudUpdateCert extends AbstractTaskPlugin {
@TaskInput({
title: '域名证书',
helper: '请选择前置任务输出的域名证书',
component: {
name: 'output-selector',
from: [...CertApplyPluginNames, 'JDCloudUploadCert'],
},
required: true,
})
cert!: CertInfo | string;
@TaskInput(createCertDomainGetterInputDefine({ props: { required: false } }))
certDomains!: string[];
@TaskInput({
title: 'Access授权',
helper: '京东云AccessKeyId、AccessKeySecret',
component: {
name: 'access-selector',
type: 'jdcloud',
},
required: true,
})
accessId!: string;
@TaskInput(
createRemoteSelectInputDefine({
title: '要更新的证书id',
helper: '您在京东云上已有的证书Id',
action: JDCloudUpdateCert.prototype.onGetCertList.name,
watches: ['certDomains', 'accessId'],
required: true,
})
)
certIds!: string[];
async onInstance() {}
async execute(): Promise<void> {
this.logger.info('开始部署证书到京东云CDN');
const access = await this.accessService.getById<JDCloudAccess>(this.accessId);
const service = await this.getClient(access)
// let certId = this.cert
// const certName = this.appendTimeSuffix("certd");
// if (typeof certId !== 'string') {
// const certInfo = this.cert as CertInfo
// this.logger.info(`开始上传证书`)
//
// const res = await service.uploadCert({
// // certName String True 证书名称
// // keyFile String True 私钥
// // certFile String True 证书
// // aliasName String False 证书别名
// certName: certName,
// keyFile: certInfo.key,
// certFile: certInfo.crt,
// aliasName: certName
// })
// certId = res.result.certId
// }
const certInfo = this.cert as CertInfo
for (const certId of this.certIds) {
this.logger.info(`开始更新证书:${certId}`)
const res = await service.updateCert({
/*
@param {string} opts.certId - Id
@param {string} opts.certId - ID
@param {string} opts.keyFile -
@param {string} opts.certFile -
@param {string} callback - callback
*/
certId,
certFile: certInfo.crt,
keyFile:certInfo.key,
})
this.logger.info(`更新证书${certId}成功:${JSON.stringify(res)}`);
await this.ctx.utils.sleep(2000)
}
}
async getClient(access: JDCloudAccess) {
const {JDSslService} = await import("@certd/jdcloud")
const service = new JDSslService({
credentials: {
accessKeyId: access.accessKeyId,
secretAccessKey: access.secretAccessKey
},
regionId: "cn-north-1" //地域信息某个api调用可以单独传参regionId如果不传则会使用此配置中的regionId
});
return service;
}
async onGetCertList(data: any) {
if (!this.accessId) {
throw new Error('请选择Access授权');
}
const access = await this.accessService.getById<JDCloudAccess>(this.accessId);
const service = await this.getClient(access);
/**
* pageNumber Integer False 1 pageNumber,1
* pageSize
*/
const res = await service.describeCerts({
pageNumber: 1,
pageSize: 100,
})
// @ts-ignore
const list = res?.result?.certListDetails
if (!list || list.length === 0) {
throw new Error('找不到证书您可以手动输入证书id');
}
const options = list.map((item: any) => {
return {
value: item.certId,
label: `${item.certName}<${item.certId}_${item.commonName}>`,
domain: item.commonName, // or item.dnsNames 证书所有域名
};
});
return optionsUtils.buildGroupOptions(options, this.certDomains);
}
}
new JDCloudUpdateCert();

View File

@ -0,0 +1,92 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline";
import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert";
import { JDCloudAccess } from "../access.js";
@IsTaskPlugin({
name: "JDCloudUploadCert",
title: "京东云-上传新证书",
icon: "svg:icon-jdcloud",
group: pluginGroups.jdcloud.key,
desc: "上传证书到SSL数字证书中心",
default: {
strategy: {
runStrategy: RunStrategy.SkipWhenSucceed
}
}
})
export class JDCloudUploadCert extends AbstractTaskPlugin {
@TaskInput({
title: "域名证书",
helper: "请选择前置任务输出的域名证书",
component: {
name: "output-selector",
from: [...CertApplyPluginNames, "JDCloudUploadCert"]
},
required: true
})
cert!: CertInfo | string;
@TaskInput({
title: "Access授权",
helper: "京东云AccessKeyId、AccessKeySecret",
component: {
name: "access-selector",
type: "jdcloud"
},
required: true
})
accessId!: string;
@TaskInput({
title: "证书名称前缀",
helper: "证书形成默认为certd",
required: false
})
certName!: string;
@TaskOutput({
title: "上传成功后的京东云CertId"
})
jdcloudCertId!: number;
async onInstance() {
}
async execute(): Promise<void> {
this.logger.info("开始上传证书到京东云数字证书中心");
const access = await this.accessService.getById<JDCloudAccess>(this.accessId);
const service = await this.getClient(access);
const certInfo = this.cert as CertInfo;
const res = await service.uploadCert({
/*
@param {string} opts.certName -
@param {string} opts.keyFile -
@param {string} opts.certFile -
@param {string} [opts.aliasName] - optional
*/
certName: this.appendTimeSuffix(this.certName || "certd"),
certFile: certInfo.crt,
keyFile: certInfo.key
});
this.jdcloudCertId = res.result.certId;
this.logger.info(`上传证书成功:${JSON.stringify(res)}`);
}
async getClient(access: JDCloudAccess) {
const { JDSslService } = await import("@certd/jdcloud");
const service = new JDSslService({
credentials: {
accessKeyId: access.accessKeyId,
secretAccessKey: access.secretAccessKey
},
regionId: "cn-north-1" //地域信息某个api调用可以单独传参regionId如果不传则会使用此配置中的regionId
});
return service;
}
}
new JDCloudUploadCert();