diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..2c73e4957 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "packages/node-acme-client"] + path = packages/node-acme-client + url = https://github.com/certd/node-acme-client diff --git a/package.json b/package.json index 2079bf74f..a3adbfe67 100644 --- a/package.json +++ b/package.json @@ -4,5 +4,8 @@ "devDependencies": { "lerna": "^3.18.4" }, + "scripts": { + "submodule":"git submodule update --init --recursive" + }, "license": "MIT" } diff --git a/packages/certd/package.json b/packages/certd/package.json index feb5b56c7..3200c4f00 100644 --- a/packages/certd/package.json +++ b/packages/certd/package.json @@ -12,10 +12,10 @@ "dependencies": { "@alicloud/pop-core": "^1.7.10", "@types/node": "^14.14.13", - "acme-client": "^4.1.2", "dayjs": "^1.9.7", "lodash": "^4.17.20", - "log4js": "^6.3.0" + "log4js": "^6.3.0", + "@certd/acme-client": "^0.0.1" }, "devDependencies": { "chai": "^4.2.0", diff --git a/packages/certd/src/acme.js b/packages/certd/src/acme.js index e4438d126..f55d19437 100644 --- a/packages/certd/src/acme.js +++ b/packages/certd/src/acme.js @@ -1,5 +1,5 @@ -import acme from './acme/index.cjs' import log from './utils/util.log.js' +import acme from '@certd/acme-client' import _ from 'lodash' import sleep from './utils/util.sleep.js' export class AcmeService { @@ -27,7 +27,10 @@ export class AcmeService { const key = await this.getAccountKey(email) const client = new acme.Client({ directoryUrl: acme.directory.letsencrypt.staging, - accountKey: key + accountKey: key, + backoffAttempts: 10, + backoffMin: 5000, + backoffMax: 30000 }) return client } @@ -125,7 +128,7 @@ export class AcmeService { csr, email: email, termsOfServiceAgreed: true, - challengePriority: ['dns-01', 'http-01'], + challengePriority: ['dns-01'], challengeCreateFn: (authz, challenge, keyAuthorization) => { return this.challengeCreateFn(authz, challenge, keyAuthorization, dnsProvider) }, diff --git a/packages/certd/src/acme/index.cjs b/packages/certd/src/acme/index.cjs index e79a92109..e349fb07f 100644 --- a/packages/certd/src/acme/index.cjs +++ b/packages/certd/src/acme/index.cjs @@ -1,4 +1,3 @@ -process.env.DEBUG = '*' /** * acme-client */ diff --git a/packages/certd/src/index.js b/packages/certd/src/index.js index 9b77b2307..99131f711 100644 --- a/packages/certd/src/index.js +++ b/packages/certd/src/index.js @@ -1,13 +1,12 @@ +import logger from './utils/util.log.js' import { AcmeService } from './acme.js' import { FileStore } from './store/file-store.js' import { DnsProviderFactory } from './dns-provider/dns-provider-factory.js' import dayjs from 'dayjs' import path from 'path' -import _ from 'lodash' import fs from 'fs' import util from './utils/util.js' import forge from 'node-forge' -process.env.DEBUG = '*' export class Certd { constructor (options) { this.store = new FileStore() @@ -15,73 +14,150 @@ export class Certd { this.options = options } + getMainDomain (domains) { + if (domains == null) { + return null + } + if (typeof domains === 'string') { + return domains + } + if (domains.length > 0) { + return domains[0] + } + } + + buildDomainFileName (domains) { + const domain = this.getMainDomain(domains) + return domain.replace(/\*/g, '_') + } + buildCertDir (email, domains) { - let domainStr = _.join(domains) - domainStr = domainStr.replace(/\*/g, '') - const dir = path.join(email, '/certs/', domainStr) - return dir + const domainFileName = this.buildDomainFileName(domains) + return path.join(email, '/certs/', domainFileName) } async certApply (options) { if (options == null) { options = this.options } - const certOptions = options.cert + let oldCert + try { + oldCert = this.readCurrentCert(options.cert.email, options.cert.domains) + } catch (e) { + logger.warn('读取cert失败:', e) + } + + if (oldCert == null) { + logger.info('还未申请过,准备申请新证书') + } else { + const ret = this.isWillExpire(oldCert.expires, options.cert.renewDays) + if (!ret.isWillExpire) { + logger.info('证书还未过期:', oldCert.expires, ',剩余', ret.leftDays, '天') + if (options.args.forceCert) { + logger.info('准备强制更新证书') + } else { + logger.info('暂不更新证书') + + oldCert.isNew = false + return oldCert + } + } else { + logger.info('即将过期,准备更新证书') + } + } + + // 执行证书申请步骤 + return await this.doCertApply(options) + } + + async doCertApply (options) { const accessProviders = options.accessProviders - const providerOptions = accessProviders[certOptions.challenge.dnsProvider] + const providerOptions = accessProviders[options.cert.challenge.dnsProvider] const dnsProvider = await DnsProviderFactory.createByType(providerOptions.providerType, providerOptions) const cert = await this.acme.order({ - email: certOptions.email, - domains: certOptions.domains, + email: options.cert.email, + domains: options.cert.domains, dnsProvider: dnsProvider, - csrInfo: certOptions.csrInfo - + csrInfo: options.cert.csrInfo }) - this.writeCert(certOptions.email, certOptions.domains, cert) - const { detail, expires } = this.getDetailFromCrt(cert.crt) + const certDir = this.writeCert(options.cert.email, options.cert.domains, cert) + const { detail, expires } = this.getCrtDetail(cert.crt) return { ...cert, detail, - expires + expires, + certDir, + isNew: true } } writeCert (email, domains, cert) { const certFilesRootDir = this.buildCertDir(email, domains) const dirPath = path.join(certFilesRootDir, dayjs().format('YYYY.MM.DD.HHmmss')) - this.store.set(path.join(dirPath, '/cert.crt'), cert.crt) - this.store.set(path.join(dirPath, '/cert.key'), cert.key) - this.store.set(path.join(dirPath, '/cert.csr'), cert.csr) + + const domainFileName = this.buildDomainFileName(domains) + + this.store.set(path.join(dirPath, `/${domainFileName}.crt`), cert.crt) + this.store.set(path.join(dirPath, `/${domainFileName}.key`), cert.key) + this.store.set(path.join(dirPath, `/${domainFileName}.csr`), cert.csr) const linkPath = path.join(util.getUserBasePath(), certFilesRootDir, 'current') const lastPath = path.join(util.getUserBasePath(), dirPath) - // if (!fs.existsSync(linkPath)) { - // fs.mkdirSync(linkPath) - // } - fs.symlinkSync(lastPath, linkPath) + if (fs.existsSync(linkPath)) { + try { + fs.unlinkSync(linkPath) + } catch (e) { + logger.error('unlink error:', e) + } + } + fs.symlinkSync(lastPath, linkPath, 'dir') + + return linkPath } readCurrentCert (email, domains) { const certFilesRootDir = this.buildCertDir(email, domains) const currentPath = path.join(certFilesRootDir, 'current') + const domainFileName = this.buildDomainFileName(domains) - const crt = this.store.get(currentPath + '/cert.crt') - const key = this.store.get(currentPath + '/cert.key') - const csr = this.store.get(currentPath + '/cert.csr') - - const { detail, expires } = this.getDetailFromCrt(crt) - - const cert = { - crt, key, csr, detail, expires + const crt = this.store.get(currentPath + `/${domainFileName}.crt`) + if (crt == null) { + return null + } + const key = this.store.get(currentPath + `/${domainFileName}.key`) + const csr = this.store.get(currentPath + `/${domainFileName}.csr`) + + const { detail, expires } = this.getCrtDetail(crt) + + const certDir = path.join(util.getUserBasePath(), currentPath) + return { + crt, key, csr, detail, expires, certDir } - return cert } - getDetailFromCrt (crt) { + getCrtDetail (crt) { const pki = forge.pki const detail = pki.certificateFromPem(crt.toString()) const expires = detail.validity.notAfter return { detail, expires } } + + /** + * 检查是否过期,默认提前20天 + * @param expires + * @param maxDays + * @returns {boolean} + */ + isWillExpire (expires, maxDays = 20) { + if (expires == null) { + throw new Error('过期时间不能为空') + } + // 检查有效期 + const leftDays = dayjs(expires).diff(dayjs(), 'day') + return { + isWillExpire: leftDays < maxDays, + leftDays + } + } } diff --git a/packages/certd/test/options.js b/packages/certd/test/options.js index bb4f1e433..381fbe35a 100644 --- a/packages/certd/test/options.js +++ b/packages/certd/test/options.js @@ -1,5 +1,5 @@ import _ from 'lodash' -import optionsPrivate from '../../../test/options.private.js' +import optionsPrivate from '../../../test/options.private.mjs' const defaultOptions = { accessProviders: { aliyun: { diff --git a/packages/deployer/src/index.js b/packages/deployer/src/index.js deleted file mode 100644 index fe06d3bd8..000000000 --- a/packages/deployer/src/index.js +++ /dev/null @@ -1,34 +0,0 @@ -import Certd from '@certd/certd' -import CertdPlugins from '@certd/plugins' -import log from './util.log.js' -export class Deployer { - async run (options) { - const certd = new Certd() - const cert = certd.certApply(options) - const context = {} - for (const deploy of options.deploy) { - log.info(`-------部署任务【${deploy.deployName}】开始-------`) - - for (const task of deploy.tasks) { - await this.runTask({ options, cert, task, context }) - } - log.info(`-------部署任务【${deploy.deployName}】完成-------`) - } - return { - cert, - context - } - } - - async runTask ({ options, task, cert, context }) { - const taskType = task.type - const plugin = CertdPlugins[taskType] - if (plugin == null) { - throw new Error(`插件:${taskType}还未安装`) - } - - log.info(`--插件【${task.taskName}】开始执行-------`) - await plugin.execute({ cert, accessProviders: options.accessProviders, args: task, context }) - log.info(`--插件【${task.taskName}】执行完成-------`) - } -} diff --git a/packages/deployer/test/index.test.js b/packages/deployer/test/index.test.js deleted file mode 100644 index 92752d367..000000000 --- a/packages/deployer/test/index.test.js +++ /dev/null @@ -1,13 +0,0 @@ -import pkg from 'chai' -import options from './options.js' -import Deployer from '../src/index.js' -const { expect } = pkg -describe('AutoDeploy', function () { - it('#run', async function () { - const deploy = new Deployer() - const ret = deploy.run(options) - expect(ret).ok - expect(ret.cert).ok - expect(ret.AliyunCertId).ok - }) -}) diff --git a/packages/deployer/.eslintrc b/packages/executor/.eslintrc similarity index 100% rename from packages/deployer/.eslintrc rename to packages/executor/.eslintrc diff --git a/packages/deployer/package-lock.json b/packages/executor/package-lock.json similarity index 100% rename from packages/deployer/package-lock.json rename to packages/executor/package-lock.json diff --git a/packages/deployer/package.json b/packages/executor/package.json similarity index 95% rename from packages/deployer/package.json rename to packages/executor/package.json index 0bc4f5ed3..f9122a4a2 100644 --- a/packages/deployer/package.json +++ b/packages/executor/package.json @@ -1,5 +1,5 @@ { - "name": "@certd/samples", + "name": "@certd/executor", "version": "0.0.1", "description": "", "main": "./src/index.js", diff --git a/packages/executor/src/index.js b/packages/executor/src/index.js new file mode 100644 index 000000000..6dde91ec7 --- /dev/null +++ b/packages/executor/src/index.js @@ -0,0 +1,103 @@ +import { Certd } from '@certd/certd' +import DefaultPlugins from '@certd/plugins' +import logger from './util.log.js' +import _ from 'lodash' +export class Executor { + constructor (args = {}) { + this.certd = new Certd() + const { plugins } = args + this.initPlugins(plugins) + } + + use (plugin) { + if (plugin == null) { + return + } + this.plugins[plugin.name] = plugin + if (plugin.define) { + const define = plugin.define() + this.plugins[define.name] = plugin + } + } + + initPlugins (customPlugins) { + this.plugins = {} + for (const key in DefaultPlugins) { + this.use(DefaultPlugins[key]) + } + if (customPlugins) { + for (const plugin of customPlugins) { + this.use(plugin) + } + } + } + + async run (options, args) { + if (args != null) { + _.merge(options.args, args) + } + logger.info('任务开始') + const cert = await this.runCertd(options) + if (cert == null) { + throw new Error('申请证书失败') + } + logger.info('证书保存路径:', cert.certDir) + if (!cert.isNew) { + // 如果没有更新 + if (!options.args.forceDeploy) { + // 且不需要强制运行deploy + logger.info('证书无更新,无需重新部署') + logger.info('任务完成') + return { cert } + } + } + + const context = {} + await this.runDeploys({ options, cert, context }) + logger.info('任务完成') + return { + cert, + context + } + } + + async runCertd (options) { + logger.info(`申请证书${JSON.stringify(options.cert.domains)}开始`) + const cert = await this.certd.certApply(options) + logger.info(`申请证书${JSON.stringify(options.cert.domains)}完成`) + return cert + } + + async runDeploys ({ options, cert, context }) { + if (cert == null) { + cert = this.certd.readCurrentCert(options.cert.email, options.cert.domains) + } + for (const deploy of options.deploy) { + logger.info(`--部署任务【${deploy.name}】开始`) + if (deploy.disabled === true) { + logger.info('----此任务已被禁用,跳过') + break + } + for (const task of deploy.tasks) { + await this.runTask({ options, cert, task, context }) + } + logger.info(`--部署任务【${deploy.name}】完成`) + } + } + + async runTask ({ options, task, cert, context }) { + const taskType = task.type + const Plugin = this.plugins[taskType] + if (Plugin == null) { + throw new Error(`----插件:${taskType}还未安装`) + } + + logger.info(`----任务【${task.name}】开始执行`) + let instance = Plugin + if (Plugin instanceof Function) { + instance = new Plugin() + } + await instance.execute({ cert, accessProviders: options.accessProviders, args: task, context }) + logger.info(`----任务【${task.name}】执行完成`) + } +} diff --git a/packages/deployer/src/util.log.js b/packages/executor/src/util.log.js similarity index 52% rename from packages/deployer/src/util.log.js rename to packages/executor/src/util.log.js index 0abd05552..1156b735a 100644 --- a/packages/deployer/src/util.log.js +++ b/packages/executor/src/util.log.js @@ -5,3 +5,12 @@ log4js.configure({ }) const logger = log4js.getLogger('certd') export default logger + +// import debug from 'debug' +// debug.enable('info,debug,error,warn') +// export default { +// debug: debug('debug'), +// info: debug('info'), +// error: debug('error'), +// warn: debug('warn') +// } diff --git a/packages/executor/test/index.test.js b/packages/executor/test/index.test.js new file mode 100644 index 000000000..7dee2c7c8 --- /dev/null +++ b/packages/executor/test/index.test.js @@ -0,0 +1,25 @@ +import pkg from 'chai' +import options from './options.js' +import { Executor } from '../src/index.js' +const { expect } = pkg + +describe('AutoDeploy', function () { + it('#run', async function () { + const executor = new Executor() + const ret = await executor.run(options) + expect(ret).ok + expect(ret.cert).ok + }) + it('#forceCert', async function () { + const executor = new Executor() + const ret = await executor.run(options, { forceCert: true, forceDeploy: false }) + expect(ret).ok + expect(ret.cert).ok + }) + it('#forceDeploy', async function () { + const executor = new Executor() + const ret = await executor.run(options, { forceCert: false, forceDeploy: true }) + expect(ret).ok + expect(ret.cert).ok + }) +}) diff --git a/packages/deployer/test/options.js b/packages/executor/test/options.js similarity index 66% rename from packages/deployer/test/options.js rename to packages/executor/test/options.js index c765ea6fb..32dd52e93 100644 --- a/packages/deployer/test/options.js +++ b/packages/executor/test/options.js @@ -1,6 +1,11 @@ import _ from 'lodash' -import optionsPrivate from '../../../test/options.private.js' +import optionsPrivate from '../../../test/options.private.mjs' const defaultOptions = { + args: { + forceCert: false, // 强制更新证书 + skipCert: false, // 是否跳过证书申请环节 + forceDeploy: false + }, accessProviders: { aliyun: { providerType: 'aliyun', @@ -17,7 +22,7 @@ const defaultOptions = { } }, cert: { - domains: ['*.docmirror.club', 'docmirror.xyz'], + domains: ['*.docmirror.cn'], email: 'xiaojunnuo@qq.com', challenge: { challengeType: 'dns', @@ -34,27 +39,31 @@ const defaultOptions = { }, deploy: [ { - deployName: '流程1-部署到阿里云系列产品', + name: '流程1-部署到阿里云系列产品', tasks: [ { name: '上传证书到云', type: 'uploadCertToAliyun', - certStore: 'aliyun' + accessProvider: 'aliyun' }, { // CDN、SCDN、DCDN和负载均衡(SLB) - name: '部署证书到SLB', - type: 'deployCertToAliyunSLB', - certStore: 'aliyun' - }, - { - name: '部署证书到阿里云集群Ingress', - type: 'deployCertToAliyunK8sIngress', - certStore: 'aliyun' + name: '部署证书到CDN', + type: 'deployCertToAliyunCDN', + domainName: 'certd-cdn-upload.docmirror.cn', + certName: 'certd部署测试(upload)', + certType: 'upload', + accessProvider: 'aliyun' } + // { + // name: '部署证书到阿里云集群Ingress', + // type: 'deployCertToAliyunK8sIngress', + // accessProvider: 'aliyun' + // } ] }, { - deployName: '流程2-部署到nginx服务器', + name: '流程2-部署到nginx服务器', + disabled: true, tasks: [ { name: '上传证书到服务器,并重启nginx', diff --git a/packages/deployer/yarn-error.log b/packages/executor/yarn-error.log similarity index 100% rename from packages/deployer/yarn-error.log rename to packages/executor/yarn-error.log diff --git a/packages/deployer/yarn.lock b/packages/executor/yarn.lock similarity index 100% rename from packages/deployer/yarn.lock rename to packages/executor/yarn.lock diff --git a/packages/node-acme-client b/packages/node-acme-client new file mode 160000 index 000000000..5a3f74462 --- /dev/null +++ b/packages/node-acme-client @@ -0,0 +1 @@ +Subproject commit 5a3f7446222fa123b645e51e954ccfd981f459bd diff --git a/packages/plugins/src/abstract-plugin/index.js b/packages/plugins/src/abstract-plugin/index.js index c4979a911..2bb5459b1 100644 --- a/packages/plugins/src/abstract-plugin/index.js +++ b/packages/plugins/src/abstract-plugin/index.js @@ -1,5 +1,10 @@ import fs from 'fs' +import logger from '../utils/util.log.js' export class AbstractPlugin { + constructor () { + this.logger = logger + } + async executeFromContextFile (options = {}) { const { contextPath } = options const contextJson = fs.readFileSync(contextPath) @@ -13,5 +18,10 @@ export class AbstractPlugin { return context } - + getAccessProvider (accessProvider, accessProviders) { + if (typeof accessProvider === 'string' && accessProviders) { + accessProvider = accessProviders[accessProvider] + } + return accessProvider + } } diff --git a/packages/plugins/src/aliyun/abstract-aliyun.js b/packages/plugins/src/aliyun/abstract-aliyun.js index e906f9f63..89be83fc2 100644 --- a/packages/plugins/src/aliyun/abstract-aliyun.js +++ b/packages/plugins/src/aliyun/abstract-aliyun.js @@ -1,20 +1,13 @@ -import { AbstractPlugin } from '../abstract-plugin.js' +import { AbstractPlugin } from '../abstract-plugin/index.js' export class AbstractAliyunPlugin extends AbstractPlugin { format (pem) { pem = pem.replace(/\r/g, '') - pem = pem.replace(/\n\n/g, '') + pem = pem.replace(/\n\n/g, '\n') pem = pem.replace(/\n$/g, '') return pem } - getAccessProvider (accessProvider, accessProviders) { - if (typeof accessProvider === 'string' && accessProviders) { - accessProvider = accessProviders[accessProvider] - } - return accessProvider - } - checkRet (ret) { if (ret.code != null) { throw new Error('执行失败:', ret.Message) diff --git a/packages/plugins/src/aliyun/deploy-to-cdn/index.js b/packages/plugins/src/aliyun/deploy-to-cdn/index.js index 522fee962..34d2ce349 100644 --- a/packages/plugins/src/aliyun/deploy-to-cdn/index.js +++ b/packages/plugins/src/aliyun/deploy-to-cdn/index.js @@ -1,7 +1,7 @@ -import { AbstractPlugin } from '../../abstract-plugin/index.js' +import { AbstractAliyunPlugin } from '../../aliyun/abstract-aliyun.js' import Core from '@alicloud/pop-core' import dayjs from 'dayjs' -export class UploadCertToAliyunPlugin extends AbstractPlugin { +export class DeployCertToAliyunCDN extends AbstractAliyunPlugin { /** * 插件定义 * 名称 @@ -10,7 +10,7 @@ export class UploadCertToAliyunPlugin extends AbstractPlugin { */ static define () { return { - name: 'deployToCdn', + name: 'deployCertToAliyunCDN', label: '部署到阿里云CDN', input: { domainName: { @@ -21,10 +21,11 @@ export class UploadCertToAliyunPlugin extends AbstractPlugin { label: '证书名称' }, certType: { + value: 'upload', label: '证书来源', options: [ { value: 'upload', label: '直接上传' }, - { value: 'cas', label: '从证书库(需要uploadCertToAliyun插件作为前置任务)' } + { value: 'cas', label: '从证书库', desc: '需要uploadCertToAliyun作为前置任务' } ], required: true }, @@ -76,12 +77,8 @@ export class UploadCertToAliyunPlugin extends AbstractPlugin { ServerCertificateStatus: 'on', CertName: CertName, CertType: certType, - ServerCertificate: context.aliyunCertId - } - if (certType === 'upload') { - // eslint-disable-next-line no-unused-expressions - params.ServerCertificate = this.format(cert.crt.toString()), - params.PrivateKey = this.format(cert.key.toString()) + ServerCertificate: super.format(cert.crt.toString()), + PrivateKey: super.format(cert.key.toString()) } return params } @@ -92,6 +89,6 @@ export class UploadCertToAliyunPlugin extends AbstractPlugin { } const ret = await client.request('SetDomainServerCertificate', params, requestOption) this.checkRet(ret) - console.log('设置cdn证书成功', ret) + this.logger.info('设置cdn证书成功:', ret.RequestId) } } diff --git a/packages/plugins/src/aliyun/upload-to-aliyun/index.js b/packages/plugins/src/aliyun/upload-to-aliyun/index.js index 5613cc414..81f529f8e 100644 --- a/packages/plugins/src/aliyun/upload-to-aliyun/index.js +++ b/packages/plugins/src/aliyun/upload-to-aliyun/index.js @@ -1,8 +1,7 @@ -import { AbstractPlugin } from '../../abstract-plugin/index.js' import Core from '@alicloud/pop-core' import dayjs from 'dayjs' import { AbstractAliyunPlugin } from '../abstract-aliyun.js' -export class UploadToAliyunPlugin extends AbstractAliyunPlugin { +export class UploadCertToAliyun extends AbstractAliyunPlugin { /** * 插件定义 * 名称 @@ -11,7 +10,7 @@ export class UploadToAliyunPlugin extends AbstractAliyunPlugin { */ static define () { return { - name: 'updateToAliyun', + name: 'uploadCertToAliyun', label: '上传证书到阿里云', input: { name: { @@ -42,8 +41,8 @@ export class UploadToAliyunPlugin extends AbstractAliyunPlugin { }) } - async execute ({ accessProviders, cert, args, context }) { - const { name, provider } = args + async execute ({ accessProviders, cert, args, context, logger }) { + const { name, accessProvider } = args const certName = name + '-' + dayjs().format('YYYYMMDDHHmmss') const params = { RegionId: 'cn-hangzhou', @@ -56,10 +55,11 @@ export class UploadToAliyunPlugin extends AbstractAliyunPlugin { method: 'POST' } - const accesseProvider = this.getAccessProvider(provider, accessProviders) - const client = this.getClient(accesseProvider) + const provider = super.getAccessProvider(accessProvider, accessProviders) + const client = this.getClient(provider) const ret = await client.request('CreateUserCertificate', params, requestOption) this.checkRet(ret) + this.logger.info('证书上传成功:certId=', ret.CertId) context.aliyunCertId = ret.CertId } } diff --git a/packages/plugins/src/index.js b/packages/plugins/src/index.js index 41d340413..53912bff6 100644 --- a/packages/plugins/src/index.js +++ b/packages/plugins/src/index.js @@ -1,4 +1,5 @@ -import { UploadCertToAliyun } from './upload/upload-cert-to-aliyun/index.js' +import { UploadCertToAliyun } from './aliyun/upload-to-aliyun/index.js' +import { DeployCertToAliyunCDN } from './aliyun/deploy-to-cdn/index.js' export default { - UploadCertToAliyun + UploadCertToAliyun, DeployCertToAliyunCDN } diff --git a/packages/plugins/test/aliyun/deploy-to-cdn.test.js b/packages/plugins/test/aliyun/deploy-to-cdn.test.js new file mode 100644 index 000000000..896548f51 --- /dev/null +++ b/packages/plugins/test/aliyun/deploy-to-cdn.test.js @@ -0,0 +1,21 @@ +import pkg from 'chai' +import { DeployCertToAliyunCDN } from '../../src/aliyun/deploy-to-cdn/index.js' +import options from '../options.js' +import { Certd } from '@certd/certd' +const { expect } = pkg +describe('DeployToAliyunCDN', function () { + it('#execute', async function () { + const plugin = new DeployCertToAliyunCDN() + const certd = new Certd() + const cert = certd.readCurrentCert('xiaojunnuo@qq.com', ['*.docmirror.cn']) + const ret = await plugin.execute({ + accessProviders: options.accessProviders, + cert, + args: { domainName: 'certd-cdn-upload.docmirror.cn', certName: 'certd部署测试', certType: 'cas', accessProvider: 'aliyun' }, + context: { + aliyunCertId: '4947435' + } + }) + console.log('context:', context) + }) +}) diff --git a/packages/plugins/test/aliyun/upload-to-aliyun.test.js b/packages/plugins/test/aliyun/upload-to-aliyun.test.js index 124e0557d..b71bc847a 100644 --- a/packages/plugins/test/aliyun/upload-to-aliyun.test.js +++ b/packages/plugins/test/aliyun/upload-to-aliyun.test.js @@ -1,19 +1,19 @@ import pkg from 'chai' -import { UploadToAliyunPlugin } from '../../src/aliyun/upload-to-aliyun/index.js' +import { UploadCertToAliyun } from '../../src/aliyun/upload-to-aliyun/index.js' import options from '../options.js' import { Certd } from '@certd/certd' const { expect } = pkg describe('PluginUploadToAliyun', function () { it('#execute', async function () { - const plugin = new UploadToAliyunPlugin() + const plugin = new UploadCertToAliyun() const certd = new Certd() - const cert = certd.readCurrentCert('xiaojunnuo@qq.com', ['*.docmirror.club', 'docmirror.club']) + const cert = certd.readCurrentCert('xiaojunnuo@qq.com', ['_.docmirror.cn']) const context = {} await plugin.execute({ accessProviders: options.accessProviders, cert, - args: { name: '上传证书到阿里云测试', provider: 'aliyun' }, - context + context, + args: { name: 'certd部署测试', provider: 'aliyun' } }) console.log('context:', context) diff --git a/packages/plugins/test/options.js b/packages/plugins/test/options.js index 381fbe35a..97796b825 100644 --- a/packages/plugins/test/options.js +++ b/packages/plugins/test/options.js @@ -1,6 +1,7 @@ import _ from 'lodash' import optionsPrivate from '../../../test/options.private.mjs' const defaultOptions = { + version: '1.0.0', accessProviders: { aliyun: { providerType: 'aliyun', @@ -31,55 +32,7 @@ const defaultOptions = { organizationUnit: 'IT Department', emailAddress: 'xiaojunnuo@qq.com' } - }, - deploy: [ - { - deployName: '流程1-部署到阿里云系列产品', - tasks: [ - { - name: '上传证书到云', - taskType: 'uploadCertToCloud', - certStore: 'aliyun' - }, - { - name: '部署证书到SLB', - taskType: 'deployCertToAliyunSLB', - certStore: 'aliyun' - }, - { - name: '部署证书到阿里云集群Ingress', - taskType: 'deployCertToAliyunK8sIngress', - certStore: 'aliyun' - } - ] - }, - { - deployName: '流程2-部署到nginx服务器', - tasks: [ - { - name: '上传证书到服务器,并重启nginx', - taskType: 'sshAndExecute', - ssh: 'myLinux', - upload: [ - { from: '{certPath}', to: '/xxx/xxx/xxx.cert.pem' }, - { from: '{keyPath}', to: '/xxx/xxx/xxx.key' } - ], - script: 'sudo systemctl restart nginx' - } - ] - }, - { - deployName: '流程3-触发jenkins任务', - tasks: [ - { - name: '触发jenkins任务', - taskType: 'sshAndExecute', - ssh: 'myLinux', - script: 'sudo systemctl restart nginx' - } - ] - } - ] + } } _.merge(defaultOptions, optionsPrivate)