mirror of https://github.com/certd/certd
chore:
parent
162ebfd4e0
commit
7d96a57d73
|
@ -27,8 +27,7 @@ export abstract class CertApplyBaseConvertPlugin extends AbstractTaskPlugin {
|
||||||
"1、支持多个域名打到一个证书上,例如: foo.com,*.foo.com,*.bar.com\n" +
|
"1、支持多个域名打到一个证书上,例如: foo.com,*.foo.com,*.bar.com\n" +
|
||||||
"2、子域名被通配符包含的不要填写,例如:www.foo.com已经被*.foo.com包含,不要填写www.foo.com\n" +
|
"2、子域名被通配符包含的不要填写,例如:www.foo.com已经被*.foo.com包含,不要填写www.foo.com\n" +
|
||||||
"3、泛域名只能通配*号那一级(*.foo.com的证书不能用于xxx.yyy.foo.com、不能用于foo.com)\n" +
|
"3、泛域名只能通配*号那一级(*.foo.com的证书不能用于xxx.yyy.foo.com、不能用于foo.com)\n" +
|
||||||
"4、输入一个,空格之后,再输入下一个\n" +
|
"4、输入一个,空格之后,再输入下一个",
|
||||||
"5、如果你配置了子域托管解析,请先[设置托管子域名](#/certd/pipeline/subDomain)",
|
|
||||||
})
|
})
|
||||||
domains!: string[];
|
domains!: string[];
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { AliyunAccess } from "../aliyun";
|
||||||
|
import { HttpClient, ILogger } from "@certd/basic";
|
||||||
|
import { IOssClient, OssClientDeleteReq } from "./api";
|
||||||
|
|
||||||
|
export class AliossClient implements IOssClient {
|
||||||
|
access: AliyunAccess;
|
||||||
|
logger: ILogger;
|
||||||
|
http: HttpClient;
|
||||||
|
|
||||||
|
constructor(opts: { access: AliyunAccess; http: HttpClient; logger: ILogger }) {
|
||||||
|
this.access = opts.access;
|
||||||
|
this.http = opts.http;
|
||||||
|
this.logger = opts.logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
upload(key: string, content: Buffer | string): Promise<void> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
download(key: string, savePath?: string): Promise<void> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
delete(opts: OssClientDeleteReq): Promise<void> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
export type OssClientDeleteReq = {
|
||||||
|
key: string;
|
||||||
|
beforeDays?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface IOssClient {
|
||||||
|
upload(key: string, content: Buffer | string): Promise<void>;
|
||||||
|
|
||||||
|
download(key: string, savePath?: string): Promise<void>;
|
||||||
|
|
||||||
|
delete(opts: OssClientDeleteReq): Promise<void>;
|
||||||
|
}
|
|
@ -98,17 +98,17 @@ export const certdResources = [
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
title: "子域名托管设置",
|
// title: "子域名托管设置",
|
||||||
name: "SubDomain",
|
// name: "SubDomain",
|
||||||
path: "/certd/pipeline/subDomain",
|
// path: "/certd/pipeline/subDomain",
|
||||||
component: "/certd/pipeline/sub-domain/index.vue",
|
// component: "/certd/pipeline/sub-domain/index.vue",
|
||||||
meta: {
|
// meta: {
|
||||||
icon: "material-symbols:approval-delegation-outline",
|
// icon: "material-symbols:approval-delegation-outline",
|
||||||
auth: true,
|
// auth: true,
|
||||||
keepAlive: true,
|
// keepAlive: true,
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
title: "流水线分组管理",
|
title: "流水线分组管理",
|
||||||
name: "PipelineGroupManager",
|
name: "PipelineGroupManager",
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
import {IsTaskPlugin, pluginGroups, RunStrategy, TaskInput} from '@certd/pipeline';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { AbstractPlusTaskPlugin } from '@certd/plugin-plus';
|
import {AbstractPlusTaskPlugin} from '@certd/plugin-plus';
|
||||||
import JSZip from 'jszip';
|
import JSZip from 'jszip';
|
||||||
import * as os from 'node:os';
|
import * as os from 'node:os';
|
||||||
import { SshAccess, SshClient } from '@certd/plugin-lib';
|
import {SshAccess, SshClient} from '@certd/plugin-lib';
|
||||||
|
|
||||||
const defaultBackupDir = 'certd_backup';
|
const defaultBackupDir = 'certd_backup';
|
||||||
const defaultFilePrefix = 'db-backup';
|
const defaultFilePrefix = 'db-backup';
|
||||||
|
|
||||||
@IsTaskPlugin({
|
@IsTaskPlugin({
|
||||||
name: 'DBBackupPlugin',
|
name: 'DBBackupPlugin',
|
||||||
title: '数据库备份',
|
title: '数据库备份',
|
||||||
|
@ -30,8 +31,9 @@ export class DBBackupPlugin extends AbstractPlusTaskPlugin {
|
||||||
component: {
|
component: {
|
||||||
name: 'a-select',
|
name: 'a-select',
|
||||||
options: [
|
options: [
|
||||||
{ label: '本地复制', value: 'local' },
|
{label: '本地复制', value: 'local'},
|
||||||
{ label: 'ssh上传', value: 'ssh' },
|
{label: 'ssh上传', value: 'ssh'},
|
||||||
|
{label: 'oss上传', value: 'oss'},
|
||||||
],
|
],
|
||||||
placeholder: '',
|
placeholder: '',
|
||||||
},
|
},
|
||||||
|
@ -57,6 +59,51 @@ export class DBBackupPlugin extends AbstractPlusTaskPlugin {
|
||||||
})
|
})
|
||||||
sshAccessId!: number;
|
sshAccessId!: number;
|
||||||
|
|
||||||
|
|
||||||
|
@TaskInput({
|
||||||
|
title: 'OSS类型',
|
||||||
|
component: {
|
||||||
|
name: 'a-input',
|
||||||
|
options: [
|
||||||
|
{value: "aliyun", label: "阿里云OSS"},
|
||||||
|
{value: "s3", label: "MinIO/S3"},
|
||||||
|
{value: "qiniu", label: "七牛云"},
|
||||||
|
{value: "tencent", label: "腾讯云COS"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
mergeScript: `
|
||||||
|
return {
|
||||||
|
show:ctx.compute(({form})=>{
|
||||||
|
return form.backupMode === 'oss';
|
||||||
|
})
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
ossType!: string;
|
||||||
|
|
||||||
|
@TaskInput({
|
||||||
|
title: 'OSS授权',
|
||||||
|
component: {
|
||||||
|
name: 'access-selector',
|
||||||
|
},
|
||||||
|
mergeScript: `
|
||||||
|
return {
|
||||||
|
show:ctx.compute(({form})=>{
|
||||||
|
return form.backupMode === 'ssh';
|
||||||
|
}),
|
||||||
|
component:{
|
||||||
|
type: ctx.compute(({form})=>{
|
||||||
|
return form.ossType;
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
ossAccessId!: number;
|
||||||
|
|
||||||
|
|
||||||
@TaskInput({
|
@TaskInput({
|
||||||
title: '备份保存目录',
|
title: '备份保存目录',
|
||||||
component: {
|
component: {
|
||||||
|
@ -104,7 +151,9 @@ export class DBBackupPlugin extends AbstractPlusTaskPlugin {
|
||||||
})
|
})
|
||||||
retainDays!: number;
|
retainDays!: number;
|
||||||
|
|
||||||
async onInstance() {}
|
async onInstance() {
|
||||||
|
}
|
||||||
|
|
||||||
async execute(): Promise<void> {
|
async execute(): Promise<void> {
|
||||||
this.logger.info('开始备份数据库');
|
this.logger.info('开始备份数据库');
|
||||||
|
|
||||||
|
@ -118,7 +167,7 @@ export class DBBackupPlugin extends AbstractPlusTaskPlugin {
|
||||||
const dbZipFilename = `${dbTmpFilename}.zip`;
|
const dbZipFilename = `${dbTmpFilename}.zip`;
|
||||||
const tempDir = path.resolve(os.tmpdir(), 'certd_backup');
|
const tempDir = path.resolve(os.tmpdir(), 'certd_backup');
|
||||||
if (!fs.existsSync(tempDir)) {
|
if (!fs.existsSync(tempDir)) {
|
||||||
await fs.promises.mkdir(tempDir, { recursive: true });
|
await fs.promises.mkdir(tempDir, {recursive: true});
|
||||||
}
|
}
|
||||||
const dbTmpPath = path.resolve(tempDir, dbTmpFilename);
|
const dbTmpPath = path.resolve(tempDir, dbTmpFilename);
|
||||||
const dbZipPath = path.resolve(tempDir, dbZipFilename);
|
const dbZipPath = path.resolve(tempDir, dbZipFilename);
|
||||||
|
@ -129,14 +178,14 @@ export class DBBackupPlugin extends AbstractPlusTaskPlugin {
|
||||||
const zip = new JSZip();
|
const zip = new JSZip();
|
||||||
const stream = fs.createReadStream(dbTmpPath);
|
const stream = fs.createReadStream(dbTmpPath);
|
||||||
// 使用流的方式添加文件内容
|
// 使用流的方式添加文件内容
|
||||||
zip.file(dbTmpFilename, stream, { binary: true, compression: 'DEFLATE' });
|
zip.file(dbTmpFilename, stream, {binary: true, compression: 'DEFLATE'});
|
||||||
|
|
||||||
const uploadDir = path.resolve('data', 'upload');
|
const uploadDir = path.resolve('data', 'upload');
|
||||||
if (this.withUpload && fs.existsSync(uploadDir)) {
|
if (this.withUpload && fs.existsSync(uploadDir)) {
|
||||||
zip.folder(uploadDir);
|
zip.folder(uploadDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
const content = await zip.generateAsync({ type: 'nodebuffer' });
|
const content = await zip.generateAsync({type: 'nodebuffer'});
|
||||||
|
|
||||||
await fs.promises.writeFile(dbZipPath, content);
|
await fs.promises.writeFile(dbZipPath, content);
|
||||||
this.logger.info(`数据库文件压缩完成:${dbZipPath}`);
|
this.logger.info(`数据库文件压缩完成:${dbZipPath}`);
|
||||||
|
@ -164,7 +213,7 @@ export class DBBackupPlugin extends AbstractPlusTaskPlugin {
|
||||||
}
|
}
|
||||||
const dir = path.dirname(backupPath);
|
const dir = path.dirname(backupPath);
|
||||||
if (!fs.existsSync(dir)) {
|
if (!fs.existsSync(dir)) {
|
||||||
await fs.promises.mkdir(dir, { recursive: true });
|
await fs.promises.mkdir(dir, {recursive: true});
|
||||||
}
|
}
|
||||||
backupPath = path.resolve(backupPath);
|
backupPath = path.resolve(backupPath);
|
||||||
await fs.promises.copyFile(dbPath, backupPath);
|
await fs.promises.copyFile(dbPath, backupPath);
|
||||||
|
@ -195,7 +244,7 @@ export class DBBackupPlugin extends AbstractPlusTaskPlugin {
|
||||||
this.logger.info('备份目录:', backupPath);
|
this.logger.info('备份目录:', backupPath);
|
||||||
await sshClient.uploadFiles({
|
await sshClient.uploadFiles({
|
||||||
connectConf: access,
|
connectConf: access,
|
||||||
transports: [{ localPath: dbPath, remotePath: backupPath }],
|
transports: [{localPath: dbPath, remotePath: backupPath}],
|
||||||
mkdirs: true,
|
mkdirs: true,
|
||||||
});
|
});
|
||||||
this.logger.info('备份文件上传完成');
|
this.logger.info('备份文件上传完成');
|
||||||
|
@ -224,4 +273,5 @@ export class DBBackupPlugin extends AbstractPlusTaskPlugin {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
new DBBackupPlugin();
|
new DBBackupPlugin();
|
||||||
|
|
Loading…
Reference in New Issue