mirror of
https://github.com/certd/certd.git
synced 2026-04-23 19:57:27 +08:00
feat: 上传证书到服务器,执行远程脚本
This commit is contained in:
@@ -3,12 +3,14 @@ import DefaultPlugins from '@certd/plugins'
|
||||
import logger from './util.log.js'
|
||||
import _ from 'lodash'
|
||||
import dayjs from 'dayjs'
|
||||
import { Trace } from './trace.js'
|
||||
export class Executor {
|
||||
constructor (args = {}) {
|
||||
const { plugins } = args
|
||||
this.plugins = {}
|
||||
this.usePlugins(DefaultPlugins)
|
||||
this.usePlugins(plugins)
|
||||
this.trace = new Trace()
|
||||
}
|
||||
|
||||
use (plugin) {
|
||||
@@ -32,17 +34,18 @@ export class Executor {
|
||||
|
||||
async run (options, args) {
|
||||
try {
|
||||
return await this.doRun(options, args)
|
||||
if (args != null) {
|
||||
_.merge(options.args, args)
|
||||
}
|
||||
return await this.doRun(options)
|
||||
} catch (e) {
|
||||
logger.error('任务执行出错:', e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
async doRun (options, args) {
|
||||
if (args != null) {
|
||||
_.merge(options.args, args)
|
||||
}
|
||||
async doRun (options) {
|
||||
// 申请证书
|
||||
logger.info('任务开始')
|
||||
const certd = new Certd(options)
|
||||
const cert = await this.runCertd(certd)
|
||||
@@ -50,28 +53,36 @@ export class Executor {
|
||||
throw new Error('申请证书失败')
|
||||
}
|
||||
logger.info('证书保存路径:', cert.certDir)
|
||||
|
||||
logger.info('----------------------')
|
||||
if (!cert.isNew) {
|
||||
// 如果没有更新
|
||||
if (!options.args.forceDeploy) {
|
||||
if (!options.args?.forceDeploy && !options.args?.forceRedeploy) {
|
||||
// 且不需要强制运行deploy
|
||||
logger.info('证书无更新,无需重新部署')
|
||||
logger.info('任务完成')
|
||||
return { cert }
|
||||
}
|
||||
}
|
||||
|
||||
let context = {}
|
||||
// 读取上次执行进度
|
||||
let context = {
|
||||
certIsNew: !!cert.isNew
|
||||
}
|
||||
const contextJson = await certd.certStore.getCurrentFile('context.json')
|
||||
if (contextJson) {
|
||||
context = JSON.parse(contextJson)
|
||||
}
|
||||
|
||||
const trace = new Trace(context)
|
||||
// 运行部署任务
|
||||
try {
|
||||
await this.runDeploys({ options, cert, context })
|
||||
await this.runDeploys({ options, cert, context, trace })
|
||||
} finally {
|
||||
await certd.certStore.setCurrentFile('context.json', JSON.stringify(context))
|
||||
}
|
||||
|
||||
logger.info('任务完成')
|
||||
trace.print()
|
||||
return {
|
||||
cert,
|
||||
context
|
||||
@@ -79,54 +90,69 @@ export class Executor {
|
||||
}
|
||||
|
||||
async runCertd (certd) {
|
||||
logger.info(`申请证书${JSON.stringify(certd.options.cert.domains)}开始`)
|
||||
logger.info(`证书任务 ${JSON.stringify(certd.options.cert.domains)} 开始`)
|
||||
const cert = await certd.certApply()
|
||||
logger.info(`申请证书${JSON.stringify(certd.options.cert.domains)}完成`)
|
||||
logger.info(`证书任务 ${JSON.stringify(certd.options.cert.domains)} 完成`)
|
||||
return cert
|
||||
}
|
||||
|
||||
async runDeploys ({ options, cert, context }) {
|
||||
async runDeploys ({ options, cert, context, trace }) {
|
||||
if (cert == null) {
|
||||
const certd = new Certd(options)
|
||||
cert = await certd.readCurrentCert()
|
||||
}
|
||||
logger.info('部署任务开始')
|
||||
for (const deploy of options.deploy) {
|
||||
logger.info(`--部署任务【${deploy.deployName}】开始`)
|
||||
const deployName = deploy.deployName
|
||||
logger.info(`------------【${deployName}】-----------`)
|
||||
if (deploy.disabled === true) {
|
||||
logger.info('----此部署任务已被禁用,跳过')
|
||||
logger.info('此流程已被禁用,跳过')
|
||||
logger.info('')
|
||||
trace.set({ deployName, value: { current: 'skip', status: 'disabled', remark: '流程禁用' } })
|
||||
continue
|
||||
}
|
||||
for (const task of deploy.tasks) {
|
||||
await this.runTask({ options, cert, task, context })
|
||||
try {
|
||||
for (const task of deploy.tasks) {
|
||||
if (context[deployName] == null) {
|
||||
context[deployName] = {}
|
||||
}
|
||||
const taskContext = context[deployName]
|
||||
await this.runTask({ options, cert, task, context: taskContext, deploy, trace })
|
||||
}
|
||||
|
||||
trace.set({ deployName, value: { status: 'success', remark: '执行成功' } })
|
||||
} catch (e) {
|
||||
trace.set({ deployName, value: { status: 'error', remark: '执行失败:' + e.message } })
|
||||
logger.error('流程执行失败', e)
|
||||
}
|
||||
logger.info(`--部署任务【${deploy.deployName}】完成`)
|
||||
|
||||
logger.info('')
|
||||
}
|
||||
}
|
||||
|
||||
async runTask ({ options, task, cert, context }) {
|
||||
async runTask ({ options, task, cert, context, deploy, trace }) {
|
||||
const taskType = task.type
|
||||
const Plugin = this.plugins[taskType]
|
||||
const deployName = deploy.deployName
|
||||
const taskName = task.taskName
|
||||
if (Plugin == null) {
|
||||
throw new Error(`----插件:${taskType}还未安装`)
|
||||
throw new Error(`插件:${taskType}还未安装`)
|
||||
}
|
||||
|
||||
logger.info(`----任务【${task.taskName}】开始执行`)
|
||||
let instance = Plugin
|
||||
if (Plugin instanceof Function) {
|
||||
instance = new Plugin()
|
||||
instance = new Plugin({ accessProviders: options.accessProviders })
|
||||
}
|
||||
if (context.progress && context.progress[task.taskName] && context.progress[task.taskName].success) {
|
||||
logger.info(`----任务【${task.taskName}】已经执行完成,跳过此任务`)
|
||||
const traceStatus = trace.get({ deployName: deploy.deployName, taskName: taskName })
|
||||
if (traceStatus?.status === 'success' && !options?.args?.forceRedeploy) {
|
||||
logger.info(`----【${taskName}】已经执行完成,跳过此任务`)
|
||||
trace.set({ deployName, taskName, value: { current: 'skip', status: 'success', remark: '已执行成功过,本次跳过' } })
|
||||
return
|
||||
}
|
||||
await instance.execute({ cert, accessProviders: options.accessProviders, props: task.props, context })
|
||||
if (context.progress == null) {
|
||||
context.progress = {}
|
||||
}
|
||||
context.progress[task.taskName] = {
|
||||
success: true,
|
||||
time: dayjs().format()
|
||||
}
|
||||
logger.info(`----任务【${task.taskName}】执行完成`)
|
||||
logger.info(`----【${taskName}】开始执行`)
|
||||
await instance.execute({ cert, props: task.props, context })
|
||||
trace.set({ deployName, taskName, value: { current: 'success', status: 'success', remark: '执行成功', time: dayjs().format() } })
|
||||
logger.info(`----任务【${taskName}】执行完成`)
|
||||
logger.info('')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
import logger from './util.log.js'
|
||||
import _ from 'lodash'
|
||||
export class Trace {
|
||||
constructor (context) {
|
||||
this.context = context
|
||||
}
|
||||
|
||||
set ({ deployName, taskName, prop, value }) {
|
||||
const key = this.buildTraceKey({ deployName, taskName, prop })
|
||||
const oldValue = _.get(this.context, key) || {}
|
||||
_.merge(oldValue, value)
|
||||
_.set(this.context, key, oldValue)
|
||||
}
|
||||
|
||||
get ({ deployName, taskName, prop }) {
|
||||
return _.get(this.context, this.buildTraceKey({ deployName, taskName, prop }))
|
||||
}
|
||||
|
||||
buildTraceKey ({ deployName, taskName, prop }) {
|
||||
let key = '__trace__'
|
||||
if (deployName) {
|
||||
key += '.'
|
||||
key += deployName.replace(/\./g, '_')
|
||||
}
|
||||
if (taskName) {
|
||||
key += '.tasks.'
|
||||
key += taskName.replace(/\./g, '_')
|
||||
}
|
||||
if (prop) {
|
||||
key += '.' + prop
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
getStringLength (str) {
|
||||
const enLength = str.replace(/[\u0391-\uFFE5]/g, '').length // 先把中文替换成两个字节的英文,再计算长度
|
||||
return Math.floor((str.length - enLength) * 1.5) + enLength
|
||||
}
|
||||
|
||||
print () {
|
||||
const context = this.context
|
||||
logger.info('---------------------------任务结果总览--------------------------')
|
||||
if (!context.certIsNew) {
|
||||
this.printTraceLine({ current: 'skip', remark: '还未到过期时间,跳过' }, '更新证书')
|
||||
} else {
|
||||
this.printTraceLine({ current: 'success', remark: '证书更新成功' }, '更新证书')
|
||||
}
|
||||
const trace = this.get({ })
|
||||
// logger.info('trace', trace)
|
||||
for (const deployName in trace) {
|
||||
if (trace[deployName] == null) {
|
||||
trace[deployName] = {}
|
||||
}
|
||||
const traceStatus = this.printTraceLine(trace[deployName], deployName)
|
||||
|
||||
const tasks = traceStatus.tasks
|
||||
if (tasks) {
|
||||
for (const taskName in tasks) {
|
||||
if (tasks[taskName] == null) {
|
||||
tasks[taskName] = {}
|
||||
}
|
||||
this.printTraceLine(tasks[taskName], taskName, ' └')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printTraceLine (traceStatus, name, prefix = '') {
|
||||
const length = this.getStringLength(name)
|
||||
const endPad = _.repeat('-', 45 - prefix.length - length) + '\t'
|
||||
const status = traceStatus.current || traceStatus.status || ''
|
||||
const remark = traceStatus.remark || ''
|
||||
logger.info(`${prefix}【${name}】${endPad}[${status}] \t${remark}`)
|
||||
return traceStatus
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user