perf: 创建证书任务可以选择lege插件

This commit is contained in:
xiaojunnuo
2024-07-21 02:26:03 +08:00
parent 4afbf20c1a
commit affef13037
40 changed files with 434 additions and 378 deletions
@@ -1,2 +1,3 @@
koa:
port: 7001
+1
View File
@@ -14,6 +14,7 @@
"lint:fix": "mwts fix",
"ci": "npm run cov",
"build": "mwtsc --cleanOutDir --skipLibCheck",
"build-on-docker": "node ./before-build.js && npm run build",
"up-mw-deps": "npx midway-version -u -w"
},
"dependencies": {
@@ -37,7 +37,9 @@ const development = {
},
},
},
cron: {},
cron: {
immediateTriggerOnce: false,
},
/**
* 演示环境
*/
@@ -84,6 +86,8 @@ const development = {
resetAdminPasswd: false,
},
} as MidwayConfig;
mergeConfig(development, 'development');
mergeConfig(development, env);
export default development;
@@ -8,6 +8,9 @@ const production = {
preview: {
enabled: false,
},
cron: {
immediateTriggerOnce: true,
},
} as MidwayConfig;
mergeConfig(production, 'production');
@@ -1,4 +1,4 @@
import { Autoload, Init, Inject, Scope, ScopeEnum } from '@midwayjs/core';
import { Autoload, Config, Init, Inject, Scope, ScopeEnum } from '@midwayjs/core';
import { PipelineService } from '../service/pipeline-service.js';
import { logger } from '../../../utils/logger.js';
@@ -10,11 +10,13 @@ export class AutoRegisterCron {
// @Inject()
// echoPlugin: EchoPlugin;
@Config('cron.immediateTriggerOnce')
private immediateTriggerOnce = false;
@Init()
async init() {
logger.info('加载定时trigger开始');
await this.pipelineService.onStartup();
await this.pipelineService.onStartup(this.immediateTriggerOnce);
// logger.info(this.echoPlugin, this.echoPlugin.test);
// logger.info('加载定时trigger完成');
//
@@ -1,11 +1,4 @@
import {
ALL,
Controller,
Inject,
Post,
Provide,
Query,
} from '@midwayjs/core';
import { ALL, Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
import { BaseController } from '../../../basic/base-controller.js';
import { PluginService } from '../service/plugin-service.js';
import { Constants } from '../../../basic/constants.js';
@@ -25,4 +18,11 @@ export class PluginController extends BaseController {
const list = this.service.getList();
return this.ok(list);
}
@Post('/groups', { summary: Constants.per.authOnly })
async groups(@Query(ALL) query) {
query.userId = this.ctx.user.id;
const group = this.service.getGroups();
return this.ok(group);
}
}
@@ -1,4 +1,4 @@
import { Config, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
import { Config, Inject, Provide, Scope, ScopeEnum, sleep } from '@midwayjs/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { In, Repository } from 'typeorm';
import { BaseService } from '../../../basic/base-service.js';
@@ -80,7 +80,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
/**
* 应用启动后初始加载记录
*/
async onStartup() {
async onStartup(immediateTriggerOnce: boolean) {
logger.info('加载定时trigger开始');
const idEntityList = await this.repository.find({
select: {
@@ -114,7 +114,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
for (const entity of list) {
const pipeline = JSON.parse(entity.content ?? '{}');
try {
this.registerTriggers(pipeline);
await this.registerTriggers(pipeline, immediateTriggerOnce);
} catch (e) {
logger.error('加载定时trigger失败:', e);
}
@@ -123,13 +123,18 @@ export class PipelineService extends BaseService<PipelineEntity> {
logger.info('定时器数量:', this.cron.getListSize());
}
registerTriggers(pipeline?: Pipeline) {
async registerTriggers(pipeline?: Pipeline, immediateTriggerOnce = false) {
if (pipeline?.triggers == null) {
return;
}
for (const trigger of pipeline.triggers) {
this.registerCron(pipeline.id, trigger);
}
if (immediateTriggerOnce) {
await this.trigger(pipeline.id);
await sleep(1000);
}
}
async trigger(id) {
@@ -1,5 +1,5 @@
import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
import { pluginRegistry } from '@certd/pipeline';
import { pluginGroups, pluginRegistry } from '@certd/pipeline';
@Provide()
@Scope(ScopeEnum.Singleton)
export class PluginService {
@@ -12,4 +12,8 @@ export class PluginService {
}
return list;
}
getGroups() {
return pluginGroups;
}
}
@@ -1,4 +1,4 @@
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput, utils } from '@certd/pipeline';
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, utils } from '@certd/pipeline';
// @ts-ignore
import { ROAClient } from '@alicloud/pop-core';
import { AliyunAccess } from '../../access/index.js';
@@ -9,6 +9,7 @@ import { CertInfo } from '@certd/plugin-cert';
@IsTaskPlugin({
name: 'DeployCertToAliyunAckIngress',
title: '部署到阿里云AckIngress',
group: pluginGroups.aliyun.key,
input: {},
output: {},
default: {
@@ -2,7 +2,7 @@ import {
AbstractTaskPlugin,
IAccessService,
ILogger,
IsTaskPlugin,
IsTaskPlugin, pluginGroups,
RunStrategy,
TaskInput,
} from '@certd/pipeline';
@@ -14,6 +14,7 @@ import { AliyunAccess } from '../../access/index.js';
@IsTaskPlugin({
name: 'DeployCertToAliyunCDN',
title: '部署证书至阿里云CDN',
group: pluginGroups.aliyun.key,
desc: '依赖证书申请前置任务,自动部署域名证书至阿里云CDN',
default: {
strategy: {
@@ -1,11 +1,4 @@
import {
AbstractTaskPlugin,
IAccessService,
IsTaskPlugin,
RunStrategy,
TaskInput,
TaskOutput,
} from '@certd/pipeline';
import { AbstractTaskPlugin, IAccessService, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from '@certd/pipeline';
import Core from '@alicloud/pop-core';
import { AliyunAccess } from '../../access/index.js';
import { appendTimeSuffix, checkRet, ZoneOptions } from '../../utils/index.js';
@@ -14,6 +7,7 @@ import { Logger } from 'log4js';
@IsTaskPlugin({
name: 'uploadCertToAliyun',
title: '上传证书到阿里云',
group: pluginGroups.aliyun.key,
desc: '',
default: {
strategy: {
@@ -76,9 +70,7 @@ export class UploadCertToAliyun extends AbstractTaskPlugin {
async execute(): Promise<void> {
console.log('开始部署证书到阿里云cdn');
const access = (await this.accessService.getById(
this.accessId
)) as AliyunAccess;
const access = (await this.accessService.getById(this.accessId)) as AliyunAccess;
const client = this.getClient(access);
const certName = appendTimeSuffix(this.name);
const params = {
@@ -92,11 +84,7 @@ export class UploadCertToAliyun extends AbstractTaskPlugin {
method: 'POST',
};
const ret = (await client.request(
'CreateUserCertificate',
params,
requestOption
)) as any;
const ret = (await client.request('CreateUserCertificate', params, requestOption)) as any;
checkRet(ret);
this.logger.info('证书上传成功:aliyunCertId=', ret.CertId);
@@ -1,16 +1,10 @@
import {
AbstractTaskPlugin,
IAccessService,
ILogger,
IsTaskPlugin,
RunStrategy,
TaskInput,
} from '@certd/pipeline';
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
import { CertInfo, CertReader } from '@certd/plugin-cert';
@IsTaskPlugin({
name: 'CloudflareDeployToCDN',
title: '部署证书到CF CDN',
group: pluginGroups.other.key,
desc: '暂未实现,不可用',
default: {
strategy: {
@@ -1,10 +1,11 @@
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput } from '@certd/pipeline';
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
import { CertInfo, CertReader } from '@certd/plugin-cert';
import { K8sClient } from '@certd/lib-k8s';
@IsTaskPlugin({
name: 'demoTest',
title: 'Demo测试插件',
group: pluginGroups.other.key,
default: {
strategy: {
runStrategy: RunStrategy.SkipWhenSucceed,
@@ -1,16 +1,10 @@
import {
AbstractTaskPlugin,
IAccessService,
ILogger,
IsTaskPlugin,
RunStrategy,
TaskInput,
} from '@certd/pipeline';
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
import { SshClient } from '../../lib/ssh.js';
@IsTaskPlugin({
name: 'hostShellExecute',
title: '执行远程主机脚本命令',
group: pluginGroups.host.key,
input: {},
default: {
strategy: {
@@ -1,4 +1,4 @@
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput, TaskOutput } from '@certd/pipeline';
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from '@certd/pipeline';
import { SshClient } from '../../lib/ssh.js';
import { CertInfo, CertReader } from '@certd/plugin-cert';
import * as fs from 'fs';
@@ -7,6 +7,7 @@ import { SshAccess } from '../../access/index.js';
@IsTaskPlugin({
name: 'uploadCertToHost',
title: '上传证书到主机',
group: pluginGroups.host.key,
desc: '也支持复制证书到本机',
default: {
strategy: {
@@ -1,11 +1,4 @@
import {
AbstractTaskPlugin,
IAccessService,
ILogger,
IsTaskPlugin,
RunStrategy,
TaskInput,
} from '@certd/pipeline';
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
import tencentcloud from 'tencentcloud-sdk-nodejs';
import { TencentAccess } from '../../access/index.js';
import { CertInfo } from '@certd/plugin-cert';
@@ -13,6 +6,7 @@ import { CertInfo } from '@certd/plugin-cert';
@IsTaskPlugin({
name: 'DeployCertToTencentCDN',
title: '部署到腾讯云CDN',
group: pluginGroups.tencent.key,
default: {
strategy: {
runStrategy: RunStrategy.SkipWhenSucceed,
@@ -75,9 +69,7 @@ export class DeployToCdnPlugin extends AbstractTaskPlugin {
}
async execute(): Promise<void> {
const accessProvider: TencentAccess = (await this.accessService.getById(
this.accessId
)) as TencentAccess;
const accessProvider: TencentAccess = (await this.accessService.getById(this.accessId)) as TencentAccess;
const client = this.getClient(accessProvider);
const params = this.buildParams();
await this.doRequest(client, params);
@@ -1,12 +1,4 @@
import {
AbstractTaskPlugin,
IAccessService,
ILogger,
IsTaskPlugin,
RunStrategy,
TaskInput,
utils,
} from '@certd/pipeline';
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, utils } from '@certd/pipeline';
import tencentcloud from 'tencentcloud-sdk-nodejs';
import { TencentAccess } from '../../access/index.js';
import dayjs from 'dayjs';
@@ -14,6 +6,7 @@ import dayjs from 'dayjs';
@IsTaskPlugin({
name: 'DeployCertToTencentCLB',
title: '部署到腾讯云CLB',
group: pluginGroups.tencent.key,
desc: '暂时只支持单向认证证书,暂时只支持通用负载均衡',
default: {
strategy: {
@@ -40,8 +33,7 @@ export class DeployToClbPlugin extends AbstractTaskPlugin {
@TaskInput({
title: '负载均衡ID',
helper:
'如果没有配置,则根据域名匹配负载均衡下的监听器(根据域名匹配时暂时只支持前100个)',
helper: '如果没有配置,则根据域名匹配负载均衡下的监听器(根据域名匹配时暂时只支持前100个)',
required: true,
})
loadBalancerId!: string;
@@ -88,9 +80,7 @@ export class DeployToClbPlugin extends AbstractTaskPlugin {
this.logger = this.ctx.logger;
}
async execute(): Promise<void> {
const accessProvider = (await this.accessService.getById(
this.accessId
)) as TencentAccess;
const accessProvider = (await this.accessService.getById(this.accessId)) as TencentAccess;
const client = this.getClient(accessProvider, this.region);
const lastCertId = await this.getCertIdFromProps(client);
@@ -103,10 +93,7 @@ export class DeployToClbPlugin extends AbstractTaskPlugin {
try {
await utils.sleep(2000);
let newCertId = await this.getCertIdFromProps(client);
if (
(lastCertId && newCertId === lastCertId) ||
(!lastCertId && !newCertId)
) {
if ((lastCertId && newCertId === lastCertId) || (!lastCertId && !newCertId)) {
await utils.sleep(2000);
newCertId = await this.getCertIdFromProps(client);
}
@@ -121,11 +108,7 @@ export class DeployToClbPlugin extends AbstractTaskPlugin {
}
async getCertIdFromProps(client: any) {
const listenerRet = await this.getListenerList(
client,
this.loadBalancerId,
[this.listenerId]
);
const listenerRet = await this.getListenerList(client, this.loadBalancerId, [this.listenerId]);
return this.getCertIdFromListener(listenerRet[0], this.domain);
}
@@ -152,14 +135,7 @@ export class DeployToClbPlugin extends AbstractTaskPlugin {
const params = this.buildProps();
const ret = await client.ModifyListener(params);
this.checkRet(ret);
this.logger.info(
'设置腾讯云CLB证书成功:',
ret.RequestId,
'->loadBalancerId:',
this.loadBalancerId,
'listenerId',
this.listenerId
);
this.logger.info('设置腾讯云CLB证书成功:', ret.RequestId, '->loadBalancerId:', this.loadBalancerId, 'listenerId', this.listenerId);
return ret;
}
@@ -1,11 +1,4 @@
import {
AbstractTaskPlugin,
IAccessService,
IsTaskPlugin,
RunStrategy,
TaskInput,
utils,
} from '@certd/pipeline';
import { AbstractTaskPlugin, IAccessService, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, utils } from '@certd/pipeline';
import tencentcloud from 'tencentcloud-sdk-nodejs';
import { K8sClient } from '@certd/lib-k8s';
import dayjs from 'dayjs';
@@ -14,6 +7,7 @@ import { Logger } from 'log4js';
@IsTaskPlugin({
name: 'DeployCertToTencentTKEIngress',
title: '部署到腾讯云TKE-ingress',
group: pluginGroups.tencent.key,
desc: '需要【上传到腾讯云】作为前置任务',
default: {
strategy: {
@@ -104,10 +98,7 @@ export class DeployCertToTencentTKEIngressPlugin extends AbstractTaskPlugin {
async execute(): Promise<void> {
const accessProvider = await this.accessService.getById(this.accessId);
const tkeClient = this.getTkeClient(accessProvider, this.region);
const kubeConfigStr = await this.getTkeKubeConfig(
tkeClient,
this.clusterId
);
const kubeConfigStr = await this.getTkeKubeConfig(tkeClient, this.clusterId);
this.logger.info('kubeconfig已成功获取');
const k8sClient = new K8sClient(kubeConfigStr);
@@ -154,9 +145,7 @@ export class DeployCertToTencentTKEIngressPlugin extends AbstractTaskPlugin {
};
const ret = await client.DescribeClusterKubeconfig(params);
this.checkRet(ret);
this.logger.info(
'注意:后续操作需要在【集群->基本信息】中开启外网或内网访问,https://console.cloud.tencent.com/tke2/cluster'
);
this.logger.info('注意:后续操作需要在【集群->基本信息】中开启外网或内网访问,https://console.cloud.tencent.com/tke2/cluster');
return ret.Kubeconfig;
}
@@ -1,4 +1,4 @@
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput, TaskOutput } from '@certd/pipeline';
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from '@certd/pipeline';
import tencentcloud from 'tencentcloud-sdk-nodejs';
import dayjs from 'dayjs';
@@ -6,6 +6,7 @@ import dayjs from 'dayjs';
name: 'UploadCertToTencent',
title: '上传证书到腾讯云',
desc: '上传成功后输出:tencentCertId',
group: pluginGroups.tencent.key,
default: {
strategy: {
runStrategy: RunStrategy.SkipWhenSucceed,