mirror of
https://github.com/certd/certd.git
synced 2026-04-08 09:00:56 +08:00
Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5fbd774266 | ||
|
|
bdec010d2e | ||
|
|
05a00b7b78 | ||
|
|
eaf23c3034 | ||
|
|
276a8b35e5 | ||
|
|
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 |
10
.gitignore
vendored
10
.gitignore
vendored
@@ -8,9 +8,13 @@ node_modules/
|
||||
|
||||
/*.log
|
||||
|
||||
/ui/*/.idea
|
||||
/packages/ui/*/.idea
|
||||
|
||||
/ui/*/node_modules
|
||||
/packages/ui/*/node_modules
|
||||
|
||||
/packages/*/node_modules
|
||||
/ui/certd-server/tmp/
|
||||
/packages/ui/certd-server/tmp/
|
||||
/packages/ui/certd-ui/dist/
|
||||
/other
|
||||
/dev-sidecar-test
|
||||
/packages/core/certd/yarn.lock
|
||||
|
||||
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,7 +1,6 @@
|
||||
{
|
||||
"packages": [
|
||||
"packages/*",
|
||||
"ui/*"
|
||||
"packages/*/*"
|
||||
],
|
||||
"version": "0.1.12"
|
||||
"version": "0.2.0"
|
||||
}
|
||||
|
||||
16295
package-lock.json
generated
16295
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,10 @@
|
||||
"devDependencies": {
|
||||
"lerna": "^3.18.4"
|
||||
},
|
||||
"scripts": {},
|
||||
"scripts": {
|
||||
"start": "lerna bootstrap --hoist",
|
||||
"i-all": "lerna link && lerna exec npm install "
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lodash-es": "^4.17.20"
|
||||
|
||||
1599
packages/access-providers/package-lock.json
generated
1599
packages/access-providers/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"name": "@certd/access-providers",
|
||||
"version": "0.1.12",
|
||||
"description": "",
|
||||
"main": "./src/index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"type": "module",
|
||||
"author": "Greper",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@certd/api": "^0.1.12",
|
||||
"lodash-es": "^4.17.20"
|
||||
},
|
||||
"devDependencies": {
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import _ from 'lodash-es'
|
||||
import { AliyunAccessProvider } from './providers/aliyun.js'
|
||||
import { DnspodAccessProvider } from './providers/dnspod.js'
|
||||
import { TencentAccessProvider } from './providers/tencent.js'
|
||||
import { accessProviderRegistry } from '@certd/api'
|
||||
|
||||
export const DefaultAccessProviders = {
|
||||
AliyunAccessProvider,
|
||||
DnspodAccessProvider,
|
||||
TencentAccessProvider,
|
||||
}
|
||||
export default {
|
||||
install () {
|
||||
_.forEach(DefaultAccessProviders, item => {
|
||||
accessProviderRegistry.install(item)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
|
||||
export class Registry {
|
||||
constructor () {
|
||||
this.collection = {}
|
||||
}
|
||||
|
||||
install (target) {
|
||||
if (target == null) {
|
||||
return
|
||||
}
|
||||
if (this.collection == null) {
|
||||
this.collection = {}
|
||||
}
|
||||
const defineName = (target.define && target.define().name) || target.name
|
||||
this.register(defineName, target)
|
||||
}
|
||||
|
||||
register (key, value) {
|
||||
if (!key || value == null) {
|
||||
return
|
||||
}
|
||||
this.collection[key] = value
|
||||
}
|
||||
|
||||
get (name) {
|
||||
if (name) {
|
||||
return this.collection[name]
|
||||
}
|
||||
|
||||
throw new Error(`${name} not found`)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/api",
|
||||
"version": "0.1.12",
|
||||
"version": "0.2.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "@certd/api",
|
||||
"version": "0.1.12",
|
||||
"version": "0.2.0",
|
||||
"description": "",
|
||||
"main": "./src/index.js",
|
||||
"main": "src/index.js",
|
||||
"type": "module",
|
||||
"author": "Greper",
|
||||
"license": "MIT",
|
||||
@@ -22,5 +22,5 @@
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"mocha": "^8.2.1"
|
||||
},
|
||||
"gitHead": "2942d39dfe64d60ce7dc0e0b2c0887866ca67f18"
|
||||
"gitHead": "4a421d5b142d453203c68ce6d1036e168ea2455b"
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
import _ from 'lodash-es'
|
||||
import logger from '../utils/util.log.js'
|
||||
import commonUtil from '../utils/util.common.js'
|
||||
export class AbstractDnsProvider {
|
||||
constructor ({ accessProviders }) {
|
||||
this.logger = logger
|
||||
this.accessProviders = accessProviders
|
||||
this.accessProviders = commonUtil.arrayToMap(accessProviders)
|
||||
}
|
||||
|
||||
async createRecord ({ fullRecord, type, value }) {
|
||||
@@ -34,9 +35,13 @@ export class AbstractDnsProvider {
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Registry } from '../registry/registry.js'
|
||||
export { AbstractDnsProvider } from './abstract-dns-provider.js'
|
||||
|
||||
export const dnsProviderRegistry = new Registry()
|
||||
@@ -3,3 +3,4 @@ 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,11 +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) {
|
||||
@@ -61,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) {
|
||||
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
|
||||
}
|
||||
}
|
||||
7
packages/core/certd/.gitignore
vendored
Normal file
7
packages/core/certd/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
.vscode/
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
yarn.lock
|
||||
package-lock.json
|
||||
/.idea/
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/certd",
|
||||
"version": "0.1.12",
|
||||
"version": "0.2.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -43,6 +43,18 @@
|
||||
"node-forge": "^0.10.0"
|
||||
}
|
||||
},
|
||||
"@certd/api": {
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/@certd/api/-/api-0.1.13.tgz",
|
||||
"integrity": "sha512-klb4B5D+lu1SAtopCyU4sfe12Q9U4k5x+GTaSLLk1Dr3cX0Mpq7/fySQIW5yPH2ZJGQQAbKm/vciBnUGYWFy/A==",
|
||||
"requires": {
|
||||
"axios": "^0.21.1",
|
||||
"dayjs": "^1.9.7",
|
||||
"lodash-es": "^4.17.20",
|
||||
"log4js": "^6.3.0",
|
||||
"qs": "^6.9.4"
|
||||
}
|
||||
},
|
||||
"@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",
|
||||
@@ -1790,6 +1802,11 @@
|
||||
"integrity": "sha1-tYsBCsQMIsVldhbI0sLALHv0eew=",
|
||||
"dev": true
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.9.6",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz",
|
||||
"integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ=="
|
||||
},
|
||||
"randombytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npm.taobao.org/randombytes/download/randombytes-2.1.0.tgz",
|
||||
@@ -1,18 +1,17 @@
|
||||
{
|
||||
"name": "@certd/certd",
|
||||
"version": "0.1.12",
|
||||
"description": "",
|
||||
"main": "./src/index.js",
|
||||
"version": "0.2.0",
|
||||
"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.12",
|
||||
"@certd/dns-providers": "^0.1.12",
|
||||
"@certd/acme-client": "^0.2.0",
|
||||
"@certd/api": "^0.2.0",
|
||||
"dayjs": "^1.9.7",
|
||||
"lodash-es": "^4.17.20",
|
||||
"node-forge": "^0.10.0"
|
||||
@@ -26,5 +25,5 @@
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"mocha": "^8.2.1"
|
||||
},
|
||||
"gitHead": "2942d39dfe64d60ce7dc0e0b2c0887866ca67f18"
|
||||
"gitHead": "4a421d5b142d453203c68ce6d1036e168ea2455b"
|
||||
}
|
||||
@@ -4,8 +4,8 @@ import { FileStore } from './store/file-store.js'
|
||||
import { CertStore } from './store/cert-store.js'
|
||||
import dayjs from 'dayjs'
|
||||
import forge from 'node-forge'
|
||||
const logger = util.logger
|
||||
|
||||
const logger = util.logger
|
||||
export class Certd {
|
||||
constructor (options) {
|
||||
this.options = options
|
||||
@@ -122,11 +122,10 @@ export class Certd {
|
||||
|
||||
createProviderByType (props, accessProviders) {
|
||||
const { type } = props
|
||||
try {
|
||||
const Provider = dnsProviderRegistry.get(type)
|
||||
return new Provider({ accessProviders, props })
|
||||
} catch (e) {
|
||||
throw new Error('暂不支持此dnsProvider,请先注册该provider:' + type, e)
|
||||
const Provider = dnsProviderRegistry.get(type)
|
||||
if (Provider == null) {
|
||||
throw new Error('暂不支持此dnsProvider,请先注册该provider:' + type)
|
||||
}
|
||||
return new Provider({ accessProviders, props })
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,8 @@ export class CertStore {
|
||||
this.domains = domains
|
||||
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.domainDir = this.safetyDomain + '-' + md5(this.getDomainStr(this.domains))
|
||||
// this.domainDir = this.safetyDomain
|
||||
this.certsRootPath = this.store.buildKey(this.email, 'certs')
|
||||
|
||||
this.currentMarkPath = this.store.buildKey(this.certsRootPath, this.domainDir, 'current.json')
|
||||
@@ -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
|
||||
@@ -68,7 +68,7 @@ describe('Certd', function () {
|
||||
const certd = new Certd(options)
|
||||
const currentRootPath = certd.certStore.currentMarkPath
|
||||
console.log('rootDir', currentRootPath)
|
||||
expect(currentRootPath).match(/xiaojunnuo@qq.com\\certs\\_.docmirror.club\w*\\current.json/)
|
||||
expect(currentRootPath).match(/xiaojunnuo@qq.com\\certs\\_.docmirror.club-\w*\\current.json/)
|
||||
})
|
||||
it('#writeAndReadCert', async function () {
|
||||
const options = createOptions()
|
||||
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,23 +1,24 @@
|
||||
{
|
||||
"name": "@certd/executor",
|
||||
"version": "0.1.12",
|
||||
"version": "0.2.0",
|
||||
"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.12",
|
||||
"@certd/certd": "^0.1.12",
|
||||
"@certd/dns-providers": "^0.1.12",
|
||||
"@certd/plugins": "^0.1.12",
|
||||
"@certd/api": "^0.2.0",
|
||||
"@certd/certd": "^0.2.0",
|
||||
"dayjs": "^1.9.7",
|
||||
"lodash-es": "^4.17.20"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/plugin-aliyun": "^0.2.0",
|
||||
"@certd/plugin-host": "^0.2.0",
|
||||
"@certd/plugin-tencent": "^0.2.0",
|
||||
"@rollup/plugin-commonjs": "^17.0.0",
|
||||
"@rollup/plugin-json": "^4.1.0",
|
||||
"@rollup/plugin-node-resolve": "^11.0.1",
|
||||
@@ -34,5 +35,5 @@
|
||||
"author": "Greper",
|
||||
"license": "MIT",
|
||||
"sideEffects": false,
|
||||
"gitHead": "2942d39dfe64d60ce7dc0e0b2c0887866ca67f18"
|
||||
"gitHead": "4a421d5b142d453203c68ce6d1036e168ea2455b"
|
||||
}
|
||||
@@ -3,15 +3,8 @@ import { pluginRegistry, util } from '@certd/api'
|
||||
import _ from 'lodash-es'
|
||||
import dayjs from 'dayjs'
|
||||
import { Trace } from './trace.js'
|
||||
import DefaultPlugins from '@certd/plugins'
|
||||
import DefaultDnsProviders from '@certd/dns-providers'
|
||||
|
||||
const logger = util.logger
|
||||
|
||||
// 安装默认插件和授权提供者
|
||||
DefaultPlugins.install()
|
||||
DefaultDnsProviders.install()
|
||||
|
||||
function createDefaultOptions () {
|
||||
return {
|
||||
args: {
|
||||
@@ -30,14 +23,28 @@ export class Executor {
|
||||
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('任务开始')
|
||||
@@ -51,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 }
|
||||
@@ -78,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) {
|
||||
@@ -111,6 +122,7 @@ export class Executor {
|
||||
logger.info('此流程已被禁用,跳过')
|
||||
logger.info('')
|
||||
deployTrace.set({ value: { current: 'skip', status: 'disabled', remark: '流程禁用' } })
|
||||
deployTrace.set({ tasks: null })
|
||||
continue
|
||||
}
|
||||
try {
|
||||
@@ -124,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 } })
|
||||
@@ -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,28 +0,0 @@
|
||||
{
|
||||
"name": "@certd/dns-providers",
|
||||
"version": "0.1.12",
|
||||
"description": "",
|
||||
"main": "./src/index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"type": "module",
|
||||
"author": "Greper",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@alicloud/pop-core": "^1.7.10",
|
||||
"@certd/api": "^0.1.12",
|
||||
"lodash-es": "^4.17.20",
|
||||
"tencentcloud-sdk-nodejs": "^4.0.44"
|
||||
},
|
||||
"devDependencies": {
|
||||
"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"
|
||||
},
|
||||
"gitHead": "2942d39dfe64d60ce7dc0e0b2c0887866ca67f18"
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import _ from 'lodash-es'
|
||||
import { AliyunDnsProvider } from './providers/aliyun.js'
|
||||
import { DnspodDnsProvider } from './providers/dnspod.js'
|
||||
import { dnsProviderRegistry } from '@certd/api'
|
||||
|
||||
export const DefaultDnsProviders = {
|
||||
AliyunDnsProvider,
|
||||
DnspodDnsProvider
|
||||
}
|
||||
export default {
|
||||
install () {
|
||||
_.forEach(DefaultDnsProviders, item => {
|
||||
dnsProviderRegistry.install(item)
|
||||
})
|
||||
}
|
||||
}
|
||||
2557
packages/executor/package-lock.json
generated
2557
packages/executor/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
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.2.0",
|
||||
"description": "",
|
||||
"main": "src/index.js",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@alicloud/pop-core": "^1.7.10",
|
||||
"@certd/api": "^0.2.0",
|
||||
"dayjs": "^1.9.7",
|
||||
"lodash-es": "^4.17.20"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/certd": "^0.2.0",
|
||||
"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"
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import _ from 'lodash-es'
|
||||
export class AliyunAccessProvider{
|
||||
export class AliyunAccessProvider {
|
||||
static define () {
|
||||
return {
|
||||
name: 'aliyun',
|
||||
@@ -28,7 +27,4 @@ export class AliyunAccessProvider{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor () {
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AbstractAliyunPlugin } from '../../aliyun/abstract-aliyun.js'
|
||||
import { AbstractAliyunPlugin } from '../abstract-aliyun.js'
|
||||
import Core from '@alicloud/pop-core'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
@@ -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/providers/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)
|
||||
})
|
||||
})
|
||||
@@ -3,10 +3,6 @@
|
||||
"env": {
|
||||
"mocha": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"sourceType": "module",
|
||||
"ecmaVersion": 2020
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.test.js", "*.spec.js"],
|
||||
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.2.0",
|
||||
"description": "",
|
||||
"main": "src/index.js",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@certd/api": "^0.2.0",
|
||||
"dayjs": "^1.9.7",
|
||||
"lodash-es": "^4.17.20",
|
||||
"ssh2": "^0.8.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/certd": "^0.2.0",
|
||||
"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,18 +12,21 @@ export class HostShellExecute extends AbstractHostPlugin {
|
||||
name: 'hostShellExecute',
|
||||
label: '执行远程主机脚本命令',
|
||||
input: {
|
||||
script: {
|
||||
label: 'shell脚本命令'
|
||||
},
|
||||
accessProvider: {
|
||||
label: '主机登录配置',
|
||||
type: [String, Object],
|
||||
desc: '登录',
|
||||
component: {
|
||||
name: 'access-provider-selector',
|
||||
filter: 'host'
|
||||
filter: 'ssh'
|
||||
},
|
||||
required: true
|
||||
},
|
||||
script: {
|
||||
label: 'shell脚本命令',
|
||||
component: {
|
||||
name: 'a-textarea'
|
||||
}
|
||||
}
|
||||
},
|
||||
output: {
|
||||
@@ -36,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,10 +13,10 @@ export class UploadCertToHost extends AbstractHostPlugin {
|
||||
label: '上传证书到主机',
|
||||
input: {
|
||||
crtPath: {
|
||||
label: '证书路径'
|
||||
label: '证书保存路径'
|
||||
},
|
||||
keyPath: {
|
||||
label: '私钥路径'
|
||||
label: '私钥保存路径'
|
||||
},
|
||||
accessProvider: {
|
||||
label: '主机登录配置',
|
||||
@@ -24,9 +24,12 @@ export class UploadCertToHost extends AbstractHostPlugin {
|
||||
desc: 'access授权',
|
||||
component: {
|
||||
name: 'access-provider-selector',
|
||||
filter: 'host'
|
||||
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
@@ -3,10 +3,6 @@
|
||||
"env": {
|
||||
"mocha": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"sourceType": "module",
|
||||
"ecmaVersion": 2020
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.test.js", "*.spec.js"],
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/plugins",
|
||||
"version": "0.1.12",
|
||||
"name": "@certd/plugin-tencent",
|
||||
"version": "0.2.0",
|
||||
"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,6 +132,75 @@
|
||||
"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.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",
|
||||
"lodash-es": "^4.17.20",
|
||||
"log4js": "^6.3.0",
|
||||
"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",
|
||||
@@ -476,6 +546,14 @@
|
||||
"resolved": "https://registry.npm.taobao.org/aws4/download/aws4-1.11.0.tgz?cache=0&sync_timestamp=1604101166484&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Faws4%2Fdownload%2Faws4-1.11.0.tgz",
|
||||
"integrity": "sha1-1h9G2DslGSUOJ4Ta9bCUeai0HFk="
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.21.1",
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"babel-eslint": {
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npm.taobao.org/babel-eslint/download/babel-eslint-10.1.0.tgz?cache=0&sync_timestamp=1599054223324&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbabel-eslint%2Fdownload%2Fbabel-eslint-10.1.0.tgz",
|
||||
@@ -489,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",
|
||||
@@ -510,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",
|
||||
@@ -518,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",
|
||||
@@ -762,6 +853,11 @@
|
||||
"assert-plus": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"date-format": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npm.taobao.org/date-format/download/date-format-3.0.0.tgz",
|
||||
"integrity": "sha1-64eANlx9KxURB4+0keZHl4DzrZU="
|
||||
},
|
||||
"dayjs": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npm.taobao.org/dayjs/download/dayjs-1.10.2.tgz?cache=0&sync_timestamp=1609889274763&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdayjs%2Fdownload%2Fdayjs-1.10.2.tgz",
|
||||
@@ -1406,6 +1502,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"flatted": {
|
||||
"version": "2.0.2",
|
||||
"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.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",
|
||||
"resolved": "https://registry.npm.taobao.org/forever-agent/download/forever-agent-0.6.1.tgz",
|
||||
@@ -1421,6 +1527,16 @@
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"fs-extra": {
|
||||
"version": "8.1.0",
|
||||
"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",
|
||||
"universalify": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npm.taobao.org/fs.realpath/download/fs.realpath-1.0.0.tgz",
|
||||
@@ -1537,8 +1653,7 @@
|
||||
"graceful-fs": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npm.taobao.org/graceful-fs/download/graceful-fs-4.2.4.tgz",
|
||||
"integrity": "sha1-Ila94U02MpWMRl68ltxGfKB6Kfs=",
|
||||
"dev": true
|
||||
"integrity": "sha1-Ila94U02MpWMRl68ltxGfKB6Kfs="
|
||||
},
|
||||
"growl": {
|
||||
"version": "1.10.5",
|
||||
@@ -1618,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"
|
||||
@@ -1627,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"
|
||||
}
|
||||
@@ -1634,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
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1879,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"
|
||||
}
|
||||
@@ -1923,6 +2042,14 @@
|
||||
"minimist": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"jsonfile": {
|
||||
"version": "4.0.0",
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"jsonpath-plus": {
|
||||
"version": "0.19.0",
|
||||
"resolved": "https://registry.npm.taobao.org/jsonpath-plus/download/jsonpath-plus-0.19.0.tgz",
|
||||
@@ -1959,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",
|
||||
@@ -2083,6 +2211,33 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"log4js": {
|
||||
"version": "6.3.0",
|
||||
"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",
|
||||
"flatted": "^2.0.1",
|
||||
"rfdc": "^1.1.4",
|
||||
"streamroller": "^2.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"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=",
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"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="
|
||||
}
|
||||
}
|
||||
},
|
||||
"loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npm.taobao.org/loose-envify/download/loose-envify-1.4.0.tgz",
|
||||
@@ -2287,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",
|
||||
@@ -2795,6 +2956,11 @@
|
||||
"lowercase-keys": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"rfdc": {
|
||||
"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",
|
||||
"resolved": "https://registry.npm.taobao.org/rimraf/download/rimraf-3.0.2.tgz?cache=0&sync_timestamp=1599054104695&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frimraf%2Fdownload%2Frimraf-3.0.2.tgz",
|
||||
@@ -2817,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",
|
||||
@@ -2957,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",
|
||||
@@ -2991,10 +3140,35 @@
|
||||
"tweetnacl": "~0.14.0"
|
||||
}
|
||||
},
|
||||
"streamsearch": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npm.taobao.org/streamsearch/download/streamsearch-0.1.2.tgz",
|
||||
"integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
|
||||
"streamroller": {
|
||||
"version": "2.2.4",
|
||||
"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",
|
||||
"fs-extra": "^8.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"date-format": {
|
||||
"version": "2.1.0",
|
||||
"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.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.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="
|
||||
}
|
||||
}
|
||||
},
|
||||
"string-width": {
|
||||
"version": "4.2.0",
|
||||
@@ -3215,6 +3389,11 @@
|
||||
"resolved": "https://registry.npm.taobao.org/underscore/download/underscore-1.12.0.tgz?cache=0&sync_timestamp=1606179462980&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Funderscore%2Fdownload%2Funderscore-1.12.0.tgz",
|
||||
"integrity": "sha1-SBSUBVH8gFh873hA0euw8WRTvpc="
|
||||
},
|
||||
"universalify": {
|
||||
"version": "0.1.2",
|
||||
"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",
|
||||
"resolved": "https://registry.npm.taobao.org/uri-js/download/uri-js-4.4.0.tgz",
|
||||
@@ -3401,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"
|
||||
@@ -3409,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.12",
|
||||
"name": "@certd/plugin-tencent",
|
||||
"version": "0.2.0",
|
||||
"description": "",
|
||||
"main": "./src/index.js",
|
||||
"main": "src/index.js",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@alicloud/pop-core": "^1.7.10",
|
||||
"@certd/api": "^0.1.12",
|
||||
"@certd/api": "^0.2.0",
|
||||
"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.2.0",
|
||||
"chai": "^4.2.0",
|
||||
"eslint": "^7.15.0",
|
||||
"eslint-config-standard": "^16.0.2",
|
||||
@@ -24,5 +23,5 @@
|
||||
},
|
||||
"author": "Greper",
|
||||
"license": "MIT",
|
||||
"gitHead": "2942d39dfe64d60ce7dc0e0b2c0887866ca67f18"
|
||||
"gitHead": "4a421d5b142d453203c68ce6d1036e168ea2455b"
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
export class DnspodAccessProvider {
|
||||
export class DnspodAccessProvider {
|
||||
static define () {
|
||||
return {
|
||||
name: 'dnspod',
|
||||
@@ -23,8 +23,4 @@ export class DnspodAccessProvider {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor () {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
export class TencentAccessProvider {
|
||||
export class TencentAccessProvider {
|
||||
static define () {
|
||||
return {
|
||||
name: 'tencent',
|
||||
@@ -6,7 +6,7 @@ export class TencentAccessProvider {
|
||||
input: {
|
||||
secretId: {
|
||||
type: String,
|
||||
label:'secretId',
|
||||
label: 'secretId',
|
||||
component: {
|
||||
placeholder: 'secretId',
|
||||
rules: [{ required: true, message: '该项必填' }]
|
||||
@@ -23,8 +23,4 @@ export class TencentAccessProvider {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor () {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -29,7 +29,7 @@ export class DnspodDnsProvider extends AbstractDnsProvider {
|
||||
this.loginToken = accessProvider.id + ',' + accessProvider.token
|
||||
}
|
||||
|
||||
async doRequest (options) {
|
||||
async doRequest (options, successCodes = []) {
|
||||
const config = {
|
||||
method: 'post',
|
||||
formData: {
|
||||
@@ -43,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
|
||||
}
|
||||
@@ -73,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'
|
||||
|
||||
@@ -44,7 +44,10 @@ export class DeployCertToTencentCDN extends AbstractTencentPlugin {
|
||||
}
|
||||
},
|
||||
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 {
|
||||
/**
|
||||
@@ -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 {
|
||||
@@ -41,6 +41,11 @@ export class DeployCertToTencentTKEIngress extends AbstractTencentPlugin {
|
||||
label: 'ingress名称',
|
||||
desc: '支持多个(传入数组)'
|
||||
},
|
||||
ingressClass: {
|
||||
type: String,
|
||||
label: 'ingress类型',
|
||||
desc: '可选 qcloud / nginx'
|
||||
},
|
||||
clusterIp: {
|
||||
type: String,
|
||||
label: '集群内网ip',
|
||||
@@ -86,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
|
||||
@@ -121,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('请先将【上传证书到腾讯云】作为前置任务')
|
||||
@@ -151,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'
|
||||
|
||||
@@ -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/providers/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)
|
||||
})
|
||||
})
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user