mirror of
https://github.com/certd/certd.git
synced 2026-04-17 07:10:52 +08:00
Compare commits
82 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b53fea32ce | ||
|
|
58ce899be2 | ||
|
|
f881d755b4 | ||
|
|
1a1b6f4b5e | ||
|
|
f65e523ba6 | ||
|
|
6b2ab3585f | ||
|
|
622b8f1f78 | ||
|
|
aee4e563b6 | ||
|
|
1f75657496 | ||
|
|
9fe021cd89 | ||
|
|
466d659f6e | ||
|
|
84e26381b5 | ||
|
|
469b5a5f69 | ||
|
|
ad77ebd2f9 | ||
|
|
b75543c3bc | ||
|
|
0677275742 | ||
|
|
0c3724e0ad | ||
|
|
803083d23c | ||
|
|
f4f8067a12 | ||
|
|
caa9f084d6 | ||
|
|
81407b65d1 | ||
|
|
8a24293fd7 | ||
|
|
8f1886a585 | ||
|
|
0a64e5fa67 | ||
|
|
7a70603971 | ||
|
|
0d5e00e744 | ||
|
|
91ba1433af | ||
|
|
12e56d14f2 | ||
|
|
7326119f52 | ||
|
|
136983cf14 | ||
|
|
105a1b80ae | ||
|
|
b8000ca533 | ||
|
|
c3e374e6e5 | ||
|
|
a9b6e87249 | ||
|
|
61de5422bf | ||
|
|
f96697f619 | ||
|
|
b4560d6370 | ||
|
|
a7bcde8d82 | ||
|
|
34bb4d54c2 | ||
|
|
e0116a1a03 | ||
|
|
12fec7939d | ||
|
|
ff8e02cceb | ||
|
|
8122bed97f | ||
|
|
991c3dbb76 | ||
|
|
399c23623d | ||
|
|
2232f21b48 | ||
|
|
e41c084381 | ||
|
|
520b27e0dc | ||
|
|
ace7e0247a | ||
|
|
9ae414b1c6 | ||
|
|
cb8c8186f1 | ||
|
|
82f86d9556 | ||
|
|
cfb1034450 | ||
|
|
2a07442a85 | ||
|
|
68c1eff81d | ||
|
|
baec15dfc6 | ||
|
|
6eb9817296 | ||
|
|
b9d5d33aaa | ||
|
|
560519894c | ||
|
|
9f434b0968 | ||
|
|
07066dde87 | ||
|
|
074c8f7cd0 | ||
|
|
e9df2355f4 | ||
|
|
45547d6f94 | ||
|
|
4a421d5b14 | ||
|
|
7b9825eb40 | ||
|
|
5cde165f0b | ||
|
|
305824ff1a | ||
|
|
86ddb72227 | ||
|
|
cca33478e4 | ||
|
|
a8f41d3c48 | ||
|
|
a25a15ca6e | ||
|
|
a39dac4dbd | ||
|
|
eab0c3be60 | ||
|
|
b4ee3d0dfc | ||
|
|
2f03e18c59 | ||
|
|
232cd7215e | ||
|
|
86b1e9959b | ||
|
|
fd130f86fd | ||
|
|
2669f509e1 | ||
|
|
d3619ad60f | ||
|
|
c26417d769 |
14
.gitignore
vendored
14
.gitignore
vendored
@@ -5,7 +5,15 @@ out
|
||||
gen
|
||||
node_modules/
|
||||
/test/*.private.*
|
||||
/other/node-acme-client/.idea/
|
||||
|
||||
/*.log
|
||||
/other/certd-run
|
||||
/other/node-acme-client
|
||||
|
||||
/packages/ui/*/.idea
|
||||
|
||||
/packages/ui/*/node_modules
|
||||
|
||||
/packages/*/node_modules
|
||||
/packages/ui/certd-server/tmp/
|
||||
/packages/ui/certd-ui/dist/
|
||||
/other
|
||||
/dev-sidecar-test
|
||||
|
||||
9
.gitmodules
vendored
Normal file
9
.gitmodules
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
[submodule "packages/deploy/server"]
|
||||
path = packages/deploy/server
|
||||
url = https://github.com/certd/certd-server.git
|
||||
[submodule "packages/deploy/client"]
|
||||
path = packages/deploy/client
|
||||
url = https://github.com/certd/certd-client.git
|
||||
[submodule "packages/issuer/node-acme-client"]
|
||||
path = packages/issuer/node-acme-client
|
||||
url = https://github.com/certd/node-acme-client.git
|
||||
101
README.md
101
README.md
@@ -26,88 +26,31 @@ CertD 是一个帮助你全自动申请和部署SSL证书的工具。
|
||||
## 快速开始
|
||||
本案例演示,如何配置自动申请证书,并部署到阿里云CDN,然后快要到期前自动更新证书并重新部署
|
||||
|
||||
|
||||
1. 环境准备
|
||||
安装[nodejs](https://nodejs.org/zh-cn/)
|
||||
|
||||
2. 创建任务项目
|
||||
|
||||
2. 生成node项目
|
||||
|
||||
通过ui生成: https://certd.docmirror.cn/
|
||||
|
||||
开始生成证书,先填写域名,支持将多个域名打到一个证书上
|
||||

|
||||
|
||||
配置证书详细信息
|
||||

|
||||
|
||||
配置证书部署流程
|
||||

|
||||
|
||||
配置好之后,点击导出按钮,导出一个node项目包
|
||||
|
||||
4. 运行
|
||||
将导出的压缩包解压,然后执行如下命令,即可开始申请证书并部署
|
||||
```
|
||||
mkdir certd-run # 项目名称可以任意命名
|
||||
cd certd-run -y
|
||||
npm install @certd/executor -s --production
|
||||
```
|
||||
|
||||
3. 创建index.js
|
||||
|
||||
参数配置分几个部分
|
||||
args: 运行时参数
|
||||
accessProviders: 授权提供者,提供dns验证与部署任务的授权
|
||||
cert: 证书申请的配置
|
||||
deploy: 证书部署流程
|
||||
|
||||
```js
|
||||
import { Executor } from '@certd/executor'
|
||||
const options = {
|
||||
args: { // 运行时参数
|
||||
forceDeploy: true,
|
||||
},
|
||||
accessProviders: { //授权提供者
|
||||
aliyun: { // 阿里云accessKey,用于dns验证和上传证书到阿里云,并部署到cdn
|
||||
providerType: 'aliyun',
|
||||
accessKeyId: 'Your accessKeyId',
|
||||
accessKeySecret: 'Your accessKeySecret'
|
||||
},
|
||||
},
|
||||
cert: { //免费证书申请配置
|
||||
domains: [ //可以在一张证书上绑定多个域名(前提是他们的验证方式要一样,目前仅支持dns验证)
|
||||
'*.yourdomain.com',
|
||||
'*.test.yourdomain.com',
|
||||
'yourdomain.com'
|
||||
],
|
||||
email: 'Your email',
|
||||
dnsProvider: 'aliyun', //上方accessProviders里面配置的
|
||||
csrInfo: { //证书csr信息
|
||||
country: 'CN',
|
||||
state: 'GuangDong',
|
||||
locality: 'ShengZhen',
|
||||
organization: 'Your company Org.',
|
||||
organizationUnit: 'IT Department',
|
||||
emailAddress: 'Your email'
|
||||
}
|
||||
},
|
||||
deploy: [ //部署流程配置,数组,可以配置多条流程
|
||||
{
|
||||
deployName: '流程1-部署到阿里云CDN',
|
||||
tasks: [ //流程任务,一个流程下可以包含多个部署任务,并且将按顺序执行
|
||||
{ //任务1
|
||||
taskName: '上传到阿里云', //任务名称
|
||||
type: 'uploadCertToAliyun', //任务插件名称
|
||||
props: { //任务插件参数
|
||||
accessProvider: 'aliyun'
|
||||
}
|
||||
},
|
||||
{ // 任务2
|
||||
taskName: '部署证书到CDN',
|
||||
type: 'deployCertToAliyunCDN', //任务插件名称
|
||||
props:{
|
||||
domainName: 'your cdn domain 全称', //cdn域名全称
|
||||
certName: 'certd自动部署',//证书名称前缀
|
||||
accessProvider: 'aliyun'
|
||||
}
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
const executor = new Executor()
|
||||
await executor.run(options)
|
||||
```
|
||||
|
||||
4. 运行
|
||||
```
|
||||
node index.js
|
||||
npm install
|
||||
npm run certd
|
||||
```
|
||||
5. 执行效果
|
||||
生成的证书默认会存储在 `${home}/.certd/${email}/certs/${domain}/current`目录下
|
||||
@@ -129,7 +72,7 @@ node index.js
|
||||
所以当你临时需要将证书部署到其他地方时,直接追加部署任务,然后再次运行即可
|
||||
|
||||
## CI/DI集成与自动续期重新部署
|
||||
集成前,将以上代码提交到内网git仓库,或者私有git仓库(由于包含敏感信息,不要提交到公开git仓库)
|
||||
集成前,将以上导出的node项目提交到内网git仓库,或者私有git仓库(由于包含敏感信息,不要提交到公开git仓库)
|
||||
|
||||
### jenkins任务
|
||||
1. 创建任务
|
||||
|
||||
BIN
doc/step1.png
Normal file
BIN
doc/step1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
doc/step2.png
Normal file
BIN
doc/step2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
BIN
doc/step3.png
Normal file
BIN
doc/step3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 92 KiB |
BIN
doc/tasks.png
Normal file
BIN
doc/tasks.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
@@ -1,6 +1,8 @@
|
||||
{
|
||||
"packages": [
|
||||
"packages/*"
|
||||
"packages/core/*",
|
||||
"packages/plugins/*",
|
||||
"packages/ui/*"
|
||||
],
|
||||
"version": "0.1.11"
|
||||
"version": "0.1.21"
|
||||
}
|
||||
|
||||
22168
package-lock.json
generated
Normal file
22168
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,9 @@
|
||||
"lerna": "^3.18.4"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "lerna bootstrap --hoist",
|
||||
"i-all": "lerna link && lerna exec npm install ",
|
||||
"init": "git submodule update --init --recursive"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
export { AbstractDnsProvider } from './dns-provider/index.js'
|
||||
export { Store } from './store/store.js'
|
||||
export { util } from './utils/index.js'
|
||||
export { AbstractPlugin } from './plugin/index.js'
|
||||
17
packages/core/api/.eslintrc
Normal file
17
packages/core/api/.eslintrc
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"extends": "standard",
|
||||
"env": {
|
||||
"mocha": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2020
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.test.js", "*.spec.js"],
|
||||
"rules": {
|
||||
"no-unused-expressions": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/api",
|
||||
"version": "0.1.11",
|
||||
"version": "0.1.17",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "@certd/api",
|
||||
"version": "0.1.11",
|
||||
"version": "0.1.17",
|
||||
"description": "",
|
||||
"main": "./src/index.js",
|
||||
"main": "src/index.js",
|
||||
"type": "module",
|
||||
"author": "Greper",
|
||||
"license": "MIT",
|
||||
@@ -21,5 +21,6 @@
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"mocha": "^8.2.1"
|
||||
}
|
||||
},
|
||||
"gitHead": "4a421d5b142d453203c68ce6d1036e168ea2455b"
|
||||
}
|
||||
2
packages/core/api/src/access-provider/index.js
Normal file
2
packages/core/api/src/access-provider/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import { Registry } from '../registry/registry.js'
|
||||
export const accessProviderRegistry = new Registry()
|
||||
@@ -1,8 +1,10 @@
|
||||
import _ from 'lodash-es'
|
||||
import logger from '../utils/util.log.js'
|
||||
import commonUtil from '../utils/util.common.js'
|
||||
export class AbstractDnsProvider {
|
||||
constructor () {
|
||||
constructor ({ accessProviders }) {
|
||||
this.logger = logger
|
||||
this.accessProviders = commonUtil.arrayToMap(accessProviders)
|
||||
}
|
||||
|
||||
async createRecord ({ fullRecord, type, value }) {
|
||||
@@ -31,4 +33,15 @@ export class AbstractDnsProvider {
|
||||
}
|
||||
return domain
|
||||
}
|
||||
|
||||
getAccessProvider (accessProvider, accessProviders = this.accessProviders) {
|
||||
let access = accessProvider
|
||||
if (typeof accessProvider === 'string' && accessProviders) {
|
||||
access = accessProviders[accessProvider]
|
||||
}
|
||||
if (access == null) {
|
||||
throw new Error(`accessProvider :${accessProvider}不存在`)
|
||||
}
|
||||
return access
|
||||
}
|
||||
}
|
||||
4
packages/core/api/src/dns-provider/index.js
Normal file
4
packages/core/api/src/dns-provider/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
import { Registry } from '../registry/registry.js'
|
||||
export { AbstractDnsProvider } from './abstract-dns-provider.js'
|
||||
|
||||
export const dnsProviderRegistry = new Registry()
|
||||
6
packages/core/api/src/index.js
Normal file
6
packages/core/api/src/index.js
Normal file
@@ -0,0 +1,6 @@
|
||||
export * from './dns-provider/index.js'
|
||||
export * from './plugin/index.js'
|
||||
export * from './access-provider/index.js'
|
||||
export { Store } from './store/store.js'
|
||||
export { util } from './utils/index.js'
|
||||
// module.createRequireFromPath()
|
||||
@@ -2,10 +2,15 @@ import fs from 'fs'
|
||||
import logger from '../utils/util.log.js'
|
||||
import dayjs from 'dayjs'
|
||||
import Sleep from '../utils/util.sleep.js'
|
||||
import commonUtil from '../utils/util.common.js'
|
||||
export class AbstractPlugin {
|
||||
constructor ({ accessProviders }) {
|
||||
constructor (options) {
|
||||
if (options == null) {
|
||||
throw new Error('插件安装失败:参数不允许为空')
|
||||
}
|
||||
const { accessProviders } = options
|
||||
this.logger = logger
|
||||
this.accessProviders = accessProviders
|
||||
this.accessProviders = commonUtil.arrayToMap(accessProviders)
|
||||
}
|
||||
|
||||
appendTimeSuffix (name) {
|
||||
@@ -52,7 +57,7 @@ export class AbstractPlugin {
|
||||
}
|
||||
|
||||
/**
|
||||
* 回退,如有必要
|
||||
* 回退,用于单元测试
|
||||
* @param options
|
||||
*/
|
||||
async rollback (options) {
|
||||
@@ -60,10 +65,14 @@ export class AbstractPlugin {
|
||||
}
|
||||
|
||||
getAccessProvider (accessProvider, accessProviders = this.accessProviders) {
|
||||
let access = accessProvider
|
||||
if (typeof accessProvider === 'string' && accessProviders) {
|
||||
accessProvider = accessProviders[accessProvider]
|
||||
access = accessProviders[accessProvider]
|
||||
}
|
||||
return accessProvider
|
||||
if (access == null) {
|
||||
throw new Error(`accessProvider :${accessProvider}不存在`)
|
||||
}
|
||||
return access
|
||||
}
|
||||
|
||||
async sleep (time) {
|
||||
3
packages/core/api/src/plugin/index.js
Normal file
3
packages/core/api/src/plugin/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import { Registry } from '../registry/registry.js'
|
||||
export { AbstractPlugin } from './abstract-plugin.js'
|
||||
export const pluginRegistry = new Registry()
|
||||
46
packages/core/api/src/registry/registry.js
Normal file
46
packages/core/api/src/registry/registry.js
Normal file
@@ -0,0 +1,46 @@
|
||||
export class Registry {
|
||||
constructor () {
|
||||
this.collection = {}
|
||||
}
|
||||
|
||||
install (target) {
|
||||
if (target == null) {
|
||||
return
|
||||
}
|
||||
if (this.collection == null) {
|
||||
this.collection = {}
|
||||
}
|
||||
let defineName = target.define ? target.define().name : null
|
||||
if (defineName == null) {
|
||||
defineName = target.name
|
||||
}
|
||||
|
||||
this.register(defineName, target)
|
||||
}
|
||||
|
||||
register (key, value) {
|
||||
if (!key || value == null) {
|
||||
return
|
||||
}
|
||||
this.collection[key] = value
|
||||
}
|
||||
|
||||
get (name) {
|
||||
if (!name) {
|
||||
throw new Error('插件名称不能为空')
|
||||
}
|
||||
|
||||
if (!this.collection) {
|
||||
this.collection = {}
|
||||
}
|
||||
const plugin = this.collection[name]
|
||||
if (!plugin) {
|
||||
throw new Error(`插件${name}还未注册`)
|
||||
}
|
||||
return plugin
|
||||
}
|
||||
|
||||
getCollection () {
|
||||
return this.collection
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import logger from './util.log.js'
|
||||
import path from './util.path.js'
|
||||
import { request } from './util.request.js'
|
||||
import sleep from './util.sleep.js'
|
||||
import common from './util.common.js'
|
||||
export const util = {
|
||||
logger, path, request, sleep
|
||||
logger, path, request, sleep, common
|
||||
}
|
||||
33
packages/core/api/src/utils/util.common.js
Normal file
33
packages/core/api/src/utils/util.common.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import _ from 'lodash-es'
|
||||
export default {
|
||||
arrayToMap (array) {
|
||||
if (!array) {
|
||||
return {}
|
||||
}
|
||||
if (!_.isArray(array)) {
|
||||
return array
|
||||
}
|
||||
const map = {}
|
||||
for (const item of array) {
|
||||
if (item.key) {
|
||||
map[item.key] = item
|
||||
}
|
||||
}
|
||||
return map
|
||||
},
|
||||
mapToArray (map) {
|
||||
if (!map) {
|
||||
return []
|
||||
}
|
||||
if (_.isArray(map)) {
|
||||
return map
|
||||
}
|
||||
const array = []
|
||||
for (const key in map) {
|
||||
const item = map[key]
|
||||
item.key = key
|
||||
array.push(item)
|
||||
}
|
||||
return array
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,18 +1,17 @@
|
||||
{
|
||||
"name": "@certd/certd",
|
||||
"version": "0.1.11",
|
||||
"description": "",
|
||||
"main": "./src/index.js",
|
||||
"version": "0.1.19",
|
||||
"description": "a ssl cert keeper",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"test": "echo \\\"Error: no test specified\\\" && exit 1"
|
||||
},
|
||||
"type": "module",
|
||||
"author": "Greper",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@certd/acme-client": "^0.1.6",
|
||||
"@certd/api": "^0.1.11",
|
||||
"@certd/providers": "^0.1.11",
|
||||
"@certd/acme-client": "^0.1.8",
|
||||
"@certd/api": "^0.1.17",
|
||||
"dayjs": "^1.9.7",
|
||||
"lodash-es": "^4.17.20",
|
||||
"node-forge": "^0.10.0"
|
||||
@@ -25,5 +24,6 @@
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"mocha": "^8.2.1"
|
||||
}
|
||||
},
|
||||
"gitHead": "4a421d5b142d453203c68ce6d1036e168ea2455b"
|
||||
}
|
||||
@@ -1,27 +1,12 @@
|
||||
import { util, Store } from '@certd/api'
|
||||
import { util, Store, dnsProviderRegistry } from '@certd/api'
|
||||
import { AcmeService } from './acme.js'
|
||||
import { FileStore } from './store/file-store.js'
|
||||
import { CertStore } from './store/cert-store.js'
|
||||
import dayjs from 'dayjs'
|
||||
import forge from 'node-forge'
|
||||
import DefaultProviders from '@certd/providers'
|
||||
import _ from 'lodash-es'
|
||||
|
||||
const logger = util.logger
|
||||
|
||||
const AccessProviderClasses = {}
|
||||
function install (providerClass) {
|
||||
AccessProviderClasses[providerClass.name()] = providerClass
|
||||
}
|
||||
logger.info('use')
|
||||
_.forEach(DefaultProviders, item => {
|
||||
logger.info('use:', item.name())
|
||||
install(item)
|
||||
})
|
||||
export class Certd {
|
||||
static use (providerClass) {
|
||||
install(providerClass)
|
||||
}
|
||||
|
||||
constructor (options) {
|
||||
this.options = options
|
||||
this.email = options.cert.email
|
||||
@@ -87,16 +72,14 @@ export class Certd {
|
||||
}
|
||||
|
||||
createDnsProvider (options) {
|
||||
const accessProviders = options.accessProviders
|
||||
const providerOptions = accessProviders[options.cert.dnsProvider]
|
||||
return this.createProviderByType(providerOptions.providerType, providerOptions)
|
||||
return this.createProviderByType(options.cert.dnsProvider, options.accessProviders)
|
||||
}
|
||||
|
||||
async writeCert (cert) {
|
||||
const newPath = await this.certStore.writeCert(cert)
|
||||
return {
|
||||
realPath: this.certStore.store.getActualKey(newPath),
|
||||
currentPath: this.certStore.store.getActualKey(this.certStore.currentRootPath)
|
||||
currentPath: this.certStore.store.getActualKey(this.certStore.currentMarkPath)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,12 +120,12 @@ export class Certd {
|
||||
}
|
||||
}
|
||||
|
||||
createProviderByType (type, options) {
|
||||
try {
|
||||
const Provider = AccessProviderClasses[type]
|
||||
return new Provider(options)
|
||||
} catch (e) {
|
||||
throw new Error('暂不支持此dnsProvider,请先use该provider:' + type, e)
|
||||
createProviderByType (props, accessProviders) {
|
||||
const { type } = props
|
||||
const Provider = dnsProviderRegistry.get(type)
|
||||
if (Provider == null) {
|
||||
throw new Error('暂不支持此dnsProvider,请先注册该provider:' + type)
|
||||
}
|
||||
return new Provider({ accessProviders, props })
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import dayjs from 'dayjs'
|
||||
import crypto from 'crypto'
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function md5 (content) {
|
||||
return crypto.createHash('md5').update(content).digest('hex')
|
||||
}
|
||||
@@ -11,9 +12,10 @@ export class CertStore {
|
||||
this.domain = this.getMainDomain(this.domains)
|
||||
this.safetyDomain = this.getSafetyDomain(this.domain)
|
||||
this.domainDir = this.safetyDomain + '-' + md5(this.getDomainStr(this.domains))
|
||||
// this.domainDir = this.safetyDomain
|
||||
this.certsRootPath = this.store.buildKey(this.email, 'certs')
|
||||
|
||||
this.currentRootPath = this.store.buildKey(this.certsRootPath, this.domainDir, 'current')
|
||||
this.currentMarkPath = this.store.buildKey(this.certsRootPath, this.domainDir, 'current.json')
|
||||
}
|
||||
|
||||
getMainDomain (domains) {
|
||||
@@ -62,15 +64,19 @@ export class CertStore {
|
||||
await this.store.set(priKey, this.formatCert(cert.key.toString()))
|
||||
await this.store.set(csrKey, cert.csr.toString())
|
||||
|
||||
await this.store.link(newDir, this.currentRootPath)
|
||||
await this.store.set(this.currentMarkPath, JSON.stringify({ latest: newDir }))
|
||||
|
||||
return newDir
|
||||
}
|
||||
|
||||
async readCert (dir) {
|
||||
if (dir == null) {
|
||||
dir = this.currentRootPath
|
||||
dir = await this.getCurrentDir()
|
||||
}
|
||||
if (dir == null) {
|
||||
return
|
||||
}
|
||||
|
||||
const crtKey = this.buildKey(dir, this.safetyDomain + '.crt')
|
||||
const priKey = this.buildKey(dir, this.safetyDomain + '.key')
|
||||
const csrKey = this.buildKey(dir, this.safetyDomain + '.csr')
|
||||
@@ -99,13 +105,23 @@ export class CertStore {
|
||||
return domain.replace(/\*/g, '_')
|
||||
}
|
||||
|
||||
getCurrentFile (file) {
|
||||
const key = this.buildKey(this.currentRootPath, file)
|
||||
async getCurrentDir () {
|
||||
const current = await this.store.get(this.currentMarkPath)
|
||||
if (current == null) {
|
||||
return null
|
||||
}
|
||||
return JSON.parse(current).latest
|
||||
}
|
||||
|
||||
async getCurrentFile (file) {
|
||||
const currentDir = await this.getCurrentDir()
|
||||
const key = this.buildKey(currentDir, file)
|
||||
return this.store.get(key)
|
||||
}
|
||||
|
||||
setCurrentFile (file, value) {
|
||||
const key = this.buildKey(this.currentRootPath, file)
|
||||
async setCurrentFile (file, value) {
|
||||
const currentDir = await this.getCurrentDir()
|
||||
const key = this.buildKey(currentDir, file)
|
||||
return this.store.set(key, value)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import chai from 'chai'
|
||||
import { Certd } from '../src/index.js'
|
||||
import { createOptions } from '../../../test/options.js'
|
||||
import { createOptions } from '../../../../test/options.js'
|
||||
const { expect } = chai
|
||||
const fakeCrt = `-----BEGIN CERTIFICATE-----
|
||||
MIIFSTCCBDGgAwIBAgITAPoZZk/LhVIyXoic2NnJyxubezANBgkqhkiG9w0BAQsF
|
||||
@@ -66,9 +66,9 @@ describe('Certd', function () {
|
||||
options.cert.email = 'xiaojunnuo@qq.com'
|
||||
options.cert.domains = ['*.docmirror.club']
|
||||
const certd = new Certd(options)
|
||||
const currentRootPath = certd.certStore.currentRootPath
|
||||
const currentRootPath = certd.certStore.currentMarkPath
|
||||
console.log('rootDir', currentRootPath)
|
||||
expect(currentRootPath).match(/xiaojunnuo@qq.com\\certs\\_.docmirror.club-\w+\\current/)
|
||||
expect(currentRootPath).match(/xiaojunnuo@qq.com\\certs\\_.docmirror.club-\w*\\current.json/)
|
||||
})
|
||||
it('#writeAndReadCert', async function () {
|
||||
const options = createOptions()
|
||||
@@ -83,6 +83,6 @@ describe('Certd', function () {
|
||||
expect(cert.key).to.be.ok
|
||||
expect(cert.detail).to.be.ok
|
||||
expect(cert.expires).to.be.ok
|
||||
console.log('expires:', cert.expires)
|
||||
console.log('cert:', JSON.stringify(cert))
|
||||
})
|
||||
})
|
||||
5696
packages/core/executor/package-lock.json
generated
Normal file
5696
packages/core/executor/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,22 +1,24 @@
|
||||
{
|
||||
"name": "@certd/executor",
|
||||
"version": "0.1.11",
|
||||
"version": "0.1.21",
|
||||
"description": "",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"test": "echo \\\"Error: no test specified\\\" && exit 1",
|
||||
"build": "webpack --config webpack.config.cjs ",
|
||||
"rollup": "rollup --config rollup.config.js"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@certd/api": "^0.1.11",
|
||||
"@certd/certd": "^0.1.11",
|
||||
"@certd/plugins": "^0.1.11",
|
||||
"@certd/api": "^0.1.17",
|
||||
"@certd/certd": "^0.1.19",
|
||||
"dayjs": "^1.9.7",
|
||||
"lodash-es": "^4.17.20"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/plugin-aliyun": "^0.1.19",
|
||||
"@certd/plugin-host": "^0.1.21",
|
||||
"@certd/plugin-tencent": "^0.1.21",
|
||||
"@rollup/plugin-commonjs": "^17.0.0",
|
||||
"@rollup/plugin-json": "^4.1.0",
|
||||
"@rollup/plugin-node-resolve": "^11.0.1",
|
||||
@@ -32,5 +34,6 @@
|
||||
},
|
||||
"author": "Greper",
|
||||
"license": "MIT",
|
||||
"sideEffects": false
|
||||
"sideEffects": false,
|
||||
"gitHead": "4a421d5b142d453203c68ce6d1036e168ea2455b"
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Certd } from '@certd/certd'
|
||||
import DefaultPlugins from '@certd/plugins'
|
||||
import { util } from '@certd/api'
|
||||
import { pluginRegistry, util } from '@certd/api'
|
||||
import _ from 'lodash-es'
|
||||
import dayjs from 'dayjs'
|
||||
import { Trace } from './trace.js'
|
||||
@@ -18,59 +17,38 @@ function createDefaultOptions () {
|
||||
}
|
||||
export class Executor {
|
||||
constructor () {
|
||||
this.usePlugins(DefaultPlugins)
|
||||
this.trace = new Trace()
|
||||
}
|
||||
|
||||
useProviders (providers) {
|
||||
if (providers) {
|
||||
_.forEach(item => {
|
||||
Certd.use(item)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
useProvider (provider) {
|
||||
Certd.use(provider)
|
||||
}
|
||||
|
||||
usePlugin (plugin) {
|
||||
if (plugin == null) {
|
||||
return
|
||||
}
|
||||
if (this.plugins == null) {
|
||||
this.plugins = {}
|
||||
}
|
||||
this.plugins[plugin.name] = plugin
|
||||
if (plugin.define) {
|
||||
const define = plugin.define()
|
||||
this.plugins[define.name] = plugin
|
||||
}
|
||||
}
|
||||
|
||||
usePlugins (plugins) {
|
||||
if (plugins) {
|
||||
_.forEach(plugins, item => {
|
||||
this.usePlugin(item)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async run (options) {
|
||||
logger.info('------------------- Cert-D ---------------------')
|
||||
try {
|
||||
this.transfer(options)
|
||||
options = _.merge(createDefaultOptions(), options)
|
||||
return await this.doRun(options)
|
||||
} catch (e) {
|
||||
logger.error('任务执行出错:', e)
|
||||
logger.error('任务执行出错', e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
transfer (options) {
|
||||
const providers = options.accessProviders
|
||||
if (_.isArray(providers)) {
|
||||
const map = {}
|
||||
for (const provider of providers) {
|
||||
if (provider.key) {
|
||||
map[provider.key] = provider
|
||||
}
|
||||
}
|
||||
options.accessProviders = map
|
||||
}
|
||||
}
|
||||
|
||||
async doRun (options) {
|
||||
// 申请证书
|
||||
logger.info('任务开始')
|
||||
const certd = new Certd(options, this.providers)
|
||||
const certd = new Certd(options)
|
||||
const cert = await this.runCertd(certd)
|
||||
if (cert == null) {
|
||||
throw new Error('申请证书失败')
|
||||
@@ -80,8 +58,11 @@ export class Executor {
|
||||
logger.info('----------------------')
|
||||
if (!cert.isNew) {
|
||||
// 如果没有更新
|
||||
if (!options.args.forceDeploy && !options.args.forceRedeploy) {
|
||||
// 且不需要强制运行deploy
|
||||
if (options.args.forceRedeploy) {
|
||||
// 强制重新部署,清空保存的状态
|
||||
await certd.certStore.setCurrentFile('context.json', '{}')
|
||||
} else if (!options.args.forceDeploy) {
|
||||
// 且不需要强制deploy
|
||||
logger.info('证书无更新,无需重新部署')
|
||||
logger.info('任务完成')
|
||||
return { cert }
|
||||
@@ -107,15 +88,16 @@ export class Executor {
|
||||
logger.info('任务完成')
|
||||
trace.print()
|
||||
const result = resultTrace.get({ })
|
||||
const returnData = {
|
||||
if (result) {
|
||||
if (result.status === 'error' && options.args.doNotThrowError === false) {
|
||||
throw new Error(result.remark)
|
||||
}
|
||||
}
|
||||
return {
|
||||
cert,
|
||||
context,
|
||||
result
|
||||
}
|
||||
if (result.status === 'error' && options.args.doNotThrowError === false) {
|
||||
throw new Error(result.remark)
|
||||
}
|
||||
return returnData
|
||||
}
|
||||
|
||||
async runCertd (certd) {
|
||||
@@ -140,6 +122,7 @@ export class Executor {
|
||||
logger.info('此流程已被禁用,跳过')
|
||||
logger.info('')
|
||||
deployTrace.set({ value: { current: 'skip', status: 'disabled', remark: '流程禁用' } })
|
||||
deployTrace.set({ tasks: null })
|
||||
continue
|
||||
}
|
||||
try {
|
||||
@@ -153,6 +136,7 @@ export class Executor {
|
||||
}
|
||||
|
||||
deployTrace.set({ value: { status: 'success', remark: '执行成功' } })
|
||||
trace.set({ type: 'result', value: { status: 'success', remark: '执行成功' } })
|
||||
} catch (e) {
|
||||
deployTrace.set({ value: { status: 'error', remark: '执行失败:' + e.message } })
|
||||
trace.set({ type: 'result', value: { status: 'error', remark: deployName + '执行失败:' + e.message } })
|
||||
@@ -165,7 +149,7 @@ export class Executor {
|
||||
|
||||
async runTask ({ options, task, cert, context, deploy, trace }) {
|
||||
const taskType = task.type
|
||||
const Plugin = this.plugins[taskType]
|
||||
const Plugin = pluginRegistry.get(taskType)
|
||||
const deployName = deploy.deployName
|
||||
const taskName = task.taskName
|
||||
if (Plugin == null) {
|
||||
@@ -76,7 +76,9 @@ export class Trace {
|
||||
}
|
||||
}
|
||||
const result = this.get({ type: 'result' })
|
||||
this.printTraceLine(result, 'result', '')
|
||||
if (result) {
|
||||
this.printTraceLine(result, 'result', '')
|
||||
}
|
||||
const mainContext = {}
|
||||
_.merge(mainContext, context)
|
||||
delete mainContext.__trace__
|
||||
@@ -1,8 +1,16 @@
|
||||
import pkg from 'chai'
|
||||
import { Executor } from '../src/index.js'
|
||||
import { createOptions } from '../../../test/options.js'
|
||||
import { createOptions } from '../../../../test/options.js'
|
||||
import PluginAliyun from '@certd/plugin-aliyun'
|
||||
import PluginTencent from '@certd/plugin-tencent'
|
||||
import PluginHost from '@certd/plugin-host'
|
||||
const { expect } = pkg
|
||||
|
||||
// 安装默认插件和授权提供者
|
||||
PluginAliyun.install()
|
||||
PluginTencent.install()
|
||||
PluginHost.install()
|
||||
|
||||
describe('AutoDeploy', function () {
|
||||
it('#run', async function () {
|
||||
this.timeout(120000)
|
||||
1936
packages/core/executor/yarn.lock
Normal file
1936
packages/core/executor/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
1
packages/deploy/client
Submodule
1
packages/deploy/client
Submodule
Submodule packages/deploy/client added at 8eb90445fa
1
packages/deploy/server
Submodule
1
packages/deploy/server
Submodule
Submodule packages/deploy/server added at 07443ac885
3920
packages/executor/package-lock.json
generated
3920
packages/executor/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
1
packages/issuer/node-acme-client
Submodule
1
packages/issuer/node-acme-client
Submodule
Submodule packages/issuer/node-acme-client added at 7003db0125
File diff suppressed because it is too large
Load Diff
26
packages/plugins/plugin-aliyun/package.json
Normal file
26
packages/plugins/plugin-aliyun/package.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "@certd/plugin-aliyun",
|
||||
"version": "0.1.19",
|
||||
"description": "",
|
||||
"main": "src/index.js",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@alicloud/pop-core": "^1.7.10",
|
||||
"@certd/api": "^0.1.17",
|
||||
"dayjs": "^1.9.7",
|
||||
"lodash-es": "^4.17.20"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/certd": "^0.1.19",
|
||||
"chai": "^4.2.0",
|
||||
"eslint": "^7.15.0",
|
||||
"eslint-config-standard": "^16.0.2",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"mocha": "^8.2.1"
|
||||
},
|
||||
"author": "Greper",
|
||||
"license": "MIT",
|
||||
"gitHead": "4a421d5b142d453203c68ce6d1036e168ea2455b"
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
export class AliyunAccessProvider {
|
||||
static define () {
|
||||
return {
|
||||
name: 'aliyun',
|
||||
label: '阿里云',
|
||||
desc: '',
|
||||
input: {
|
||||
accessKeyId: {
|
||||
type: String,
|
||||
component: {
|
||||
placeholder: 'accessKeyId',
|
||||
rules: [{ required: true, message: '必填项' }]
|
||||
},
|
||||
required: true
|
||||
},
|
||||
accessKeySecret: {
|
||||
type: String,
|
||||
component: {
|
||||
placeholder: 'accessKeySecret',
|
||||
rules: [{ required: true, message: '必填项' }]
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
output: {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,20 +2,41 @@ import { AbstractDnsProvider } from '@certd/api'
|
||||
import Core from '@alicloud/pop-core'
|
||||
import _ from 'lodash-es'
|
||||
export class AliyunDnsProvider extends AbstractDnsProvider {
|
||||
constructor (dnsProviderConfig) {
|
||||
super()
|
||||
static define () {
|
||||
return {
|
||||
name: 'aliyun',
|
||||
label: '阿里云',
|
||||
desc: '',
|
||||
input: {
|
||||
accessProvider: {
|
||||
label: '授权',
|
||||
type: [String, Object],
|
||||
desc: '需要aliyun类型的授权',
|
||||
component: {
|
||||
name: 'access-provider-selector',
|
||||
filter: 'aliyun'
|
||||
},
|
||||
required: true
|
||||
}
|
||||
},
|
||||
output: {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor (args) {
|
||||
super(args)
|
||||
const { props } = args
|
||||
const accessProvider = this.getAccessProvider(props.accessProvider)
|
||||
this.client = new Core({
|
||||
accessKeyId: dnsProviderConfig.accessKeyId,
|
||||
accessKeySecret: dnsProviderConfig.accessKeySecret,
|
||||
accessKeyId: accessProvider.accessKeyId,
|
||||
accessKeySecret: accessProvider.accessKeySecret,
|
||||
endpoint: 'https://alidns.aliyuncs.com',
|
||||
apiVersion: '2015-01-09'
|
||||
})
|
||||
}
|
||||
|
||||
static name () {
|
||||
return 'aliyun'
|
||||
}
|
||||
|
||||
async getDomainList () {
|
||||
const params = {
|
||||
RegionId: 'cn-hangzhou'
|
||||
24
packages/plugins/plugin-aliyun/src/index.js
Normal file
24
packages/plugins/plugin-aliyun/src/index.js
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
import _ from 'lodash-es'
|
||||
|
||||
import { AliyunDnsProvider } from './dns-providers/aliyun.js'
|
||||
import { AliyunAccessProvider } from './access-providers/aliyun.js'
|
||||
import { UploadCertToAliyun } from './plugins/upload-to-aliyun/index.js'
|
||||
import { DeployCertToAliyunCDN } from './plugins/deploy-to-cdn/index.js'
|
||||
|
||||
import { pluginRegistry, accessProviderRegistry, dnsProviderRegistry } from '@certd/api'
|
||||
|
||||
export const Plugins = {
|
||||
UploadCertToAliyun,
|
||||
DeployCertToAliyunCDN
|
||||
}
|
||||
export default {
|
||||
install () {
|
||||
_.forEach(Plugins, item => {
|
||||
pluginRegistry.install(item)
|
||||
})
|
||||
|
||||
accessProviderRegistry.install(AliyunAccessProvider)
|
||||
dnsProviderRegistry.install(AliyunDnsProvider)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
import { AbstractAliyunPlugin } from '../abstract-aliyun.js'
|
||||
import Core from '@alicloud/pop-core'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
const define = {
|
||||
name: 'deployCertToAliyunCDN',
|
||||
label: '部署到阿里云CDN',
|
||||
input: {
|
||||
domainName: {
|
||||
label: 'cdn加速域名',
|
||||
component: {
|
||||
placeholder: 'cdn加速域名'
|
||||
},
|
||||
required: true
|
||||
},
|
||||
certName: {
|
||||
label: '证书名称',
|
||||
component: {
|
||||
placeholder: '上传后将以此名称作为前缀'
|
||||
}
|
||||
},
|
||||
from: {
|
||||
default: 'upload',
|
||||
label: '证书来源',
|
||||
required: true,
|
||||
component: {
|
||||
required: true,
|
||||
placeholder: '证书来源',
|
||||
name: 'a-select',
|
||||
options: [
|
||||
{ value: 'upload', label: '直接上传' },
|
||||
{ value: 'cas', label: '从证书库', title: '需要uploadCertToAliyun作为前置任务' }
|
||||
]
|
||||
},
|
||||
desc: '如果选择‘从证书库’类型,则需要以《上传证书到阿里云》作为前置任务'
|
||||
|
||||
},
|
||||
// serverCertificateStatus: {
|
||||
// label: '启用https',
|
||||
// options: [
|
||||
// { value: 'on', label: '开启HTTPS,并更新证书' },
|
||||
// { value: 'auto', label: '若HTTPS开启则更新,未开启不更新' }
|
||||
// ],
|
||||
// required:true
|
||||
// },
|
||||
accessProvider: {
|
||||
label: 'Access提供者',
|
||||
type: [String, Object],
|
||||
desc: 'access授权',
|
||||
component: {
|
||||
name: 'access-provider-selector',
|
||||
filter: 'aliyun'
|
||||
},
|
||||
required: true
|
||||
}
|
||||
},
|
||||
output: {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export class DeployCertToAliyunCDN extends AbstractAliyunPlugin {
|
||||
static define () {
|
||||
return define
|
||||
}
|
||||
|
||||
async execute ({ cert, props, context }) {
|
||||
const accessProvider = this.getAccessProvider(props.accessProvider)
|
||||
const client = this.getClient(accessProvider)
|
||||
const params = this.buildParams(props, context, cert)
|
||||
await this.doRequest(client, params)
|
||||
}
|
||||
|
||||
getClient (aliyunProvider) {
|
||||
return new Core({
|
||||
accessKeyId: aliyunProvider.accessKeyId,
|
||||
accessKeySecret: aliyunProvider.accessKeySecret,
|
||||
endpoint: 'https://cdn.aliyuncs.com',
|
||||
apiVersion: '2018-05-10'
|
||||
})
|
||||
}
|
||||
|
||||
buildParams (args, context, cert) {
|
||||
const { certName, from, domainName } = args
|
||||
const CertName = certName + '-' + dayjs().format('YYYYMMDDHHmmss')
|
||||
|
||||
const params = {
|
||||
RegionId: 'cn-hangzhou',
|
||||
DomainName: domainName,
|
||||
ServerCertificateStatus: 'on',
|
||||
CertName: CertName,
|
||||
CertType: from,
|
||||
ServerCertificate: cert.crt,
|
||||
PrivateKey: cert.key
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
async doRequest (client, params) {
|
||||
const requestOption = {
|
||||
method: 'POST'
|
||||
}
|
||||
const ret = await client.request('SetDomainServerCertificate', params, requestOption)
|
||||
this.checkRet(ret)
|
||||
this.logger.info('设置cdn证书成功:', ret.RequestId)
|
||||
}
|
||||
}
|
||||
@@ -1,38 +1,41 @@
|
||||
import Core from '@alicloud/pop-core'
|
||||
import { AbstractAliyunPlugin } from '../abstract-aliyun.js'
|
||||
export class UploadCertToAliyun extends AbstractAliyunPlugin {
|
||||
/**
|
||||
* 插件定义
|
||||
* 名称
|
||||
* 入参
|
||||
* 出参
|
||||
*/
|
||||
static define () {
|
||||
return {
|
||||
name: 'uploadCertToAliyun',
|
||||
label: '上传证书到阿里云',
|
||||
input: {
|
||||
name: {
|
||||
label: '证书名称'
|
||||
},
|
||||
regionId: {
|
||||
label: '大区',
|
||||
value: 'cn-hangzhou'
|
||||
},
|
||||
accessProvider: {
|
||||
label: 'Access提供者',
|
||||
type: [String, Object],
|
||||
desc: 'AccessProviders的key 或 一个包含accessKeyId与accessKeySecret的对象',
|
||||
options: 'accessProviders[type=aliyun]'
|
||||
}
|
||||
|
||||
const define = {
|
||||
name: 'uploadCertToAliyun',
|
||||
label: '上传证书到阿里云',
|
||||
input: {
|
||||
name: {
|
||||
label: '证书名称',
|
||||
desc: '证书上传后将以此参数作为名称前缀'
|
||||
},
|
||||
regionId: {
|
||||
label: '大区',
|
||||
default: 'cn-hangzhou',
|
||||
required: true
|
||||
},
|
||||
accessProvider: {
|
||||
label: 'Access提供者',
|
||||
type: [String, Object],
|
||||
desc: 'access授权',
|
||||
component: {
|
||||
name: 'access-provider-selector',
|
||||
filter: 'aliyun'
|
||||
},
|
||||
output: {
|
||||
aliyunCertId: {
|
||||
type: String,
|
||||
desc: '上传成功后的阿里云CertId'
|
||||
}
|
||||
}
|
||||
required: true
|
||||
}
|
||||
},
|
||||
output: {
|
||||
aliyunCertId: {
|
||||
type: String,
|
||||
desc: '上传成功后的阿里云CertId'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class UploadCertToAliyun extends AbstractAliyunPlugin {
|
||||
static define () {
|
||||
return define
|
||||
}
|
||||
|
||||
getClient (aliyunProvider) {
|
||||
@@ -1,6 +1,10 @@
|
||||
import pkg from 'chai'
|
||||
import { createOptions } from '../../../../test/options.js'
|
||||
import { Certd } from '../../src/index.js'
|
||||
import { createOptions } from '../../../../../test/options.js'
|
||||
import { Certd } from '@certd/certd'
|
||||
import PluginAliyun from '../../src/index.js'
|
||||
|
||||
// 安装默认插件和授权提供者
|
||||
PluginAliyun.install()
|
||||
const { expect } = pkg
|
||||
describe('AliyunDnsProvider', function () {
|
||||
it('#申请证书-aliyun', async function () {
|
||||
@@ -1,27 +1,33 @@
|
||||
import pkg from 'chai'
|
||||
import AliyunDnsProvider from '../../src/dns-provider/aliyun.js'
|
||||
import { createOptions } from '../../../../test/options.js'
|
||||
import { AliyunDnsProvider } from '../../src/dns-providers/aliyun.js'
|
||||
import { createOptions } from '../../../../../test/options.js'
|
||||
const { expect } = pkg
|
||||
|
||||
export function getPluginOptions () {
|
||||
const options = createOptions()
|
||||
return { accessProviders: options.accessProviders, props: options.cert.dnsProvider }
|
||||
}
|
||||
|
||||
describe('AliyunDnsProvider', function () {
|
||||
it('#getDomainList', async function () {
|
||||
const options = createOptions()
|
||||
const aliyunDnsProvider = new AliyunDnsProvider(options.accessProviders.aliyun)
|
||||
const options = getPluginOptions()
|
||||
const aliyunDnsProvider = new AliyunDnsProvider(options)
|
||||
const domainList = await aliyunDnsProvider.getDomainList()
|
||||
console.log('domainList', domainList)
|
||||
expect(domainList.length).gt(0)
|
||||
})
|
||||
|
||||
it('#getRecords', async function () {
|
||||
const options = createOptions()
|
||||
const aliyunDnsProvider = new AliyunDnsProvider(options.accessProviders.aliyun)
|
||||
const options = getPluginOptions()
|
||||
const aliyunDnsProvider = new AliyunDnsProvider(options)
|
||||
const recordList = await aliyunDnsProvider.getRecords('docmirror.cn', '*')
|
||||
console.log('recordList', recordList)
|
||||
expect(recordList.length).gt(0)
|
||||
})
|
||||
|
||||
it('#createAndRemoveRecord', async function () {
|
||||
const options = createOptions()
|
||||
const aliyunDnsProvider = new AliyunDnsProvider(options.accessProviders.aliyun)
|
||||
const options = getPluginOptions()
|
||||
const aliyunDnsProvider = new AliyunDnsProvider(options)
|
||||
const record = await aliyunDnsProvider.createRecord({ fullRecord: '___certd___.__test__.docmirror.cn', type: 'TXT', value: 'aaaa' })
|
||||
console.log('recordId', record)
|
||||
expect(record != null).ok
|
||||
42
packages/plugins/plugin-aliyun/test/options.js
Normal file
42
packages/plugins/plugin-aliyun/test/options.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import _ from 'lodash-es'
|
||||
import optionsPrivate from '../../../test/options.private.mjs'
|
||||
const defaultOptions = {
|
||||
version: '1.0.0',
|
||||
args: {
|
||||
directory: 'test',
|
||||
dry: false
|
||||
},
|
||||
accessProviders: {
|
||||
aliyun: {
|
||||
providerType: 'aliyun',
|
||||
accessKeyId: '',
|
||||
accessKeySecret: ''
|
||||
},
|
||||
myLinux: {
|
||||
providerType: 'SSH',
|
||||
username: 'xxx',
|
||||
password: 'xxx',
|
||||
host: '1111.com',
|
||||
port: 22,
|
||||
publicKey: ''
|
||||
}
|
||||
},
|
||||
cert: {
|
||||
domains: ['*.docmirror.club', 'docmirror.club'],
|
||||
email: 'xiaojunnuo@qq.com',
|
||||
dnsProvider: { type: 'aliyun', accessProvider: 'aliyun' },
|
||||
certProvider: 'letsencrypt',
|
||||
csrInfo: {
|
||||
country: 'CN',
|
||||
state: 'GuangDong',
|
||||
locality: 'ShengZhen',
|
||||
organization: 'CertD Org.',
|
||||
organizationUnit: 'IT Department',
|
||||
emailAddress: 'xiaojunnuo@qq.com'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_.merge(defaultOptions, optionsPrivate)
|
||||
|
||||
export default defaultOptions
|
||||
@@ -1,20 +1,20 @@
|
||||
import pkg from 'chai'
|
||||
import { DeployCertToAliyunCDN } from '../../src/aliyun/deploy-to-cdn/index.js'
|
||||
import { DeployCertToAliyunCDN } from '../../src/plugins/deploy-to-cdn/index.js'
|
||||
import { Certd } from '@certd/certd'
|
||||
import createOptions from '../../../../test/options.js'
|
||||
import { createOptions } from '../../../../../test/options.js'
|
||||
const { expect } = pkg
|
||||
|
||||
describe('DeployToAliyunCDN', function () {
|
||||
it('#execute', async function () {
|
||||
this.timeout(5000)
|
||||
const options = createOptions()
|
||||
const plugin = new DeployCertToAliyunCDN()
|
||||
const plugin = new DeployCertToAliyunCDN(options)
|
||||
options.cert.domains = ['*.docmirror.cn', 'docmirror.cn']
|
||||
const certd = new Certd(options)
|
||||
const cert = await certd.readCurrentCert()
|
||||
const ret = await plugin.doExecute({
|
||||
accessProviders: options.accessProviders,
|
||||
cert,
|
||||
props: { domainName: 'certd-cdn-upload.docmirror.cn', certName: 'certd部署测试', certType: 'cas', accessProvider: 'aliyun' }
|
||||
props: { domainName: 'certd-cdn-upload.docmirror.cn', certName: 'certd部署测试', from: 'cas', accessProvider: 'aliyun' }
|
||||
})
|
||||
console.log('context:', context, ret)
|
||||
})
|
||||
@@ -1,7 +1,7 @@
|
||||
import pkg from 'chai'
|
||||
import { UploadCertToAliyun } from '../../src/aliyun/upload-to-aliyun/index.js'
|
||||
import { UploadCertToAliyun } from '../../src/plugins/upload-to-aliyun/index.js'
|
||||
import { Certd } from '@certd/certd'
|
||||
import { createOptions } from '../../../../test/options.js'
|
||||
import { createOptions } from '../../../../../test/options.js'
|
||||
const { expect } = pkg
|
||||
describe('PluginUploadToAliyun', function () {
|
||||
it('#execute', async function () {
|
||||
@@ -9,12 +9,11 @@ describe('PluginUploadToAliyun', function () {
|
||||
const options = createOptions()
|
||||
options.cert.email = 'xiaojunnuo@qq.com'
|
||||
options.cert.domains = ['_.docmirror.cn']
|
||||
const plugin = new UploadCertToAliyun()
|
||||
const plugin = new UploadCertToAliyun(options)
|
||||
const certd = new Certd(options)
|
||||
const cert = await certd.readCurrentCert()
|
||||
const context = {}
|
||||
const deployOpts = {
|
||||
accessProviders: options.accessProviders,
|
||||
cert,
|
||||
props: { accessProvider: 'aliyun' },
|
||||
context
|
||||
@@ -22,7 +21,7 @@ describe('PluginUploadToAliyun', function () {
|
||||
await plugin.doExecute(deployOpts)
|
||||
console.log('context:', context)
|
||||
|
||||
// await plugin.sleep(1000)
|
||||
// await plugin.sleep(1000)
|
||||
// await plugin.rollback(deployOpts)
|
||||
})
|
||||
})
|
||||
3166
packages/plugins/plugin-host/package-lock.json
generated
Normal file
3166
packages/plugins/plugin-host/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
26
packages/plugins/plugin-host/package.json
Normal file
26
packages/plugins/plugin-host/package.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "@certd/plugin-host",
|
||||
"version": "0.1.21",
|
||||
"description": "",
|
||||
"main": "src/index.js",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@certd/api": "^0.1.17",
|
||||
"dayjs": "^1.9.7",
|
||||
"lodash-es": "^4.17.20",
|
||||
"ssh2": "^0.8.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/certd": "^0.1.19",
|
||||
"chai": "^4.2.0",
|
||||
"eslint": "^7.15.0",
|
||||
"eslint-config-standard": "^16.0.2",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"mocha": "^8.2.1"
|
||||
},
|
||||
"author": "Greper",
|
||||
"license": "MIT",
|
||||
"gitHead": "4a421d5b142d453203c68ce6d1036e168ea2455b"
|
||||
}
|
||||
26
packages/plugins/plugin-host/src/access-providers/ssh.js
Normal file
26
packages/plugins/plugin-host/src/access-providers/ssh.js
Normal file
@@ -0,0 +1,26 @@
|
||||
export class SSHAccessProvider {
|
||||
static define () {
|
||||
return {
|
||||
name: 'ssh',
|
||||
label: '主机',
|
||||
desc: '',
|
||||
input: {
|
||||
host: { required: true },
|
||||
port: {
|
||||
label: '端口',
|
||||
type: Number,
|
||||
default: '22',
|
||||
required: true
|
||||
},
|
||||
username: {
|
||||
default: 'root',
|
||||
required: true
|
||||
},
|
||||
password: { desc: '登录密码' },
|
||||
privateKey: {
|
||||
desc: '密钥,密码或此项必填一项'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
packages/plugins/plugin-host/src/index.js
Normal file
22
packages/plugins/plugin-host/src/index.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import _ from 'lodash-es'
|
||||
|
||||
import { SSHAccessProvider } from './access-providers/ssh.js'
|
||||
|
||||
import { UploadCertToHost } from './plugins/upload-to-host/index.js'
|
||||
import { HostShellExecute } from './plugins/host-shell-execute/index.js'
|
||||
|
||||
import { pluginRegistry, accessProviderRegistry } from '@certd/api'
|
||||
|
||||
export const DefaultPlugins = {
|
||||
UploadCertToHost,
|
||||
HostShellExecute
|
||||
}
|
||||
export default {
|
||||
install () {
|
||||
_.forEach(DefaultPlugins, item => {
|
||||
pluginRegistry.install(item)
|
||||
})
|
||||
|
||||
accessProviderRegistry.install(SSHAccessProvider)
|
||||
}
|
||||
}
|
||||
@@ -12,14 +12,21 @@ export class HostShellExecute extends AbstractHostPlugin {
|
||||
name: 'hostShellExecute',
|
||||
label: '执行远程主机脚本命令',
|
||||
input: {
|
||||
script: {
|
||||
label: 'shell脚本命令'
|
||||
},
|
||||
accessProvider: {
|
||||
label: '主机登录配置',
|
||||
type: [String, Object],
|
||||
desc: 'AccessProviders的key 或 一个包含用户名密码的对象',
|
||||
options: 'accessProviders[type=ssh]'
|
||||
desc: '登录',
|
||||
component: {
|
||||
name: 'access-provider-selector',
|
||||
filter: 'ssh'
|
||||
},
|
||||
required: true
|
||||
},
|
||||
script: {
|
||||
label: 'shell脚本命令',
|
||||
component: {
|
||||
name: 'a-textarea'
|
||||
}
|
||||
}
|
||||
},
|
||||
output: {
|
||||
@@ -32,7 +39,7 @@ export class HostShellExecute extends AbstractHostPlugin {
|
||||
const { script, accessProvider } = props
|
||||
const connectConf = this.getAccessProvider(accessProvider)
|
||||
const sshClient = new SshClient()
|
||||
const ret = await sshClient.shell({
|
||||
const ret = await sshClient.exec({
|
||||
connectConf,
|
||||
script
|
||||
})
|
||||
@@ -1,6 +1,8 @@
|
||||
import ssh2 from 'ssh2'
|
||||
import logger from '../utils/util.log.js'
|
||||
import path from 'path'
|
||||
import { util } from '@certd/api'
|
||||
import _ from 'lodash-es'
|
||||
const logger = util.logger
|
||||
export class SshClient {
|
||||
/**
|
||||
*
|
||||
@@ -13,7 +15,7 @@ export class SshClient {
|
||||
}
|
||||
* @param transports
|
||||
*/
|
||||
uploadFiles ({ connectConf, transports }) {
|
||||
uploadFiles ({ connectConf, transports, sudo = false }) {
|
||||
const conn = new ssh2.Client()
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -27,7 +29,8 @@ export class SshClient {
|
||||
try {
|
||||
for (const transport of transports) {
|
||||
logger.info('上传文件:', JSON.stringify(transport))
|
||||
await this.exec({ conn, cmd: 'mkdir ' + path.dirname(transport.remotePath) })
|
||||
sudo = sudo ? 'sudo' : ''
|
||||
await this.exec({ connectConf, script: `${sudo} mkdir -p ${path.dirname(transport.remotePath)} ` })
|
||||
await this.fastPut({ sftp, ...transport })
|
||||
}
|
||||
resolve()
|
||||
@@ -41,6 +44,43 @@ export class SshClient {
|
||||
})
|
||||
}
|
||||
|
||||
exec ({ connectConf, script }) {
|
||||
if (_.isArray(script)) {
|
||||
script = script.join('\n')
|
||||
}
|
||||
console.log('执行命令:', script)
|
||||
return new Promise((resolve, reject) => {
|
||||
this.connect({
|
||||
connectConf,
|
||||
onReady: (conn) => {
|
||||
conn.exec(script, (err, stream) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
return
|
||||
}
|
||||
let data = null
|
||||
stream.on('close', (code, signal) => {
|
||||
console.log(`[${connectConf.host}][close]:code:${code}`)
|
||||
data = data ? data.toString() : null
|
||||
if (code === 0) {
|
||||
resolve(data)
|
||||
} else {
|
||||
reject(new Error(data))
|
||||
}
|
||||
conn.end()
|
||||
}).on('data', (ret) => {
|
||||
console.log(`[${connectConf.host}][info]: ` + ret)
|
||||
data = ret
|
||||
}).stderr.on('data', (err) => {
|
||||
console.log(`[${connectConf.host}][error]: ` + err)
|
||||
data = err
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
shell ({ connectConf, script }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.connect({
|
||||
@@ -87,24 +127,4 @@ export class SshClient {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
exec ({ conn, cmd }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
conn.exec(cmd, (err, stream) => {
|
||||
if (err) {
|
||||
logger.error('执行命令出错', err)
|
||||
reject(err)
|
||||
// return conn.end()
|
||||
}
|
||||
|
||||
stream.on('close', (code, signal) => {
|
||||
// logger.info('Stream :: close :: code: ' + code + ', signal: ' + signal)
|
||||
// conn.end()
|
||||
resolve()
|
||||
}).on('data', (data) => {
|
||||
logger.info('data', data.toString())
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -13,16 +13,23 @@ export class UploadCertToHost extends AbstractHostPlugin {
|
||||
label: '上传证书到主机',
|
||||
input: {
|
||||
crtPath: {
|
||||
label: '证书路径'
|
||||
label: '证书保存路径'
|
||||
},
|
||||
keyPath: {
|
||||
label: '私钥路径'
|
||||
label: '私钥保存路径'
|
||||
},
|
||||
accessProvider: {
|
||||
label: '主机登录配置',
|
||||
type: [String, Object],
|
||||
desc: 'AccessProviders的key 或 一个包含用户名密码的对象',
|
||||
options: 'accessProviders[type=ssh]'
|
||||
desc: 'access授权',
|
||||
component: {
|
||||
name: 'access-provider-selector',
|
||||
filter: 'ssh'
|
||||
},
|
||||
required: true
|
||||
},
|
||||
sudo: {
|
||||
label: '是否sudo'
|
||||
}
|
||||
},
|
||||
output: {
|
||||
@@ -0,0 +1,52 @@
|
||||
import pkg from 'chai'
|
||||
import { HostShellExecute } from '../../src/plugins/host-shell-execute/index.js'
|
||||
import { Certd } from '@certd/certd'
|
||||
import { createOptions } from '../../../../../test/options.js'
|
||||
const { expect } = pkg
|
||||
describe('HostShellExecute', function () {
|
||||
it('#execute', async function () {
|
||||
this.timeout(10000)
|
||||
const options = createOptions()
|
||||
options.args = { test: false }
|
||||
options.cert.email = 'xiaojunnuo@qq.com'
|
||||
options.cert.domains = ['*.docmirror.cn']
|
||||
const plugin = new HostShellExecute(options)
|
||||
const certd = new Certd(options)
|
||||
const cert = await certd.readCurrentCert()
|
||||
const context = {}
|
||||
const uploadOpts = {
|
||||
cert,
|
||||
props: { script: ['ls ', 'ls '], accessProvider: 'aliyun-ssh' },
|
||||
context
|
||||
}
|
||||
const ret = await plugin.doExecute(uploadOpts)
|
||||
expect(ret).ok
|
||||
console.log('-----' + JSON.stringify(ret))
|
||||
})
|
||||
|
||||
it('#execute-hk-restart-docker', async function () {
|
||||
this.timeout(10000)
|
||||
const options = createOptions()
|
||||
const plugin = new HostShellExecute(options)
|
||||
const uploadOpts = {
|
||||
props: { script: ['cd /home/ubuntu/deloy/nginx-proxy\nsudo docker-compose build\nsudo docker-compose up -d\n'], accessProvider: 'aliyun-ssh-hk' },
|
||||
context: {}
|
||||
}
|
||||
const ret = await plugin.doExecute(uploadOpts)
|
||||
expect(ret).ok
|
||||
console.log('-----' + JSON.stringify(ret))
|
||||
})
|
||||
|
||||
it('#execute-publicKey-login', async function () {
|
||||
this.timeout(10000)
|
||||
const options = createOptions()
|
||||
const plugin = new HostShellExecute(options)
|
||||
const shellOpts = {
|
||||
props: { script: ['ls'], accessProvider: 'tencent-ssh-base01' },
|
||||
context: {}
|
||||
}
|
||||
const ret = await plugin.doExecute(shellOpts)
|
||||
expect(ret).ok
|
||||
console.log('-----' + JSON.stringify(ret))
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,48 @@
|
||||
import pkg from 'chai'
|
||||
import { UploadCertToHost } from '../../src/plugins/upload-to-host/index.js'
|
||||
import { Certd } from '@certd/certd'
|
||||
import { createOptions } from '../../../../../test/options.js'
|
||||
const { expect } = pkg
|
||||
describe('PluginUploadToHost', function () {
|
||||
it('#execute', async function () {
|
||||
this.timeout(10000)
|
||||
const options = createOptions()
|
||||
options.args = { test: false }
|
||||
options.cert.email = 'xiaojunnuo@qq.com'
|
||||
options.cert.domains = ['*.docmirror.cn']
|
||||
const plugin = new UploadCertToHost(options)
|
||||
const certd = new Certd(options)
|
||||
const cert = await certd.readCurrentCert()
|
||||
const context = {}
|
||||
const uploadOpts = {
|
||||
cert,
|
||||
props: { crtPath: '/root/certd/test/test.crt', keyPath: '/root/certd/test/test.key', accessProvider: 'aliyun-ssh' },
|
||||
context
|
||||
}
|
||||
await plugin.doExecute(uploadOpts)
|
||||
console.log('context:', context)
|
||||
|
||||
await plugin.doRollback(uploadOpts)
|
||||
})
|
||||
|
||||
it('#execute-to-ubantu', async function () {
|
||||
this.timeout(10000)
|
||||
const options = createOptions()
|
||||
options.args = { test: false }
|
||||
options.cert.email = 'xiaojunnuo@qq.com'
|
||||
options.cert.domains = ['*.docmirror.cn']
|
||||
const plugin = new UploadCertToHost(options)
|
||||
const certd = new Certd(options)
|
||||
const cert = await certd.readCurrentCert()
|
||||
const context = {}
|
||||
const uploadOpts = {
|
||||
cert,
|
||||
props: { crtPath: '/home/ubuntu/deloy/nginx-proxy/ssl/test.crt', keyPath: '/home/ubuntu/deloy/nginx-proxy/ssl/test.key', accessProvider: 'aliyun-ssh-hk' },
|
||||
context
|
||||
}
|
||||
await plugin.doExecute(uploadOpts)
|
||||
console.log('context:', context)
|
||||
|
||||
await plugin.doRollback(uploadOpts)
|
||||
})
|
||||
})
|
||||
1858
packages/plugins/plugin-host/yarn-error.log
Normal file
1858
packages/plugins/plugin-host/yarn-error.log
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/plugins",
|
||||
"version": "0.1.11",
|
||||
"name": "@certd/plugin-tencent",
|
||||
"version": "0.1.21",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -8,6 +8,7 @@
|
||||
"version": "1.7.10",
|
||||
"resolved": "https://registry.npm.taobao.org/@alicloud/pop-core/download/@alicloud/pop-core-1.7.10.tgz",
|
||||
"integrity": "sha1-0OIhA227DM3kU90Jsc+r2DQbemk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "^3.1.0",
|
||||
"httpx": "^2.1.2",
|
||||
@@ -131,10 +132,41 @@
|
||||
"to-fast-properties": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"@certd/acme-client": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@certd/acme-client/-/acme-client-0.1.6.tgz",
|
||||
"integrity": "sha512-XffzB/QHRj61gUHXor1B8R2TVt7HnklJpjAbwQi8vHjBGloU8I3occJxIunoh1AShhc4wsxnc+h/D5yRIUp17A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"axios": "0.21.1",
|
||||
"backo2": "^1.0.0",
|
||||
"bluebird": "^3.5.0",
|
||||
"debug": "^4.1.1",
|
||||
"log4js": "^6.3.0",
|
||||
"node-forge": "^0.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
|
||||
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@certd/api": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@certd/api/-/api-0.1.7.tgz",
|
||||
"integrity": "sha512-2spEdF9A6Tpe5KwkbWV1zE9Zwql04DrG5KlWRUsn8kLvwY6qfdDsdCsNoFf1+XDytn4OYH5nfrMGZBi8TpG84w==",
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npm.taobao.org/@certd/api/download/@certd/api-0.1.13.tgz",
|
||||
"integrity": "sha1-ProCS1OfZAWzr3bIKHHfZA5hrOw=",
|
||||
"requires": {
|
||||
"axios": "^0.21.1",
|
||||
"dayjs": "^1.9.7",
|
||||
@@ -143,6 +175,32 @@
|
||||
"qs": "^6.9.4"
|
||||
}
|
||||
},
|
||||
"@certd/certd": {
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@certd/certd/-/certd-0.1.13.tgz",
|
||||
"integrity": "sha512-ng4iFJY23AhTM2VY/tX/3ywoIF96pUF6VP6iXRlhdap8o4xOEywfjeHefFMxdi85Aw3sklBm4U38QZjqA++tnA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@certd/acme-client": "^0.1.6",
|
||||
"@certd/api": "^0.1.13",
|
||||
"@certd/dns-providers": "^0.1.13",
|
||||
"dayjs": "^1.9.7",
|
||||
"lodash-es": "^4.17.20",
|
||||
"node-forge": "^0.10.0"
|
||||
}
|
||||
},
|
||||
"@certd/dns-providers": {
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@certd/dns-providers/-/dns-providers-0.1.13.tgz",
|
||||
"integrity": "sha512-a9eD61t6dnacTLJqEUWijhVf1OUmZmPyrm8asTxMAPt7zw60xNxFSJFGHGJYM0bMGPsqUP4WBsSZ5JU4SHy5bg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@alicloud/pop-core": "^1.7.10",
|
||||
"@certd/api": "^0.1.13",
|
||||
"lodash-es": "^4.17.20",
|
||||
"tencentcloud-sdk-nodejs": "^4.0.44"
|
||||
}
|
||||
},
|
||||
"@eslint/eslintrc": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npm.taobao.org/@eslint/eslintrc/download/@eslint/eslintrc-0.2.2.tgz?cache=0&sync_timestamp=1607145629875&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40eslint%2Feslintrc%2Fdownload%2F%40eslint%2Feslintrc-0.2.2.tgz",
|
||||
@@ -490,8 +548,8 @@
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.21.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
|
||||
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
|
||||
"resolved": "https://registry.npm.taobao.org/axios/download/axios-0.21.1.tgz?cache=0&sync_timestamp=1608609215811&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Faxios%2Fdownload%2Faxios-0.21.1.tgz",
|
||||
"integrity": "sha1-IlY0gZYvTWvemnbVFu8OXTwJsrg=",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.10.0"
|
||||
}
|
||||
@@ -509,6 +567,12 @@
|
||||
"resolve": "^1.12.0"
|
||||
}
|
||||
},
|
||||
"backo2": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
|
||||
"integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=",
|
||||
"dev": true
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.0.tgz",
|
||||
@@ -530,7 +594,8 @@
|
||||
"bignumber.js": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npm.taobao.org/bignumber.js/download/bignumber.js-9.0.1.tgz",
|
||||
"integrity": "sha1-jXuhJMiCv9jkMmDGdHVRjQaJ5OU="
|
||||
"integrity": "sha1-jXuhJMiCv9jkMmDGdHVRjQaJ5OU=",
|
||||
"dev": true
|
||||
},
|
||||
"binary-extensions": {
|
||||
"version": "2.1.0",
|
||||
@@ -538,6 +603,12 @@
|
||||
"integrity": "sha1-MPpAyef+B9vIlWeM0ocCTeokHdk=",
|
||||
"dev": true
|
||||
},
|
||||
"bluebird": {
|
||||
"version": "3.7.2",
|
||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
|
||||
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
|
||||
"dev": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npm.taobao.org/brace-expansion/download/brace-expansion-1.1.11.tgz?cache=0&sync_timestamp=1601898189928&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbrace-expansion%2Fdownload%2Fbrace-expansion-1.1.11.tgz",
|
||||
@@ -784,8 +855,8 @@
|
||||
},
|
||||
"date-format": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/date-format/-/date-format-3.0.0.tgz",
|
||||
"integrity": "sha512-eyTcpKOcamdhWJXj56DpQMo1ylSQpcGtGKXcU0Tb97+K56/CF5amAqqqNj0+KvA0iw2ynxtHWFsPDSClCxe48w=="
|
||||
"resolved": "https://registry.npm.taobao.org/date-format/download/date-format-3.0.0.tgz",
|
||||
"integrity": "sha1-64eANlx9KxURB4+0keZHl4DzrZU="
|
||||
},
|
||||
"dayjs": {
|
||||
"version": "1.10.2",
|
||||
@@ -1433,13 +1504,13 @@
|
||||
},
|
||||
"flatted": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz",
|
||||
"integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA=="
|
||||
"resolved": "https://registry.npm.taobao.org/flatted/download/flatted-2.0.2.tgz?cache=0&sync_timestamp=1611061309017&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fflatted%2Fdownload%2Fflatted-2.0.2.tgz",
|
||||
"integrity": "sha1-RXWyHivO50NKqb5mL0t7X5wrUTg="
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.13.1",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz",
|
||||
"integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg=="
|
||||
"version": "1.13.2",
|
||||
"resolved": "https://registry.npm.taobao.org/follow-redirects/download/follow-redirects-1.13.2.tgz?cache=0&sync_timestamp=1611606737937&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffollow-redirects%2Fdownload%2Ffollow-redirects-1.13.2.tgz",
|
||||
"integrity": "sha1-3XPI7/wScoulz0JZ12DqX7g+MUc="
|
||||
},
|
||||
"forever-agent": {
|
||||
"version": "0.6.1",
|
||||
@@ -1458,8 +1529,8 @@
|
||||
},
|
||||
"fs-extra": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
|
||||
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
|
||||
"resolved": "https://registry.npm.taobao.org/fs-extra/download/fs-extra-8.1.0.tgz?cache=0&sync_timestamp=1611075469998&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffs-extra%2Fdownload%2Ffs-extra-8.1.0.tgz",
|
||||
"integrity": "sha1-SdQ8RaiM2Wd2aMt74bRu/bjS4cA=",
|
||||
"requires": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^4.0.0",
|
||||
@@ -1662,6 +1733,7 @@
|
||||
"version": "2.2.7",
|
||||
"resolved": "https://registry.npm.taobao.org/httpx/download/httpx-2.2.7.tgz?cache=0&sync_timestamp=1604908999113&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttpx%2Fdownload%2Fhttpx-2.2.7.tgz",
|
||||
"integrity": "sha1-HjQZgUbjLKMwWmbBEglVnhy+ugk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "^14",
|
||||
"debug": "^4.1.1"
|
||||
@@ -1671,6 +1743,7 @@
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npm.taobao.org/debug/download/debug-4.3.1.tgz?cache=0&sync_timestamp=1607566533140&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-4.3.1.tgz",
|
||||
"integrity": "sha1-8NIpxQXgxtjEmsVT0bE9wYP2su4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
@@ -1678,7 +1751,8 @@
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz?cache=0&sync_timestamp=1607433842694&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.1.2.tgz",
|
||||
"integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk="
|
||||
"integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1923,6 +1997,7 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npm.taobao.org/json-bigint/download/json-bigint-1.0.0.tgz",
|
||||
"integrity": "sha1-rlR4I6wMrYOYZn+M2e9HMPWwH/E=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bignumber.js": "^9.0.0"
|
||||
}
|
||||
@@ -1969,7 +2044,7 @@
|
||||
},
|
||||
"jsonfile": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
||||
"resolved": "https://registry.npm.taobao.org/jsonfile/download/jsonfile-4.0.0.tgz?cache=0&sync_timestamp=1604161797011&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjsonfile%2Fdownload%2Fjsonfile-4.0.0.tgz",
|
||||
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.6"
|
||||
@@ -2011,7 +2086,8 @@
|
||||
"kitx": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npm.taobao.org/kitx/download/kitx-1.3.0.tgz",
|
||||
"integrity": "sha1-qz7nxZjSsdYp/VVWj4aMREDCAOo="
|
||||
"integrity": "sha1-qz7nxZjSsdYp/VVWj4aMREDCAOo=",
|
||||
"dev": true
|
||||
},
|
||||
"kubernetes-client": {
|
||||
"version": "9.0.0",
|
||||
@@ -2137,8 +2213,8 @@
|
||||
},
|
||||
"log4js": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/log4js/-/log4js-6.3.0.tgz",
|
||||
"integrity": "sha512-Mc8jNuSFImQUIateBFwdOQcmC6Q5maU0VVvdC2R6XMb66/VnT+7WS4D/0EeNMZu1YODmJe5NIn2XftCzEocUgw==",
|
||||
"resolved": "https://registry.npm.taobao.org/log4js/download/log4js-6.3.0.tgz",
|
||||
"integrity": "sha1-EN+vu0NDUaPjAnegC5h5RG9xW8s=",
|
||||
"requires": {
|
||||
"date-format": "^3.0.0",
|
||||
"debug": "^4.1.1",
|
||||
@@ -2149,16 +2225,16 @@
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
|
||||
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
|
||||
"resolved": "https://registry.npm.taobao.org/debug/download/debug-4.3.1.tgz?cache=0&sync_timestamp=1607566533140&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-4.3.1.tgz",
|
||||
"integrity": "sha1-8NIpxQXgxtjEmsVT0bE9wYP2su4=",
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
"resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz?cache=0&sync_timestamp=1607433842694&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.1.2.tgz",
|
||||
"integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -2366,6 +2442,12 @@
|
||||
"resolved": "https://registry.npm.taobao.org/node-fetch/download/node-fetch-2.6.1.tgz?cache=0&sync_timestamp=1599309179354&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnode-fetch%2Fdownload%2Fnode-fetch-2.6.1.tgz",
|
||||
"integrity": "sha1-BFvTI2Mfdu0uK1VXM5RBa2OaAFI="
|
||||
},
|
||||
"node-forge": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
|
||||
"integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==",
|
||||
"dev": true
|
||||
},
|
||||
"normalize-package-data": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npm.taobao.org/normalize-package-data/download/normalize-package-data-2.5.0.tgz?cache=0&sync_timestamp=1602547447569&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnormalize-package-data%2Fdownload%2Fnormalize-package-data-2.5.0.tgz",
|
||||
@@ -2875,9 +2957,9 @@
|
||||
}
|
||||
},
|
||||
"rfdc": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz",
|
||||
"integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug=="
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npm.taobao.org/rfdc/download/rfdc-1.2.0.tgz?cache=0&sync_timestamp=1610744108114&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frfdc%2Fdownload%2Frfdc-1.2.0.tgz",
|
||||
"integrity": "sha1-npiUJY9I8oS0PDFDxoBwpPNzuUk="
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "3.0.2",
|
||||
@@ -2901,7 +2983,8 @@
|
||||
"sax": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npm.taobao.org/sax/download/sax-1.2.4.tgz",
|
||||
"integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk="
|
||||
"integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=",
|
||||
"dev": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.4",
|
||||
@@ -3041,24 +3124,6 @@
|
||||
"resolved": "https://registry.npm.taobao.org/sprintf-js/download/sprintf-js-1.0.3.tgz",
|
||||
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
|
||||
},
|
||||
"ssh2": {
|
||||
"version": "0.8.9",
|
||||
"resolved": "https://registry.npm.taobao.org/ssh2/download/ssh2-0.8.9.tgz",
|
||||
"integrity": "sha1-VNo6bEuj2vDYR3pTikgTJgkYFfM=",
|
||||
"requires": {
|
||||
"ssh2-streams": "~0.4.10"
|
||||
}
|
||||
},
|
||||
"ssh2-streams": {
|
||||
"version": "0.4.10",
|
||||
"resolved": "https://registry.npm.taobao.org/ssh2-streams/download/ssh2-streams-0.4.10.tgz",
|
||||
"integrity": "sha1-SO9+ig452PKSHDBSHVbayzHSOjQ=",
|
||||
"requires": {
|
||||
"asn1": "~0.2.0",
|
||||
"bcrypt-pbkdf": "^1.0.2",
|
||||
"streamsearch": "~0.1.2"
|
||||
}
|
||||
},
|
||||
"sshpk": {
|
||||
"version": "1.16.1",
|
||||
"resolved": "https://registry.npm.taobao.org/sshpk/download/sshpk-1.16.1.tgz",
|
||||
@@ -3077,8 +3142,8 @@
|
||||
},
|
||||
"streamroller": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/streamroller/-/streamroller-2.2.4.tgz",
|
||||
"integrity": "sha512-OG79qm3AujAM9ImoqgWEY1xG4HX+Lw+yY6qZj9R1K2mhF5bEmQ849wvrb+4vt4jLMLzwXttJlQbOdPOQVRv7DQ==",
|
||||
"resolved": "https://registry.npm.taobao.org/streamroller/download/streamroller-2.2.4.tgz",
|
||||
"integrity": "sha1-wZjO1C25QIamGTYIGHzoCl8rDlM=",
|
||||
"requires": {
|
||||
"date-format": "^2.1.0",
|
||||
"debug": "^4.1.1",
|
||||
@@ -3087,29 +3152,24 @@
|
||||
"dependencies": {
|
||||
"date-format": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz",
|
||||
"integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA=="
|
||||
"resolved": "https://registry.npm.taobao.org/date-format/download/date-format-2.1.0.tgz",
|
||||
"integrity": "sha1-MdW16iEc9f12TNOLr50DPffhJc8="
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
|
||||
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
|
||||
"resolved": "https://registry.npm.taobao.org/debug/download/debug-4.3.1.tgz?cache=0&sync_timestamp=1607566533140&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-4.3.1.tgz",
|
||||
"integrity": "sha1-8NIpxQXgxtjEmsVT0bE9wYP2su4=",
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
"resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz?cache=0&sync_timestamp=1607433842694&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.1.2.tgz",
|
||||
"integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk="
|
||||
}
|
||||
}
|
||||
},
|
||||
"streamsearch": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npm.taobao.org/streamsearch/download/streamsearch-0.1.2.tgz",
|
||||
"integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
|
||||
},
|
||||
"string-width": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npm.taobao.org/string-width/download/string-width-4.2.0.tgz",
|
||||
@@ -3331,8 +3391,8 @@
|
||||
},
|
||||
"universalify": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
|
||||
"resolved": "https://registry.npm.taobao.org/universalify/download/universalify-0.1.2.tgz?cache=0&sync_timestamp=1603179967633&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Funiversalify%2Fdownload%2Funiversalify-0.1.2.tgz",
|
||||
"integrity": "sha1-tkb2m+OULavOzJ1mOcgNwQXvqmY="
|
||||
},
|
||||
"uri-js": {
|
||||
"version": "4.4.0",
|
||||
@@ -3520,6 +3580,7 @@
|
||||
"version": "0.4.23",
|
||||
"resolved": "https://registry.npm.taobao.org/xml2js/download/xml2js-0.4.23.tgz?cache=0&sync_timestamp=1599054229598&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fxml2js%2Fdownload%2Fxml2js-0.4.23.tgz",
|
||||
"integrity": "sha1-oMaVFnUkIesqx1juTUzPWIQ+rGY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"sax": ">=0.6.0",
|
||||
"xmlbuilder": "~11.0.0"
|
||||
@@ -3528,7 +3589,8 @@
|
||||
"xmlbuilder": {
|
||||
"version": "11.0.1",
|
||||
"resolved": "https://registry.npm.taobao.org/xmlbuilder/download/xmlbuilder-11.0.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fxmlbuilder%2Fdownload%2Fxmlbuilder-11.0.1.tgz",
|
||||
"integrity": "sha1-vpuuHIoEbnazESdyY0fQrXACvrM="
|
||||
"integrity": "sha1-vpuuHIoEbnazESdyY0fQrXACvrM=",
|
||||
"dev": true
|
||||
},
|
||||
"y18n": {
|
||||
"version": "4.0.1",
|
||||
@@ -1,19 +1,18 @@
|
||||
{
|
||||
"name": "@certd/plugins",
|
||||
"version": "0.1.11",
|
||||
"name": "@certd/plugin-tencent",
|
||||
"version": "0.1.21",
|
||||
"description": "",
|
||||
"main": "./src/index.js",
|
||||
"main": "src/index.js",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@alicloud/pop-core": "^1.7.10",
|
||||
"@certd/api": "^0.1.11",
|
||||
"@certd/api": "^0.1.17",
|
||||
"dayjs": "^1.9.7",
|
||||
"kubernetes-client": "^9.0.0",
|
||||
"lodash-es": "^4.17.20",
|
||||
"ssh2": "^0.8.9",
|
||||
"tencentcloud-sdk-nodejs": "^4.0.44"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/certd": "^0.1.19",
|
||||
"chai": "^4.2.0",
|
||||
"eslint": "^7.15.0",
|
||||
"eslint-config-standard": "^16.0.2",
|
||||
@@ -23,5 +22,6 @@
|
||||
"mocha": "^8.2.1"
|
||||
},
|
||||
"author": "Greper",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"gitHead": "4a421d5b142d453203c68ce6d1036e168ea2455b"
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
export class DnspodAccessProvider {
|
||||
static define () {
|
||||
return {
|
||||
name: 'dnspod',
|
||||
label: 'dnspod',
|
||||
desc: '腾讯云的域名解析接口已迁移到dnspod',
|
||||
input: {
|
||||
id: {
|
||||
type: String,
|
||||
component: {
|
||||
placeholder: 'dnspod接口账户id',
|
||||
rules: [{ required: true, message: '该项必填' }]
|
||||
}
|
||||
},
|
||||
token: {
|
||||
type: String,
|
||||
label: 'token',
|
||||
component: {
|
||||
placeholder: '开放接口token',
|
||||
rules: [{ required: true, message: '该项必填' }]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
export class TencentAccessProvider {
|
||||
static define () {
|
||||
return {
|
||||
name: 'tencent',
|
||||
label: '腾讯云',
|
||||
input: {
|
||||
secretId: {
|
||||
type: String,
|
||||
label: 'secretId',
|
||||
component: {
|
||||
placeholder: 'secretId',
|
||||
rules: [{ required: true, message: '该项必填' }]
|
||||
}
|
||||
},
|
||||
secretKey: {
|
||||
type: String,
|
||||
label: 'secretKey',
|
||||
component: {
|
||||
placeholder: 'secretKey',
|
||||
rules: [{ required: true, message: '该项必填' }]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,19 +2,34 @@ import { AbstractDnsProvider, util } from '@certd/api'
|
||||
import _ from 'lodash-es'
|
||||
const request = util.request
|
||||
export class DnspodDnsProvider extends AbstractDnsProvider {
|
||||
static name () {
|
||||
return 'dnspod'
|
||||
}
|
||||
|
||||
constructor (dnsProviderConfig) {
|
||||
super()
|
||||
if (!dnsProviderConfig.id || !dnsProviderConfig.token) {
|
||||
throw new Error('请正确配置dnspod的 id 和 token')
|
||||
static define () {
|
||||
return {
|
||||
name: 'dnspod',
|
||||
label: 'dnspod(腾讯云)',
|
||||
desc: '腾讯云的域名解析接口已迁移到dnspod',
|
||||
input: {
|
||||
accessProvider: {
|
||||
label: '授权',
|
||||
type: [String, Object],
|
||||
desc: '需要dnspod类型的授权',
|
||||
component: {
|
||||
name: 'access-provider-selector',
|
||||
filter: 'dnspod'
|
||||
},
|
||||
required: true
|
||||
}
|
||||
}
|
||||
}
|
||||
this.loginToken = dnsProviderConfig.id + ',' + dnsProviderConfig.token
|
||||
}
|
||||
|
||||
async doRequest (options) {
|
||||
constructor (args) {
|
||||
super(args)
|
||||
const { props } = args
|
||||
const accessProvider = this.getAccessProvider(props.accessProvider)
|
||||
this.loginToken = accessProvider.id + ',' + accessProvider.token
|
||||
}
|
||||
|
||||
async doRequest (options, successCodes = []) {
|
||||
const config = {
|
||||
method: 'post',
|
||||
formData: {
|
||||
@@ -28,8 +43,11 @@ export class DnspodDnsProvider extends AbstractDnsProvider {
|
||||
_.merge(config, options)
|
||||
|
||||
const ret = await request(config)
|
||||
if (!ret || !ret.status || ret.status.code !== '1') {
|
||||
throw new Error('请求失败:' + ret.status.message + ',api=' + config.url)
|
||||
if (!ret || !ret.status) {
|
||||
const code = ret.status.code
|
||||
if (code !== '1' || !successCodes.includes(code)) {
|
||||
throw new Error('请求失败:' + ret.status.message + ',api=' + config.url)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
@@ -58,7 +76,7 @@ export class DnspodDnsProvider extends AbstractDnsProvider {
|
||||
value: value,
|
||||
mx: 1
|
||||
}
|
||||
})
|
||||
}, ['104'])// 104错误码为记录已存在,无需再次添加
|
||||
this.logger.info('添加域名解析成功:', fullRecord, value, JSON.stringify(ret.record))
|
||||
return ret.record
|
||||
}
|
||||
34
packages/plugins/plugin-tencent/src/index.js
Normal file
34
packages/plugins/plugin-tencent/src/index.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import _ from 'lodash-es'
|
||||
|
||||
import { TencentAccessProvider } from './access-providers/tencent.js'
|
||||
import { DnspodAccessProvider } from './access-providers/dnspod.js'
|
||||
import { DnspodDnsProvider } from './dns-providers/dnspod.js'
|
||||
|
||||
import { UploadCertToTencent } from './plugins/upload-to-tencent/index.js'
|
||||
|
||||
import { DeployCertToTencentCDN } from './plugins/deploy-to-cdn/index.js'
|
||||
|
||||
import { DeployCertToTencentCLB } from './plugins/deploy-to-clb/index.js'
|
||||
|
||||
import { DeployCertToTencentTKEIngress } from './plugins/deploy-to-tke-ingress/index.js'
|
||||
|
||||
import { pluginRegistry, accessProviderRegistry, dnsProviderRegistry } from '@certd/api'
|
||||
|
||||
export const DefaultPlugins = {
|
||||
UploadCertToTencent,
|
||||
DeployCertToTencentTKEIngress,
|
||||
DeployCertToTencentCDN,
|
||||
DeployCertToTencentCLB
|
||||
}
|
||||
export default {
|
||||
install () {
|
||||
_.forEach(DefaultPlugins, item => {
|
||||
pluginRegistry.install(item)
|
||||
})
|
||||
|
||||
accessProviderRegistry.install(TencentAccessProvider)
|
||||
accessProviderRegistry.install(DnspodAccessProvider)
|
||||
|
||||
dnsProviderRegistry.install(DnspodDnsProvider)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AbstractTencentPlugin } from '../../tencent/abstract-tencent.js'
|
||||
import { AbstractTencentPlugin } from '../abstract-tencent.js'
|
||||
import dayjs from 'dayjs'
|
||||
import tencentcloud from 'tencentcloud-sdk-nodejs'
|
||||
|
||||
@@ -19,35 +19,35 @@ export class DeployCertToTencentCDN extends AbstractTencentPlugin {
|
||||
required: true
|
||||
},
|
||||
certName: {
|
||||
label: '证书名称'
|
||||
label: '证书名称',
|
||||
desc: '证书上传后将以此参数作为名称前缀'
|
||||
},
|
||||
certType: {
|
||||
value: 'upload',
|
||||
default: 'upload',
|
||||
label: '证书来源',
|
||||
options: [
|
||||
{ value: 'upload', label: '直接上传' },
|
||||
{ value: 'cloud', label: '从证书库', desc: '需要uploadCertToTencent作为前置任务' }
|
||||
],
|
||||
desc: '如果选择‘从证书库’类型,则需要以《上传证书到腾讯云》作为前置任务',
|
||||
required: true
|
||||
},
|
||||
// serverCertificateStatus: {
|
||||
// label: '启用https',
|
||||
// options: [
|
||||
// { value: 'on', label: '开启HTTPS,并更新证书' },
|
||||
// { value: 'auto', label: '若HTTPS开启则更新,未开启不更新' }
|
||||
// ],
|
||||
// required:true
|
||||
// },
|
||||
accessProvider: {
|
||||
label: 'Access提供者',
|
||||
type: [String, Object],
|
||||
desc: 'AccessProviders的key 或 一个包含accessKeyId与accessKeySecret的对象',
|
||||
options: 'accessProviders[type=aliyun]',
|
||||
desc: 'access 授权',
|
||||
component: {
|
||||
name: 'access-provider-selector',
|
||||
filter: 'tencent'
|
||||
},
|
||||
required: true
|
||||
}
|
||||
},
|
||||
output: {
|
||||
|
||||
tencentCertId: {
|
||||
type: String,
|
||||
desc: '证书来源选择上传时,将返回此id'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AbstractTencentPlugin } from '../../tencent/abstract-tencent.js'
|
||||
import { AbstractTencentPlugin } from '../abstract-tencent.js'
|
||||
import tencentcloud from 'tencentcloud-sdk-nodejs'
|
||||
export class DeployCertToTencentCLB extends AbstractTencentPlugin {
|
||||
/**
|
||||
@@ -15,16 +15,19 @@ export class DeployCertToTencentCLB extends AbstractTencentPlugin {
|
||||
input: {
|
||||
region: {
|
||||
label: '大区',
|
||||
value: 'ap-guangzhou'
|
||||
default: 'ap-guangzhou',
|
||||
required: true
|
||||
},
|
||||
domain: {
|
||||
label: '域名',
|
||||
type: [String, Array],
|
||||
required: true,
|
||||
desc: '要更新的支持https的负载均衡的域名'
|
||||
},
|
||||
loadBalancerId: {
|
||||
label: '负载均衡ID',
|
||||
desc: '如果没有配置,则根据域名匹配负载均衡下的监听器(根据域名匹配时暂时只支持前100个)'
|
||||
desc: '如果没有配置,则根据域名匹配负载均衡下的监听器(根据域名匹配时暂时只支持前100个)',
|
||||
required: true
|
||||
},
|
||||
listenerId: {
|
||||
label: '监听器ID',
|
||||
@@ -37,8 +40,11 @@ export class DeployCertToTencentCLB extends AbstractTencentPlugin {
|
||||
accessProvider: {
|
||||
label: 'Access提供者',
|
||||
type: [String, Object],
|
||||
desc: 'AccessProviders的key 或 一个包含accessKeyId与accessKeySecret的对象',
|
||||
options: 'accessProviders[type=tencent]',
|
||||
desc: 'access授权',
|
||||
component: {
|
||||
name: 'access-provider-selector',
|
||||
filter: 'tencent'
|
||||
},
|
||||
required: true
|
||||
}
|
||||
},
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AbstractTencentPlugin } from '../../tencent/abstract-tencent.js'
|
||||
import { AbstractTencentPlugin } from '../abstract-tencent.js'
|
||||
import tencentcloud from 'tencentcloud-sdk-nodejs'
|
||||
import { K8sClient } from '../../utils/util.k8s.client.js'
|
||||
export class DeployCertToTencentTKEIngress extends AbstractTencentPlugin {
|
||||
@@ -16,27 +16,36 @@ export class DeployCertToTencentTKEIngress extends AbstractTencentPlugin {
|
||||
input: {
|
||||
region: {
|
||||
label: '大区',
|
||||
value: 'ap-guangzhou'
|
||||
default: 'ap-guangzhou',
|
||||
required: true
|
||||
},
|
||||
clusterId: {
|
||||
label: '集群ID',
|
||||
required: true,
|
||||
desc: '例如:cls-6lbj1vee'
|
||||
desc: '例如:cls-6lbj1vee',
|
||||
request: true
|
||||
},
|
||||
namespace: {
|
||||
label: '集群的namespace',
|
||||
value: 'default'
|
||||
label: '集群namespace',
|
||||
default: 'default',
|
||||
required: true
|
||||
},
|
||||
secreteName: {
|
||||
type: [String, Array],
|
||||
label: '证书的secret名称',
|
||||
desc: '支持多个(传入数组)'
|
||||
desc: '支持多个(传入数组)',
|
||||
required: true
|
||||
},
|
||||
ingressName: {
|
||||
type: [String, Array],
|
||||
label: 'ingress名称',
|
||||
desc: '支持多个(传入数组)'
|
||||
},
|
||||
ingressClass: {
|
||||
type: String,
|
||||
label: 'ingress类型',
|
||||
desc: '可选 qcloud / nginx'
|
||||
},
|
||||
clusterIp: {
|
||||
type: String,
|
||||
label: '集群内网ip',
|
||||
@@ -44,20 +53,19 @@ export class DeployCertToTencentTKEIngress extends AbstractTencentPlugin {
|
||||
},
|
||||
clusterDomain: {
|
||||
type: String,
|
||||
label: '集群域名,可不填,默认为:[clusterId].ccs.tencent-cloud.com'
|
||||
label: '集群域名',
|
||||
desc: '可不填,默认为:[clusterId].ccs.tencent-cloud.com'
|
||||
},
|
||||
/**
|
||||
* AccessProvider的key,或者一个包含access的具体的对象
|
||||
*/
|
||||
accessProvider: {
|
||||
label: 'Access提供者',
|
||||
label: 'Access授权',
|
||||
type: [String, Object],
|
||||
desc: '请选择access提供者',
|
||||
desc: 'access授权',
|
||||
component: {
|
||||
name: 'accessProviderSelect',
|
||||
props: {
|
||||
filterType: 'tencent'
|
||||
}
|
||||
name: 'access-provider-selector',
|
||||
filter: 'tencent'
|
||||
},
|
||||
required: true
|
||||
}
|
||||
@@ -83,7 +91,13 @@ export class DeployCertToTencentTKEIngress extends AbstractTencentPlugin {
|
||||
// 修改内网解析ip地址
|
||||
k8sClient.setLookup({ [clusterDomain]: { ip: props.clusterIp } })
|
||||
}
|
||||
await this.patchCertSecret({ k8sClient, props, context })
|
||||
const ingressType = props.ingressClass || 'qcloud'
|
||||
if (ingressType === 'qcloud') {
|
||||
await this.patchQcloudCertSecret({ k8sClient, props, context })
|
||||
} else {
|
||||
await this.patchNginxCertSecret({ cert, k8sClient, props, context })
|
||||
}
|
||||
|
||||
await this.sleep(2000) // 停留2秒,等待secret部署完成
|
||||
await this.restartIngress({ k8sClient, props })
|
||||
return true
|
||||
@@ -118,7 +132,7 @@ export class DeployCertToTencentTKEIngress extends AbstractTencentPlugin {
|
||||
return ret.Kubeconfig
|
||||
}
|
||||
|
||||
async patchCertSecret ({ k8sClient, props, context }) {
|
||||
async patchQcloudCertSecret ({ k8sClient, props, context }) {
|
||||
const { tencentCertId } = context
|
||||
if (tencentCertId == null) {
|
||||
throw new Error('请先将【上传证书到腾讯云】作为前置任务')
|
||||
@@ -148,6 +162,35 @@ export class DeployCertToTencentTKEIngress extends AbstractTencentPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
async patchNginxCertSecret ({ cert, k8sClient, props, context }) {
|
||||
const crt = cert.crt
|
||||
const key = cert.key
|
||||
const crtBase64 = Buffer.from(crt).toString('base64')
|
||||
const keyBase64 = Buffer.from(key).toString('base64')
|
||||
|
||||
const { namespace, secretName } = props
|
||||
|
||||
const body = {
|
||||
data: {
|
||||
'tls.crt': crtBase64,
|
||||
'tls.key': keyBase64
|
||||
},
|
||||
metadata: {
|
||||
labels: {
|
||||
certd: this.appendTimeSuffix('certd')
|
||||
}
|
||||
}
|
||||
}
|
||||
let secretNames = secretName
|
||||
if (typeof secretName === 'string') {
|
||||
secretNames = [secretName]
|
||||
}
|
||||
for (const secret of secretNames) {
|
||||
await k8sClient.patchSecret({ namespace, secretName: secret, body })
|
||||
this.logger.info(`CertSecret已更新:${secret}`)
|
||||
}
|
||||
}
|
||||
|
||||
async restartIngress ({ k8sClient, props }) {
|
||||
const { namespace, ingressName } = props
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import dayjs from 'dayjs'
|
||||
import tencentcloud from 'tencentcloud-sdk-nodejs'
|
||||
import { AbstractTencentPlugin } from '../abstract-tencent.js'
|
||||
|
||||
@@ -18,10 +17,14 @@ export class UploadCertToTencent extends AbstractTencentPlugin {
|
||||
label: '证书名称'
|
||||
},
|
||||
accessProvider: {
|
||||
label: 'Access提供者',
|
||||
label: 'Access授权',
|
||||
type: [String, Object],
|
||||
desc: 'AccessProviders的key 或 一个包含accessKeyId与accessKeySecret的对象',
|
||||
options: 'accessProviders[type=tencent]'
|
||||
desc: 'access授权',
|
||||
component: {
|
||||
name: 'access-provider-selector',
|
||||
filter: 'tencent'
|
||||
},
|
||||
required: true
|
||||
}
|
||||
},
|
||||
output: {
|
||||
@@ -45,7 +45,7 @@ export class K8sClient {
|
||||
* @param opts = {namespace:default}
|
||||
* @returns secretsList
|
||||
*/
|
||||
async getSecret (opts) {
|
||||
async getSecret (opts = {}) {
|
||||
const namespace = opts.namespace || 'default'
|
||||
const secrets = await this.client.api.v1.namespaces(namespace).secrets.get()
|
||||
return secrets
|
||||
@@ -1,13 +1,20 @@
|
||||
import pkg from 'chai'
|
||||
import { Certd } from '../../src/index.js'
|
||||
import { createOptions } from '../../../../test/options.js'
|
||||
import PluginTencent from '../../src/index.js'
|
||||
import { createOptions } from '../../../../../test/options.js'
|
||||
import { Certd } from '@certd/certd'
|
||||
const { expect } = pkg
|
||||
|
||||
// 安装默认插件和授权提供者
|
||||
PluginTencent.install()
|
||||
describe('DnspodDnsProvider', function () {
|
||||
it('#申请证书', async function () {
|
||||
this.timeout(300000)
|
||||
const options = createOptions()
|
||||
options.cert.domains = ['*.certd.xyz', '*.test.certd.xyz', '*.base.certd.xyz', 'certd.xyz']
|
||||
options.cert.dnsProvider = 'dnspod'
|
||||
options.cert.dnsProvider = {
|
||||
type: 'dnspod',
|
||||
accessProvider: 'dnspod'
|
||||
}
|
||||
options.args = { forceCert: true }
|
||||
const certd = new Certd(options)
|
||||
const cert = await certd.certApply()
|
||||
@@ -1,20 +1,31 @@
|
||||
import pkg from 'chai'
|
||||
import DnspodDnsProvider from '../../src/dns-provider/dnspod.js'
|
||||
import { Certd } from '../../src/index.js'
|
||||
import { createOptions } from '../../../../test/options.js'
|
||||
import { DnspodDnsProvider } from '../../src/dns-providers/dnspod.js'
|
||||
import { createOptions, getDnsProviderOptions } from '../../../../../test/options.js'
|
||||
const { expect } = pkg
|
||||
describe('DnspodDnsProvider', function () {
|
||||
it('#getDomainList', async function () {
|
||||
const options = createOptions()
|
||||
const dnsProvider = new DnspodDnsProvider(options.accessProviders.dnspod)
|
||||
let options = createOptions()
|
||||
options.cert.dnsProvider = {
|
||||
type: 'dnspod',
|
||||
accessProvider: 'dnspod'
|
||||
}
|
||||
options = getDnsProviderOptions(options)
|
||||
|
||||
const dnsProvider = new DnspodDnsProvider(options)
|
||||
const domainList = await dnsProvider.getDomainList()
|
||||
console.log('domainList', domainList)
|
||||
expect(domainList.length).gt(0)
|
||||
})
|
||||
|
||||
it('#createRecord&removeRecord', async function () {
|
||||
const options = createOptions()
|
||||
const dnsProvider = new DnspodDnsProvider(options.accessProviders.dnspod)
|
||||
let options = createOptions()
|
||||
options.cert.dnsProvider = {
|
||||
type: 'dnspod',
|
||||
accessProvider: 'dnspod'
|
||||
}
|
||||
options = getDnsProviderOptions(options)
|
||||
|
||||
const dnsProvider = new DnspodDnsProvider(options)
|
||||
const record = await dnsProvider.createRecord({ fullRecord: '___certd___.__test__.certd.xyz', type: 'TXT', value: 'aaaa' })
|
||||
console.log('recordId', record.id)
|
||||
expect(record.id != null).ok
|
||||
@@ -1,35 +1,33 @@
|
||||
import pkg from 'chai'
|
||||
import { DeployCertToTencentCDN } from '../../src/tencent/deploy-to-cdn/index.js'
|
||||
import { DeployCertToTencentCDN } from '../../src/plugins/deploy-to-cdn/index.js'
|
||||
import { Certd } from '@certd/certd'
|
||||
import { UploadCertToTencent } from '../../src/tencent/upload-to-tencent/index.js'
|
||||
import { createOptions } from '../../../../test/options.js'
|
||||
import { UploadCertToTencent } from '../../src/plugins/upload-to-tencent/index.js'
|
||||
import { createOptions } from '../../../../../test/options.js'
|
||||
const { expect } = pkg
|
||||
describe('DeployToTencentCDN', function () {
|
||||
it('#execute-from-store', async function () {
|
||||
const options = createOptions()
|
||||
options.args.test = false
|
||||
const certd = new Certd(options)
|
||||
const cert = certd.readCurrentCert('xiaojunnuo@qq.com', ['*.docmirror.cn'])
|
||||
const cert = await certd.readCurrentCert('xiaojunnuo@qq.com', ['*.docmirror.cn'])
|
||||
const context = {}
|
||||
const uploadPlugin = new UploadCertToTencent()
|
||||
const uploadPlugin = new UploadCertToTencent(options)
|
||||
const uploadOptions = {
|
||||
accessProviders: options.accessProviders,
|
||||
cert,
|
||||
props: { name: 'certd部署测试', accessProvider: 'tencent' },
|
||||
context
|
||||
}
|
||||
await uploadPlugin.doExecute(uploadOptions)
|
||||
|
||||
const deployPlugin = new DeployCertToTencentCDN()
|
||||
const deployPlugin = new DeployCertToTencentCDN(options)
|
||||
const deployOpts = {
|
||||
accessProviders: options.accessProviders,
|
||||
cert,
|
||||
props: { domainName: 'tentcent-certd.docmirror.cn', certName: 'certd部署测试', accessProvider: 'tencent' },
|
||||
context
|
||||
}
|
||||
const ret = await deployPlugin.doExecute(deployOpts)
|
||||
expect(ret).ok
|
||||
await deployPlugin.doExecute(deployOpts)
|
||||
console.log('context:', context)
|
||||
expect(context.tencentCertId).ok
|
||||
|
||||
await uploadPlugin.doRollback(uploadOptions)
|
||||
})
|
||||
@@ -38,17 +36,17 @@ describe('DeployToTencentCDN', function () {
|
||||
options.args.test = false
|
||||
options.cert.email = 'xiaojunnuo@qq.com'
|
||||
options.cert.domains = ['*.docmirror.cn']
|
||||
const plugin = new DeployCertToTencentCDN()
|
||||
const plugin = new DeployCertToTencentCDN(options)
|
||||
const certd = new Certd(options)
|
||||
const cert = await certd.readCurrentCert()
|
||||
const context = {}
|
||||
const deployOpts = {
|
||||
accessProviders: options.accessProviders,
|
||||
cert,
|
||||
props: { domainName: 'tentcent-certd.docmirror.cn', accessProvider: 'tencent' },
|
||||
context
|
||||
}
|
||||
const ret = await plugin.doExecute(deployOpts)
|
||||
console.log('context:', context, ret)
|
||||
expect(context).be.empty
|
||||
})
|
||||
})
|
||||
@@ -1,23 +1,22 @@
|
||||
import pkg from 'chai'
|
||||
import { DeployCertToTencentCLB } from '../../src/tencent/deploy-to-clb/index.js'
|
||||
import { DeployCertToTencentCLB } from '../../src/plugins/deploy-to-clb/index.js'
|
||||
import { Certd } from '@certd/certd'
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
import { createOptions } from '../../../../test/options.js'
|
||||
import { UploadCertToTencent } from '../../src/tencent/upload-to-tencent/index.js'
|
||||
import { createOptions } from '../../../../../test/options.js'
|
||||
import { UploadCertToTencent } from '../../src/plugins/upload-to-tencent/index.js'
|
||||
const { expect } = pkg
|
||||
describe('DeployToTencentCLB', function () {
|
||||
it('#execute-getClbList', async function () {
|
||||
const options = createOptions()
|
||||
options.args.test = false
|
||||
options.cert.dnsProvider = 'tencent-yonsz'
|
||||
const deployPlugin = new DeployCertToTencentCLB()
|
||||
const deployPlugin = new DeployCertToTencentCLB(options)
|
||||
const props = {
|
||||
region: 'ap-guangzhou',
|
||||
domain: 'certd-test-no-sni.base.yonsz.net',
|
||||
accessProvider: 'tencent-yonsz'
|
||||
}
|
||||
const accessProviders = options.accessProviders
|
||||
const accessProvider = deployPlugin.getAccessProvider(props.accessProvider, accessProviders)
|
||||
const accessProvider = deployPlugin.getAccessProvider(props.accessProvider)
|
||||
const { region } = props
|
||||
const client = deployPlugin.getClient(accessProvider, region)
|
||||
|
||||
@@ -34,13 +33,14 @@ describe('DeployToTencentCLB', function () {
|
||||
region: 'ap-guangzhou',
|
||||
domain: 'certd-test-no-sni.base.yonsz.net',
|
||||
accessProvider: 'tencent-yonsz',
|
||||
loadBalancerId: 'lb-59yhe5xo'
|
||||
loadBalancerId: 'lb-59yhe5xo',
|
||||
listenerId: 'lbl-1vfwx8dq'
|
||||
}
|
||||
const accessProvider = deployPlugin.getAccessProvider(props.accessProvider)
|
||||
const { region } = props
|
||||
const client = deployPlugin.getClient(accessProvider, region)
|
||||
|
||||
const ret = await deployPlugin.getListenerList(client, props.loadBalancerId, props)
|
||||
const ret = await deployPlugin.getListenerList(client, props.loadBalancerId, [props.listenerId])
|
||||
expect(ret.length > 0).ok
|
||||
console.log('clb count:', ret.length, ret)
|
||||
})
|
||||
@@ -54,10 +54,9 @@ describe('DeployToTencentCLB', function () {
|
||||
options.cert.domains = ['*.docmirror.cn']
|
||||
const certd = new Certd(options)
|
||||
const cert = await certd.readCurrentCert()
|
||||
const deployPlugin = new DeployCertToTencentCLB()
|
||||
const deployPlugin = new DeployCertToTencentCLB(options)
|
||||
const context = {}
|
||||
const deployOpts = {
|
||||
accessProviders: options.accessProviders,
|
||||
cert,
|
||||
props: {
|
||||
region: 'ap-guangzhou',
|
||||
@@ -72,7 +71,7 @@ describe('DeployToTencentCLB', function () {
|
||||
console.log('ret:', ret)
|
||||
|
||||
// 删除测试证书
|
||||
const uploadPlugin = new UploadCertToTencent()
|
||||
const uploadPlugin = new UploadCertToTencent(options)
|
||||
await uploadPlugin.doRollback(deployOpts)
|
||||
})
|
||||
|
||||
@@ -83,10 +82,9 @@ describe('DeployToTencentCLB', function () {
|
||||
options.cert.dnsProvider = 'tencent-yonsz'
|
||||
const certd = new Certd(options)
|
||||
const cert = certd.readCurrentCert('xiaojunnuo@qq.com', ['*.docmirror.cn'])
|
||||
const deployPlugin = new DeployCertToTencentCLB()
|
||||
const deployPlugin = new DeployCertToTencentCLB(options)
|
||||
const context = {}
|
||||
const deployOpts = {
|
||||
accessProviders: options.accessProviders,
|
||||
cert,
|
||||
props: {
|
||||
region: 'ap-guangzhou',
|
||||
@@ -98,10 +96,10 @@ describe('DeployToTencentCLB', function () {
|
||||
context
|
||||
}
|
||||
const ret = await deployPlugin.doExecute(deployOpts)
|
||||
expect(ret).ok
|
||||
console.log('ret:', ret)
|
||||
expect(ret).ok
|
||||
// 删除测试证书
|
||||
const uploadPlugin = new UploadCertToTencent()
|
||||
const uploadPlugin = new UploadCertToTencent(options)
|
||||
await uploadPlugin.doRollback(deployOpts)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,59 @@
|
||||
import pkg from 'chai'
|
||||
import { DeployCertToTencentTKEIngress } from '../../src/plugins/deploy-to-tke-ingress/index.js'
|
||||
import { Certd } from '@certd/certd'
|
||||
import { createOptions } from '../../../../../test/options.js'
|
||||
import { K8sClient } from '../../src/utils/util.k8s.client.js'
|
||||
|
||||
const { expect } = pkg
|
||||
|
||||
async function getOptions () {
|
||||
const options = createOptions()
|
||||
options.args.test = false
|
||||
options.cert.email = 'xiaojunnuo@qq.com'
|
||||
options.cert.domains = ['*.docmirror.cn']
|
||||
const certd = new Certd(options)
|
||||
const cert = await certd.readCurrentCert()
|
||||
const context = {}
|
||||
const deployOpts = {
|
||||
accessProviders: options.accessProviders,
|
||||
cert,
|
||||
props: {
|
||||
accessProvider: 'tencent-yonsz',
|
||||
region: 'ap-guangzhou',
|
||||
clusterId: 'cls-6lbj1vee'
|
||||
},
|
||||
context
|
||||
}
|
||||
return { options, deployOpts }
|
||||
}
|
||||
|
||||
describe('DeployCertToTencentTKEIngressNginx', function () {
|
||||
it('#getTKESecrets', async function () {
|
||||
this.timeout(50000)
|
||||
const { options, deployOpts } = await getOptions()
|
||||
const plugin = new DeployCertToTencentTKEIngress(options)
|
||||
const tkeClient = plugin.getTkeClient(options.accessProviders[deployOpts.props.accessProvider], deployOpts.props.region)
|
||||
const kubeConfig = await plugin.getTkeKubeConfig(tkeClient, deployOpts.props.clusterId)
|
||||
|
||||
const k8sClient = new K8sClient(kubeConfig)
|
||||
k8sClient.setLookup({
|
||||
'cls-6lbj1vee.ccs.tencent-cloud.com': { ip: '13.123.123.123' }
|
||||
})
|
||||
const secrets = await k8sClient.getSecret({ namespace: 'stress' })
|
||||
|
||||
console.log('secrets:', secrets)
|
||||
})
|
||||
it('#execute', async function () {
|
||||
this.timeout(5000)
|
||||
|
||||
const { options, deployOpts } = await getOptions()
|
||||
deployOpts.props.ingressName = 'stress-ingress-nginx'
|
||||
deployOpts.props.ingressClass = 'nginx'
|
||||
deployOpts.props.secretName = 'stress-all'
|
||||
deployOpts.props.namespace = 'stress'
|
||||
const plugin = new DeployCertToTencentTKEIngress(options)
|
||||
|
||||
const ret = await plugin.doExecute(deployOpts)
|
||||
console.log('sucess', ret)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,57 @@
|
||||
import pkg from 'chai'
|
||||
import { DeployCertToTencentTKEIngress } from '../../src/plugins/deploy-to-tke-ingress/index.js'
|
||||
import { Certd } from '@certd/certd'
|
||||
import { createOptions } from '../../../../../test/options.js'
|
||||
import { K8sClient } from '../../src/utils/util.k8s.client.js'
|
||||
|
||||
const { expect } = pkg
|
||||
|
||||
async function getOptions () {
|
||||
const options = createOptions()
|
||||
options.args.test = false
|
||||
options.cert.email = 'xiaojunnuo@qq.com'
|
||||
options.cert.domains = ['*.docmirror.cn']
|
||||
const certd = new Certd(options)
|
||||
const cert = await certd.readCurrentCert()
|
||||
const context = {}
|
||||
const deployOpts = {
|
||||
accessProviders: options.accessProviders,
|
||||
cert,
|
||||
props: {
|
||||
accessProvider: 'tencent-yonsz',
|
||||
region: 'ap-guangzhou',
|
||||
clusterId: 'cls-6lbj1vee'
|
||||
},
|
||||
context
|
||||
}
|
||||
return { options, deployOpts }
|
||||
}
|
||||
|
||||
describe('DeployCertToTencentTKEIngress', function () {
|
||||
it('#getTKESecrets', async function () {
|
||||
this.timeout(50000)
|
||||
const { options, deployOpts } = await getOptions()
|
||||
const plugin = new DeployCertToTencentTKEIngress(options)
|
||||
const tkeClient = plugin.getTkeClient(options.accessProviders[deployOpts.props.accessProvider], deployOpts.props.region)
|
||||
const kubeConfig = await plugin.getTkeKubeConfig(tkeClient, deployOpts.props.clusterId)
|
||||
|
||||
const k8sClient = new K8sClient(kubeConfig)
|
||||
k8sClient.setLookup({
|
||||
'cls-6lbj1vee.ccs.tencent-cloud.com': { ip: '13.123.123.123' }
|
||||
})
|
||||
const secrets = await k8sClient.getSecret({ namespace: 'default' })
|
||||
|
||||
console.log('secrets:', secrets)
|
||||
})
|
||||
it('#execute', async function () {
|
||||
this.timeout(5000)
|
||||
const { options, deployOpts } = await getOptions()
|
||||
deployOpts.props.ingressName = 'ingress-base'
|
||||
deployOpts.props.secretName = 'cert---docmirror-cn'
|
||||
deployOpts.context.tencentCertId = 'hNUZJrZf'
|
||||
const plugin = new DeployCertToTencentTKEIngress(options)
|
||||
|
||||
const ret = await plugin.doExecute(deployOpts)
|
||||
console.log('sucess', ret)
|
||||
})
|
||||
})
|
||||
@@ -1,12 +1,12 @@
|
||||
import pkg from 'chai'
|
||||
import { UploadCertToTencent } from '../../src/tencent/upload-to-tencent/index.js'
|
||||
import { UploadCertToTencent } from '../../src/plugins/upload-to-tencent/index.js'
|
||||
import { Certd } from '@certd/certd'
|
||||
import { createOptions } from '../../../../test/options.js'
|
||||
import { createOptions } from '../../../../../test/options.js'
|
||||
const { expect } = pkg
|
||||
describe('PluginUploadToTencent', function () {
|
||||
it('#execute', async function () {
|
||||
const options = createOptions()
|
||||
const plugin = new UploadCertToTencent()
|
||||
const plugin = new UploadCertToTencent(options)
|
||||
options.args = { test: false }
|
||||
options.cert.email = 'xiaojunnuo@qq.com'
|
||||
options.cert.domains = ['*.docmirror.cn']
|
||||
1858
packages/plugins/plugin-tencent/yarn-error.log
Normal file
1858
packages/plugins/plugin-tencent/yarn-error.log
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user