perf: 手动上传证书部署流水线

This commit is contained in:
xiaojunnuo
2025-03-22 02:06:02 +08:00
parent fedf90ea78
commit fbb66f3c43
25 changed files with 329 additions and 511 deletions
@@ -1,8 +1,8 @@
import { Autoload, Init, Inject, Scope, ScopeEnum } from '@midwayjs/core';
import { CertInfoService } from '../monitor/index.js';
import { pipelineEmitter } from '@certd/pipeline';
import { CertReader, EVENT_CERT_APPLY_SUCCESS } from '@certd/plugin-cert';
import { PipelineEvent } from '@certd/pipeline/dist/service/emit.js';
import { Autoload, Init, Inject, Scope, ScopeEnum } from "@midwayjs/core";
import { CertInfoService } from "../monitor/index.js";
import { pipelineEmitter } from "@certd/pipeline";
import { CertInfo, EVENT_CERT_APPLY_SUCCESS } from "@certd/plugin-cert";
import { PipelineEvent } from "@certd/pipeline/dist/service/emit.js";
@Autoload()
@Scope(ScopeEnum.Request, { allowDowngrade: true })
@@ -15,8 +15,8 @@ export class AutoEPipelineEmitterRegister {
await this.onCertApplySuccess();
}
async onCertApplySuccess() {
pipelineEmitter.on(EVENT_CERT_APPLY_SUCCESS, async (event: PipelineEvent<CertReader>) => {
await this.certInfoService.updateCertByPipelineId(event.pipeline.id, event.event);
pipelineEmitter.on(EVENT_CERT_APPLY_SUCCESS, async (event: PipelineEvent<{cert:CertInfo,file:string}>) => {
await this.certInfoService.updateCertByPipelineId(event.pipeline.id, event.event.cert, event.event.file);
});
}
}
@@ -11,6 +11,7 @@ export type UploadCertReq = {
certReader: CertReader;
fromType?: string;
userId?: number;
file?:any
};
@@ -38,7 +39,7 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
});
}
async updateDomains(pipelineId: number, userId: number, domains: string[]) {
async updateDomains(pipelineId: number, userId: number, domains: string[],fromType?:string) {
const found = await this.repository.findOne({
where: {
pipelineId,
@@ -53,6 +54,7 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
//create
bean.pipelineId = pipelineId;
bean.userId = userId;
bean.fromType = fromType
if (!domains || domains.length === 0) {
return;
}
@@ -133,7 +135,7 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
return certReader.toCertInfo();
}
async updateCertByPipelineId(pipelineId: number, certReader: CertReader, fromType = 'pipeline') {
async updateCertByPipelineId(pipelineId: number, cert: CertInfo,file?:string,fromType = 'pipeline') {
const found = await this.repository.findOne({
where: {
pipelineId,
@@ -141,8 +143,9 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
});
const bean = await this.updateCert({
id: found?.id,
certReader,
certReader: new CertReader(cert),
fromType,
file
});
return bean;
}
@@ -165,6 +168,9 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
bean.expiresTime = certReader.expires;
bean.certProvider = certReader.detail.issuer.commonName;
bean.userId = userId
if(req.file){
bean.certFile = req.file
}
await this.addOrUpdate(bean);
return bean;
}
@@ -1,203 +0,0 @@
import { Inject, Provide, Scope, ScopeEnum } from "@midwayjs/core";
import { BaseService, CommonException } from "@certd/lib-server";
import { InjectEntityModel } from "@midwayjs/typeorm";
import { EntityManager, Repository } from "typeorm";
import { CertInfoEntity } from "../entity/cert-info.js";
import { CertInfo, CertReader } from "@certd/plugin-cert";
import { PipelineService } from "../../pipeline/service/pipeline-service.js";
import { CertInfoService } from "./cert-info-service.js";
import { PipelineEntity } from "../../pipeline/entity/pipeline.js";
import { nanoid } from "nanoid";
export type UploadCertReq = {
id?: number;
certReader: CertReader;
fromType?: string;
userId?: number;
pipelineId?: number;
};
export type UpdateCertReq = {
id: number;
cert: CertInfo;
userId?: number;
};
export type CreateUploadPipelineReq = {
cert: CertInfo;
userId: number;
pipelineId?: number;
pipeline?:{
input?:any;
notifications?:any[]
}
};
@Provide("CertUploadService")
@Scope(ScopeEnum.Request, { allowDowngrade: true })
export class CertUploadService extends BaseService<CertInfoEntity> {
@InjectEntityModel(CertInfoEntity)
repository: Repository<CertInfoEntity>;
@Inject()
pipelineService: PipelineService;
@Inject()
certInfoService: CertInfoService;
//@ts-ignore
getRepository() {
return this.repository;
}
/**
* 更新证书,触发流水线
* @param req
*/
async updateCert(req: UpdateCertReq) {
const certInfoEntity = await this.certInfoService.info(req.id);
if (!certInfoEntity) {
throw new CommonException("cert not found");
}
if(certInfoEntity.fromType !== 'upload') {
throw new CommonException("cert can't be custom upload");
}
await this.uploadCert(this.repository.manager,{
id: req.id,
fromType: 'upload',
userId: req.userId,
certReader: new CertReader(req.cert)
})
return {
id: certInfoEntity.id,
domains: certInfoEntity.domains.split(','),
pipelineId: certInfoEntity.pipelineId,
fromType: certInfoEntity.fromType,
updateTime: certInfoEntity.updateTime,
}
}
async createUploadCertPipeline(body:CreateUploadPipelineReq) {
const { userId, cert } = body;
if (!cert) {
throw new CommonException("cert can't be empty");
}
const certReader = new CertReader(cert)
return await this.transaction(async (tx:EntityManager)=>{
let pipelineId = body.pipelineId;
const newCertInfo = await this.uploadCert(tx,{
certReader: certReader,
fromType: 'upload',
userId,
pipelineId
});
if(!pipelineId){
const pipelineTitle = certReader.getAllDomains()[0] +"上传证书自动部署";
const notifications = body.pipeline?.notifications ||[];
if(notifications.length === 0){
notifications.push({
type: "custom",
when: ["error", "turnToSuccess", "success"],
notificationId: 0,
title: "默认通知",
});
}
let pipeline = {
title: pipelineTitle,
runnableType: "pipeline",
stages: [
{
id: nanoid(10),
title: "上传证书解析阶段",
maxTaskCount: 1,
runnableType: "stage",
tasks: [
{
id: nanoid(10),
title: "上传证书解析转换",
runnableType: "task",
steps: [
{
id: nanoid(10),
title: "上传证书解析转换",
runnableType: "step",
input: {
certInfoId: newCertInfo.id,
domains: newCertInfo.domains.split(','),
...body.pipeline?.input
},
strategy: {
runStrategy: 0, // 正常执行
},
type: "CertApplyUpload",
},
],
},
],
},
],
triggers:[],
notifications,
}
const newPipeline = await tx.getRepository(PipelineEntity).save({
userId,
title: pipelineTitle,
type:"cert_upload",
content: JSON.stringify(pipeline),
keepHistory:20,
})
newCertInfo.pipelineId = newPipeline.id;
await tx.getRepository(CertInfoEntity).save({
id: newCertInfo.id,
pipelineId: newPipeline.id
});
pipelineId = newPipeline.id;
}
return {
id:newCertInfo.id,
pipelineId: pipelineId,
domains: newCertInfo.domains.split(','),
fromType: newCertInfo.fromType,
updateTime: newCertInfo.updateTime,
}
})
}
private async uploadCert(tx:EntityManager,req: UploadCertReq) {
const bean = new CertInfoEntity();
const { id, fromType,userId, certReader } = req;
if (id) {
bean.id = id;
} else {
bean.fromType = fromType;
bean.userId = userId
}
const certInfo = certReader.toCertInfo();
bean.certInfo = JSON.stringify(certInfo);
bean.applyTime = new Date().getTime();
const domains = certReader.detail.domains.altNames;
bean.domains = domains.join(',');
bean.domain = domains[0];
bean.domainCount = domains.length;
bean.expiresTime = certReader.expires;
bean.certProvider = certReader.detail.issuer.commonName;
if (req.pipelineId){
bean.pipelineId = req.pipelineId;
}
await tx.getRepository(CertInfoEntity).save(bean);
return bean;
}
}
@@ -1,28 +0,0 @@
import {ICertApplyUploadService} from "@certd/plugin-cert";
import {IMidwayContext, Inject, Provide} from "@midwayjs/core";
import {CertInfoService} from "../../monitor/index.js";
import {CertUploadService} from "../../monitor/service/cert-upload-service.js";
@Provide("CertApplyUploadService")
export class CertApplyUploadService implements ICertApplyUploadService {
@Inject()
ctx : IMidwayContext
async getCertInfo(opts: { certId: number; userId: number; }) {
const certInfoService = this.ctx.getApp().getApplicationContext().get<CertInfoService>("CertInfoService")
const { certId, userId } = opts;
return await certInfoService.getCertInfo({
certId,
userId: Number(userId),
});
};
async updateCert(opts: { certId: any; userId: any; cert: any; }){
const certUploadService = this.ctx.getApp().getApplicationContext().get<CertUploadService>("CertUploadService")
return await certUploadService.updateCert({
id:opts.certId,
userId:opts.userId,
cert:opts.cert
});
}
}
@@ -36,7 +36,6 @@ import { NotificationService } from "./notification-service.js";
import { NotificationGetter } from "./notification-getter.js";
import { UserSuiteEntity, UserSuiteService } from "@certd/commercial-core";
import { CertInfoService } from "../../monitor/service/cert-info-service.js";
import {CertApplyUploadService} from "./cert-apply-upload-service.js";
const runningTasks: Map<string | number, Executor> = new Map();
@@ -93,8 +92,6 @@ export class PipelineService extends BaseService<PipelineEntity> {
@Inject()
certInfoService: CertInfoService;
@Inject()
certApplyUploadService: CertApplyUploadService;
//@ts-ignore
getRepository() {
return this.repository;
@@ -196,10 +193,11 @@ export class PipelineService extends BaseService<PipelineEntity> {
await this.registerTriggerById(bean.id);
//保存域名信息到certInfo表
if(bean.from !== 'cert_upload'){
await this.certInfoService.updateDomains(pipeline.id, pipeline.userId || bean.userId, domains);
let fromType = 'pipeline';
if(bean.type === 'cert_upload') {
fromType = 'upload';
}
await this.certInfoService.updateDomains(pipeline.id, pipeline.userId || bean.userId, domains,fromType);
return bean;
}
@@ -483,9 +481,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
const siteInfo = await this.sysSettingsService.getSetting<SysSiteInfo>(SysSiteInfo);
sysInfo.title = siteInfo.title;
}
const serviceContainer = {
CertApplyUploadService: this.certApplyUploadService
}
const serviceContainer = {}
const serviceGetter = {
get:(name: string) => {
return serviceContainer[name]