perf: 触发证书重新申请input变化对比规则优化,减少升级版本后触发申请证书的情况

pull/229/head
xiaojunnuo 2024-10-16 12:20:42 +08:00
parent 84fd3b250d
commit c46a2a9a39
10 changed files with 57 additions and 18 deletions

View File

@ -181,6 +181,9 @@ export class RunnableCollection {
if (runnable?.status) { if (runnable?.status) {
runnable.status.status = ResultType.none; runnable.status.status = ResultType.none;
runnable.status.result = ResultType.none; runnable.status.result = ResultType.none;
runnable.status.inputHash = "";
// @ts-ignore
runnable.input = {};
} }
} }

View File

@ -121,7 +121,6 @@ export type HistoryResultGroup = {
}; };
}; };
export type HistoryResult = { export type HistoryResult = {
// input: any;
inputHash?: string; inputHash?: string;
output: any; output: any;
files?: FileItem[]; files?: FileItem[];

View File

@ -5,6 +5,7 @@ import { CertReader } from "./cert-reader.js";
import JSZip from "jszip"; import JSZip from "jszip";
import { CertConverter } from "./convert.js"; import { CertConverter } from "./convert.js";
import fs from "fs"; import fs from "fs";
import { pick } from "lodash-es";
export { CertReader }; export { CertReader };
export type { CertInfo }; export type { CertInfo };
@ -203,10 +204,35 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
return null; return null;
} }
const inputChanged = this.ctx.inputChanged; let inputChanged = this.ctx.inputChanged;
if (inputChanged) { if (inputChanged) {
this.logger.info("输入参数变更,准备申请新证书"); this.logger.info("input hash 有变更,检查是否需要重新申请证书");
return null; //判断域名有没有变更
/**
* "renewDays": 20,
* "certApplyPlugin": "CertApply",
* "sslProvider": "letsencrypt",
* "privateKeyType": "rsa_2048_pkcs1",
* "dnsProviderType": "aliyun",
* "domains": [
* "*.handsfree.work"
* ],
* "email": "xiaojunnuo@qq.com",
* "dnsProviderAccess": 3,
* "useProxy": false,
* "skipLocalVerify": false,
* "successNotify": true,
* "pfxPassword": "123456"
*/
const checkInputChanges = ["domains", "sslProvider", "privateKeyType", "dnsProviderType", "dnsProviderAccess", "pfxPassword"];
const oldInput = JSON.stringify(pick(this.lastStatus?.input, checkInputChanges));
const thisInput = JSON.stringify(pick(this, checkInputChanges));
inputChanged = oldInput !== thisInput;
if (inputChanged) {
this.logger.info("输入参数变更,准备申请新证书");
return null;
}
} }
let oldCert: CertReader | undefined = undefined; let oldCert: CertReader | undefined = undefined;

View File

@ -6,7 +6,6 @@ import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, Edi
import { useUserStore } from "/@/store/modules/user"; import { useUserStore } from "/@/store/modules/user";
import { useSettingStore } from "/@/store/modules/settings"; import { useSettingStore } from "/@/store/modules/settings";
import { message } from "ant-design-vue"; import { message } from "ant-design-vue";
import { DoVerify } from "./api";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const router = useRouter(); const router = useRouter();
@ -125,9 +124,9 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
}), }),
form: { form: {
component: { component: {
onDictChange: ({ form, dict }) => { onDictChange: ({ form, dict }: any) => {
if (!form.cnameProviderId) { if (!form.cnameProviderId) {
const item = dict.data.find((item) => item.isDefault); const item = dict.data.find((item: any) => item.isDefault);
if (item) { if (item) {
form.cnameProviderId = item.id; form.cnameProviderId = item.id;
} }
@ -180,7 +179,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
message.success("验证成功"); message.success("验证成功");
row.status = "valid"; row.status = "valid";
} }
} catch (e) { } catch (e: any) {
console.error(e); console.error(e);
message.error(e.message); message.error(e.message);
} finally { } finally {

View File

@ -8,7 +8,7 @@
<div class="title"> <div class="title">
<div>{{ item.name }}({{ item.fileName }})</div> <div>{{ item.name }}({{ item.fileName }})</div>
<fs-copyable :model-value="item.content" :button="{ show: false }"> <fs-copyable :model-value="item.content" :button="{ show: false }">
<a-tag type="success">复制</a-tag> <a-tag color="success">复制</a-tag>
</fs-copyable> </fs-copyable>
</div> </div>
</template> </template>

View File

@ -155,7 +155,7 @@ export default function ({ crudExpose, context: { certdFormRef } }: CreateCrudOp
const viewCert = async (row: any) => { const viewCert = async (row: any) => {
const cert = await api.GetCert(row.id); const cert = await api.GetCert(row.id);
if (!cert) { if (!cert) {
notification.error({ message: "还没有产生证书,请先运行流水线" }); notification.error({ message: "请先运行一次流水线" });
return; return;
} }

View File

@ -101,7 +101,7 @@
<fs-icon <fs-icon
v-if="!editMode" v-if="!editMode"
class="pointer color-blue ml-2" class="pointer color-blue ml-2"
title="重新运行此步骤" title="完全重新运行此步骤"
icon="SyncOutlined" icon="SyncOutlined"
@click="run(item.id)" @click="run(item.id)"
></fs-icon> ></fs-icon>

View File

@ -64,6 +64,7 @@
"iconv-lite": "^0.6.3", "iconv-lite": "^0.6.3",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"jsonwebtoken": "^9.0.0", "jsonwebtoken": "^9.0.0",
"jszip": "^3.10.1",
"koa-send": "^5.0.1", "koa-send": "^5.0.1",
"kubernetes-client": "^9.0.0", "kubernetes-client": "^9.0.0",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",

View File

@ -102,7 +102,7 @@ export class AsyncSsh2Client {
let iconv: any = await import('iconv-lite'); let iconv: any = await import('iconv-lite');
iconv = iconv.default; iconv = iconv.default;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.logger.info(`执行命令:[${this.connConf.host}][exec]: ` + script); this.logger.info(`执行命令:[${this.connConf.host}][exec]: \n` + script);
this.conn.exec(script, (err: Error, stream: any) => { this.conn.exec(script, (err: Error, stream: any) => {
if (err) { if (err) {
reject(err); reject(err);
@ -274,7 +274,7 @@ export class SshClient {
let { script } = options; let { script } = options;
const { connectConf } = options; const { connectConf } = options;
this.logger.info('命令:', script); // this.logger.info('命令:', script);
return await this._call({ return await this._call({
connectConf, connectConf,
callable: async (conn: AsyncSsh2Client) => { callable: async (conn: AsyncSsh2Client) => {

View File

@ -4,6 +4,8 @@ import path from 'path';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { SshAccess, SshClient } from '../../plugin-host/index.js'; import { SshAccess, SshClient } from '../../plugin-host/index.js';
import { AbstractPlusTaskPlugin } from '@certd/plugin-plus'; import { AbstractPlusTaskPlugin } from '@certd/plugin-plus';
import JSZip from 'jszip';
import * as os from 'node:os';
const defaultBackupDir = 'certd_backup'; const defaultBackupDir = 'certd_backup';
const defaultFilePrefix = 'db-backup'; const defaultFilePrefix = 'db-backup';
@ -100,16 +102,25 @@ export class DBBackupPlugin extends AbstractPlusTaskPlugin {
return; return;
} }
this.logger.info('当前备份方式:', this.backupMode); //本地压缩
const zip = new JSZip();
zip.file(dbPath);
const content = await zip.generateAsync({ type: 'nodebuffer' });
const dbZipFilename = `${this.filePrefix}.${dayjs().format('YYYYMMDD.HHmmss')}.sqlite.zip`;
const dbZipPath = path.resolve(os.tmpdir(), dbZipFilename);
await fs.promises.writeFile(dbZipPath, content);
this.logger.info(`数据库文件压缩完成:${dbZipPath}`);
this.logger.info('开始备份,当前备份方式:', this.backupMode);
const backupDir = this.backupDir || defaultBackupDir; const backupDir = this.backupDir || defaultBackupDir;
const backupFile = `${backupDir}/${this.filePrefix}.${dayjs().format('YYYYMMDD.HHmmss')}.sqlite`; const backupFilePath = `${backupDir}/${dbZipFilename}`;
if (this.backupMode === 'local') { if (this.backupMode === 'local') {
await this.localBackup(dbPath, backupDir, backupFile); await this.localBackup(dbPath, backupDir, backupFilePath);
} else if (this.backupMode === 'ssh') { } else if (this.backupMode === 'ssh') {
await this.sshBackup(dbPath, backupDir, backupFile); await this.sshBackup(dbPath, backupDir, backupFilePath);
} else if (this.backupMode === 'oss') { } else if (this.backupMode === 'oss') {
await this.ossBackup(dbPath, backupDir, backupFile); await this.ossBackup(dbPath, backupDir, backupFilePath);
} else { } else {
throw new Error(`不支持的备份方式:${this.backupMode}`); throw new Error(`不支持的备份方式:${this.backupMode}`);
} }