mirror of
https://github.com/certd/certd.git
synced 2026-04-05 07:20:56 +08:00
Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d4385ad8a5 | ||
|
|
da07ce419f | ||
|
|
714e0206c4 | ||
|
|
79f7ec4672 | ||
|
|
0f5c69040b | ||
|
|
c9d1c45d97 | ||
|
|
ea8fdb120c | ||
|
|
f6fa830ffe | ||
|
|
992e50c014 | ||
|
|
bd705d91ba | ||
|
|
2656394195 | ||
|
|
c8df9e698c | ||
|
|
19b78a1d2f | ||
|
|
8039e8baf8 | ||
|
|
9c5142c73c | ||
|
|
8e3dcdde17 | ||
|
|
34023adafb | ||
|
|
79914e8d08 | ||
|
|
454fbda581 | ||
|
|
2c32703e6b | ||
|
|
b561535626 | ||
|
|
1fc684d995 | ||
|
|
7595d9fdfd | ||
|
|
3bf7732a21 | ||
|
|
71b5aaf8ab | ||
|
|
e1e5347476 | ||
|
|
cdcdb6a2d9 | ||
|
|
ec79104ad2 | ||
|
|
ff083ce684 | ||
|
|
0f051e322e | ||
|
|
657a2ae032 | ||
|
|
0db3570026 | ||
|
|
0ae39f160a | ||
|
|
b45977c29a | ||
|
|
b7f5740c57 | ||
|
|
21e23369d3 | ||
|
|
fca598991a | ||
|
|
aa5b909486 | ||
|
|
0a888cf51a |
25
CHANGELOG.md
25
CHANGELOG.md
@@ -3,6 +3,31 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.28.4](https://github.com/certd/certd/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复证书成功通知发送失败的bug ([0f5c690](https://github.com/certd/certd/commit/0f5c69040ba77340c909813220a26bc7ddada3ea))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 群晖支持6.x ([79f7ec4](https://github.com/certd/certd/commit/79f7ec4672f4fd5744cc45e4a6f104da943f4026))
|
||||
|
||||
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复没有配置eab时,报order无法读取的问题 ([657a2ae](https://github.com/certd/certd/commit/657a2ae032e6f61ac27fbdd26c7bf169c041219e))
|
||||
* 修复授权被删除后,无法清空的bug ([b45977c](https://github.com/certd/certd/commit/b45977c29a29084c11e496bec3415eaaebafdd74))
|
||||
* mysql下access.setting字段改成text ([b7f5740](https://github.com/certd/certd/commit/b7f5740c57743914f754f3b4fdd94b59a2e8338c))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 点击版本红点按钮,跳转到升级帮助页面 ([454fbda](https://github.com/certd/certd/commit/454fbda581bbe22abca5b91e5086ea9d9d58a020))
|
||||
* 通知标题优化 ([ff083ce](https://github.com/certd/certd/commit/ff083ce6848a8bee3c8248e4b881086ae1517c28))
|
||||
* 支持腾讯虚拟机开关机([@wujingke](https://github.com/wujingke)) ([8039e8b](https://github.com/certd/certd/commit/8039e8baf83c82d03f1a6198cf61c372026b962b))
|
||||
* 支持aws cloudfront ([0ae39f1](https://github.com/certd/certd/commit/0ae39f160a7c6b6696b3bf513d68aa28905810ad))
|
||||
|
||||
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -9,11 +9,11 @@ Certd 是一个免费全自动申请和自动部署更新SSL证书的管理系
|
||||
本项目不仅支持证书申请过程自动化,还可以自动化部署更新证书,让你的证书永不过期。
|
||||
|
||||
* 全自动申请证书(支持所有注册商注册的域名)
|
||||
* 全自动部署更新证书(目前支持部署到主机、部署到阿里云、腾讯云等,目前已支持30+部署插件)
|
||||
* 全自动部署更新证书(目前支持部署到主机、阿里云、腾讯云等,目前已支持40+部署插件)
|
||||
* 支持通配符域名/泛域名,支持多个域名打到一个证书上,支持pem、pfx、der、jks等多种证书格式
|
||||
* 邮件通知
|
||||
* 邮件通知、webhook通知
|
||||
* 私有化部署,数据保存本地,镜像由Github Actions构建,过程公开透明
|
||||
* 支持sqlite,postgresql数据库
|
||||
* 支持SQLite,PostgreSQL、MySQL数据库
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
01:55
|
||||
12:07
|
||||
|
||||
@@ -76,8 +76,8 @@ export default defineConfig({
|
||||
{ text: "源码部署", link: "/guide/install/source/" }
|
||||
]
|
||||
},
|
||||
{ text: "演示教程", link: "/guide/tutorial.md" }
|
||||
|
||||
{ text: "演示教程", link: "/guide/tutorial.md" },
|
||||
{ text: "版本升级", link: "/guide/install/upgrade.md" }
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -3,6 +3,33 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复没有配置eab时,报order无法读取的问题 ([657a2ae](https://github.com/certd/certd/commit/657a2ae032e6f61ac27fbdd26c7bf169c041219e))
|
||||
* 修复授权被删除后,无法清空的bug ([b45977c](https://github.com/certd/certd/commit/b45977c29a29084c11e496bec3415eaaebafdd74))
|
||||
* mysql下access.setting字段改成text ([b7f5740](https://github.com/certd/certd/commit/b7f5740c57743914f754f3b4fdd94b59a2e8338c))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 点击版本红点按钮,跳转到升级帮助页面 ([454fbda](https://github.com/certd/certd/commit/454fbda581bbe22abca5b91e5086ea9d9d58a020))
|
||||
* 通知标题优化 ([ff083ce](https://github.com/certd/certd/commit/ff083ce6848a8bee3c8248e4b881086ae1517c28))
|
||||
* 支持腾讯虚拟机开关机([@wujingke](https://github.com/wujingke)) ([8039e8b](https://github.com/certd/certd/commit/8039e8baf83c82d03f1a6198cf61c372026b962b))
|
||||
* 支持aws cloudfront ([0ae39f1](https://github.com/certd/certd/commit/0ae39f160a7c6b6696b3bf513d68aa28905810ad))
|
||||
|
||||
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复创建流水线通知设置无效的bug ([498cf34](https://github.com/certd/certd/commit/498cf34999fddfa24ce088e2e678469fa669abb8))
|
||||
* 修复流水线分组可以被所有人看见的bug ([a0e838d](https://github.com/certd/certd/commit/a0e838d1eec918e5dc92fe95dc72ac14facb930e))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 优化数据表索引 ([228fdf0](https://github.com/certd/certd/commit/228fdf0a0d28013f5dd156a97bbde80537e8e97e))
|
||||
* 支持mysql ([7cde1fd](https://github.com/certd/certd/commit/7cde1fdc4a9ed851900d231a5460c8dbfbcd148e))
|
||||
|
||||
## [1.28.1](https://github.com/certd/certd/compare/v1.28.0...v1.28.1) (2024-12-08)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -106,4 +106,4 @@ throw new Error("错误信息")
|
||||
## 五、贡献插件送激活码
|
||||
|
||||
- PR要求,插件功能完整,代码规范
|
||||
- PR通过后,联系我们,送您一个专业版激活码
|
||||
- PR通过后,联系我们,送您一个半年期专业版激活码
|
||||
@@ -14,7 +14,7 @@ Certd 是一款开源、免费、全自动申请和部署更新SSL证书的工
|
||||
* 支持通配符域名/泛域名,支持多个域名打到一个证书上
|
||||
* 邮件通知
|
||||
* 私有化部署,保障数据安全
|
||||
* 支持sqlite,postgresql数据库
|
||||
* 支持SQLite、Postgresql、MySQL数据库
|
||||
|
||||
|
||||
## 二、一些说明
|
||||
|
||||
BIN
docs/guide/install/1panel/images/upgrade-1.png
Normal file
BIN
docs/guide/install/1panel/images/upgrade-1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
BIN
docs/guide/install/1panel/images/upgrade-2.png
Normal file
BIN
docs/guide/install/1panel/images/upgrade-2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
@@ -31,15 +31,12 @@ admin/123456
|
||||
|
||||
## 三、升级
|
||||
|
||||
1. 找到容器,点击编辑
|
||||

|
||||
1. 找到容器,点击更多->升级
|
||||

|
||||
|
||||
2. 将latest修改为最新版本号
|
||||

|
||||
2. 选择强制拉取镜像,点击确认即可
|
||||

|
||||
|
||||

|
||||
|
||||
3. 点击确定,重启容器
|
||||
|
||||
## 四、数据备份
|
||||
|
||||
|
||||
@@ -38,28 +38,12 @@ admin/123456
|
||||
登录后请及时修改密码
|
||||
|
||||
## 三、如何升级
|
||||
宝塔升级certd非常简单
|
||||
|
||||
### 1. 应用商店安装,直接更新镜像即可
|
||||
`docker`->`容器编排`->`左侧选择Certd-xxxx`->`更新镜像`
|
||||
`docker`->`容器编排`->`左侧选择Certd`->`更新镜像`
|
||||

|
||||
|
||||
|
||||
### 2. latest更新方式
|
||||
在主机上拉取最新镜像,然后面板上重启容器
|
||||
```shell
|
||||
docker pull registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
|
||||
```
|
||||
|
||||
### 3. 固定版本号方式
|
||||
|
||||
修改容器编排模版中的镜像版本号,然后面板上重启容器
|
||||
```shell
|
||||
services:
|
||||
certd:
|
||||
# 镜像 # 修改最新版本号 ---- ↓↓↓↓↓
|
||||
image: registry.cn-shenzhen.aliyuncs.com/handsfree/certd:v1.xx.x
|
||||
```
|
||||
|
||||
## 四、数据备份
|
||||
|
||||
### 4.1 应用商店部署方式
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
```shell
|
||||
# 克隆代码
|
||||
git clone https://github.com/certd/certd
|
||||
# git checkout v1.x.x # 1.x.x换成最新版本号,当v2主干分支代码无法正常启动时,可以尝试此命令
|
||||
# git checkout v1.x.x # 当v2主干分支代码无法正常启动时,可以尝试此命令,1.x.x换成最新版本号
|
||||
cd certd
|
||||
# 启动服务
|
||||
./start.sh
|
||||
@@ -29,9 +29,15 @@ https://your_server_ip:7002
|
||||
## 二、升级
|
||||
|
||||
```shell
|
||||
# 更新代码并启动
|
||||
|
||||
cd certd
|
||||
# 确保数据安全,备份一下数据
|
||||
cp -rf ./packages/ui/certd-server/data ../certd-data-backup
|
||||
|
||||
git pull
|
||||
# 如果提示pull失败,可以尝试强制更新
|
||||
# git checkout v2 -f && git pull
|
||||
|
||||
# 先停止旧的服务,7001是certd的默认端口
|
||||
kill -9 $(lsof -t -i:7001)
|
||||
# 重新编译启动
|
||||
|
||||
12
docs/guide/install/upgrade.md
Normal file
12
docs/guide/install/upgrade.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# 版本升级
|
||||
|
||||
## 升级方法
|
||||
根据不同部署方式查看升级方法
|
||||
|
||||
1. [Docker方式部署升级](./docker/#二、升级)
|
||||
2. [宝塔面板方式部署升级](./baota/#三、如何升级)
|
||||
3. [1Panel面板方式部署升级](./1panel/#三、升级)
|
||||
4. [源码方式部署](./source/#二、升级)
|
||||
|
||||
## 升级日志
|
||||
[CHANGELOG](../changelogs/CHANGELOG.md)
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 53 KiB |
@@ -3,6 +3,8 @@
|
||||
|
||||
## 一、群晖部署Certd
|
||||
|
||||
以下是群晖`7.x`的部署`certd`步骤
|
||||
|
||||
### 1. 打开Container Manager
|
||||
|
||||

|
||||
@@ -32,6 +34,8 @@
|
||||
|
||||
## 二、更新群晖证书
|
||||
|
||||
证书部署插件支持群晖`6.x`、`7.x`
|
||||
|
||||
## 1. 前提条件
|
||||
* 已经部署了certd
|
||||
* 群晖上已经设置好了证书(证书建议设置好描述,插件需要根据描述查找证书)
|
||||
|
||||
@@ -32,5 +32,5 @@ features:
|
||||
- title: 支持私有化部署
|
||||
details: 保障数据安全
|
||||
- title: 多数据库支持
|
||||
details: 支持sqlite,postgresql数据库
|
||||
details: 支持SQLite、Postgresql、MySQL数据库
|
||||
---
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
}
|
||||
},
|
||||
"npmClient": "pnpm",
|
||||
"version": "1.28.2"
|
||||
"version": "1.28.4"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.28.4](https://github.com/publishlab/node-acme-client/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.28.3](https://github.com/publishlab/node-acme-client/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.28.2](https://github.com/publishlab/node-acme-client/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "Simple and unopinionated ACME client",
|
||||
"private": false,
|
||||
"author": "nmorsman",
|
||||
"version": "1.28.2",
|
||||
"version": "1.28.4",
|
||||
"type": "module",
|
||||
"module": "scr/index.js",
|
||||
"main": "src/index.js",
|
||||
@@ -18,7 +18,7 @@
|
||||
"types"
|
||||
],
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.28.2",
|
||||
"@certd/basic": "^1.28.4",
|
||||
"@peculiar/x509": "^1.11.0",
|
||||
"asn1js": "^3.0.5",
|
||||
"axios": "^1.7.2",
|
||||
@@ -65,5 +65,5 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/publishlab/node-acme-client/issues"
|
||||
},
|
||||
"gitHead": "a6cd532035f55a7ce122ea1229bb65f9d41e7125"
|
||||
"gitHead": "c8df9e698c265568e0e5e8b2f352c0599542d744"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.28.4](https://github.com/certd/certd/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
@@ -1 +1 @@
|
||||
22:42
|
||||
00:08
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/basic",
|
||||
"private": false,
|
||||
"version": "1.28.2",
|
||||
"version": "1.28.4",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -43,5 +43,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "a6cd532035f55a7ce122ea1229bb65f9d41e7125"
|
||||
"gitHead": "c8df9e698c265568e0e5e8b2f352c0599542d744"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,19 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.28.4](https://github.com/certd/certd/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复证书成功通知发送失败的bug ([0f5c690](https://github.com/certd/certd/commit/0f5c69040ba77340c909813220a26bc7ddada3ea))
|
||||
|
||||
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 通知标题优化 ([ff083ce](https://github.com/certd/certd/commit/ff083ce6848a8bee3c8248e4b881086ae1517c28))
|
||||
* 支持aws cloudfront ([0ae39f1](https://github.com/certd/certd/commit/0ae39f160a7c6b6696b3bf513d68aa28905810ad))
|
||||
|
||||
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/pipeline",
|
||||
"private": false,
|
||||
"version": "1.28.2",
|
||||
"version": "1.28.4",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -16,8 +16,8 @@
|
||||
"test": "mocha --loader=ts-node/esm"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.28.2",
|
||||
"@certd/plus-core": "^1.28.2",
|
||||
"@certd/basic": "^1.28.4",
|
||||
"@certd/plus-core": "^1.28.4",
|
||||
"dayjs": "^1.11.7",
|
||||
"lodash-es": "^4.17.21",
|
||||
"reflect-metadata": "^0.1.13"
|
||||
@@ -43,5 +43,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "a6cd532035f55a7ce122ea1229bb65f9d41e7125"
|
||||
"gitHead": "c8df9e698c265568e0e5e8b2f352c0599542d744"
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ import { Decorator } from "../decorator/index.js";
|
||||
import { ICnameProxyService, IEmailService, IPluginConfigService, IUrlService } from "../service/index.js";
|
||||
import { FileStore } from "./file-store.js";
|
||||
import { cloneDeep, forEach, merge } from "lodash-es";
|
||||
import { INotificationService, NotificationBody, NotificationContext, notificationRegistry } from "../notification/index.js";
|
||||
import { INotificationService } from "../notification/index.js";
|
||||
|
||||
export type SysInfo = {
|
||||
//系统标题
|
||||
title?: string;
|
||||
@@ -373,18 +374,17 @@ export class Executor {
|
||||
let subject = "";
|
||||
let content = "";
|
||||
const errorMessage = error?.message;
|
||||
const sysTitle = this.options.sysInfo?.title || "Certd";
|
||||
if (when === "start") {
|
||||
subject = `【${sysTitle}】开始执行,${this.pipeline.title}【${this.pipeline.id}】`;
|
||||
subject = `开始执行,${this.pipeline.title}【${this.pipeline.id}】`;
|
||||
content = `流水线ID:${this.pipeline.id},运行ID:${this.runtime.id}`;
|
||||
} else if (when === "success") {
|
||||
subject = `【${sysTitle}】执行成功,${this.pipeline.title}【${this.pipeline.id}】`;
|
||||
subject = `执行成功,${this.pipeline.title}【${this.pipeline.id}】`;
|
||||
content = `流水线ID:${this.pipeline.id},运行ID:${this.runtime.id}`;
|
||||
} else if (when === "turnToSuccess") {
|
||||
subject = `【${sysTitle}】执行成功(失败转成功),${this.pipeline.title}【${this.pipeline.id}】`;
|
||||
subject = `执行成功(失败转成功),${this.pipeline.title}【${this.pipeline.id}】`;
|
||||
content = `流水线ID:${this.pipeline.id},运行ID:${this.runtime.id}`;
|
||||
} else if (when === "error") {
|
||||
subject = `【${sysTitle}】执行失败,${this.pipeline.title}【${this.pipeline.id}】`;
|
||||
subject = `执行失败,${this.pipeline.title}【${this.pipeline.id}】`;
|
||||
content = `流水线ID:${this.pipeline.id},运行ID:${this.runtime.id}\n错误详情:${error.message}`;
|
||||
} else {
|
||||
return;
|
||||
@@ -407,43 +407,24 @@ export class Executor {
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
//构建notification插件,发送通知
|
||||
let notifyConfig: any;
|
||||
if (notification.notificationId === 0) {
|
||||
notifyConfig = await this.options.notificationService.getDefault();
|
||||
} else {
|
||||
notifyConfig = await this.options.notificationService.getById(notification.notificationId);
|
||||
}
|
||||
if (notifyConfig == null) {
|
||||
throw new Error(`通知配置<id:${notification.notificationId}>不存在`);
|
||||
}
|
||||
|
||||
const notificationPlugin = notificationRegistry.get(notifyConfig.type);
|
||||
const notificationCls: any = notificationPlugin.target;
|
||||
const notificationSender = new notificationCls();
|
||||
const notificationCtx: NotificationContext = {
|
||||
http: utils.http,
|
||||
logger,
|
||||
utils,
|
||||
emailService: this.options.emailService,
|
||||
};
|
||||
//设置参数
|
||||
merge(notificationSender, notifyConfig.setting);
|
||||
notificationSender.setCtx(notificationCtx);
|
||||
await notificationSender.onInstance();
|
||||
const body: NotificationBody = {
|
||||
title: subject,
|
||||
content,
|
||||
userId: this.pipeline.userId,
|
||||
pipeline: this.pipeline,
|
||||
result: this.lastRuntime.pipeline.status,
|
||||
pipelineId: this.pipeline.id,
|
||||
historyId: this.runtime.id,
|
||||
errorMessage,
|
||||
url,
|
||||
};
|
||||
//发送通知
|
||||
await notificationSender.send(body);
|
||||
await this.options.notificationService.send({
|
||||
id: notification.notificationId,
|
||||
useDefault: true,
|
||||
useEmail: false,
|
||||
logger: this.logger,
|
||||
body: {
|
||||
title: subject,
|
||||
content,
|
||||
userId: this.pipeline.userId,
|
||||
pipeline: this.pipeline,
|
||||
result: this.lastRuntime.pipeline.status,
|
||||
pipelineId: this.pipeline.id,
|
||||
historyId: this.runtime.id,
|
||||
errorMessage,
|
||||
url,
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
logger.error("send notification error", e);
|
||||
}
|
||||
|
||||
@@ -48,9 +48,18 @@ export type NotificationInstanceConfig = {
|
||||
};
|
||||
};
|
||||
|
||||
export type NotificationSendReq = {
|
||||
id?: number;
|
||||
useDefault?: boolean;
|
||||
useEmail?: boolean;
|
||||
emailAddress?: string;
|
||||
logger: ILogger;
|
||||
body: NotificationBody;
|
||||
};
|
||||
export interface INotificationService {
|
||||
getById(id: number): Promise<NotificationInstanceConfig>;
|
||||
getDefault(): Promise<NotificationInstanceConfig>;
|
||||
send(req: NotificationSendReq): Promise<void>;
|
||||
}
|
||||
|
||||
export interface INotification {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// src/decorator/memoryCache.decorator.ts
|
||||
import { Decorator } from "../decorator/index.js";
|
||||
import * as _ from "lodash-es";
|
||||
import { merge } from "lodash-es";
|
||||
import { notificationRegistry } from "./registry.js";
|
||||
import { BaseNotification, NotificationBody, NotificationContext, NotificationDefine, NotificationInputDefine, NotificationInstanceConfig } from "./api.js";
|
||||
import { isPlus } from "@certd/plus-core";
|
||||
|
||||
// 提供一个唯一 key
|
||||
export const NOTIFICATION_CLASS_KEY = "pipeline:notification";
|
||||
@@ -47,9 +47,7 @@ export async function newNotification(type: string, input: any, ctx: Notificatio
|
||||
|
||||
// @ts-ignore
|
||||
const plugin = new register.target();
|
||||
for (const key in input) {
|
||||
plugin[key] = input[key];
|
||||
}
|
||||
merge(plugin, input);
|
||||
if (!ctx) {
|
||||
throw new Error("ctx is required");
|
||||
}
|
||||
@@ -61,8 +59,5 @@ export async function newNotification(type: string, input: any, ctx: Notificatio
|
||||
|
||||
export async function sendNotification(opts: { config: NotificationInstanceConfig; ctx: NotificationContext; body: NotificationBody }) {
|
||||
const notification: BaseNotification = await newNotification(opts.config.type, opts.config.setting, opts.ctx);
|
||||
if (notification.define.needPlus && !isPlus()) {
|
||||
opts.body.content = `${opts.body.content}\n\n注意:此通知渠道已调整为专业版功能,后续版本将不再支持发送,请尽快修改或升级为专业版`;
|
||||
}
|
||||
await notification.doSend(opts.body);
|
||||
}
|
||||
|
||||
@@ -21,8 +21,9 @@ export const pluginGroups = {
|
||||
huawei: new PluginGroup("huawei", "华为云", 3),
|
||||
tencent: new PluginGroup("tencent", "腾讯云", 4),
|
||||
qiniu: new PluginGroup("qiniu", "七牛云", 5),
|
||||
host: new PluginGroup("host", "主机", 6),
|
||||
cdn: new PluginGroup("cdn", "CDN", 7),
|
||||
panel: new PluginGroup("panel", "面板", 8),
|
||||
other: new PluginGroup("other", "其他", 9),
|
||||
aws: new PluginGroup("aws", "亚马逊云", 6),
|
||||
host: new PluginGroup("host", "主机", 7),
|
||||
cdn: new PluginGroup("cdn", "CDN", 8),
|
||||
panel: new PluginGroup("panel", "面板", 9),
|
||||
other: new PluginGroup("other", "其他", 10),
|
||||
};
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.28.4](https://github.com/certd/certd/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-huawei",
|
||||
"private": false,
|
||||
"version": "1.28.2",
|
||||
"version": "1.28.4",
|
||||
"main": "./dist/bundle.js",
|
||||
"module": "./dist/bundle.js",
|
||||
"types": "./dist/d/index.d.ts",
|
||||
@@ -21,5 +21,5 @@
|
||||
"prettier": "^2.8.8",
|
||||
"tslib": "^2.8.1"
|
||||
},
|
||||
"gitHead": "a6cd532035f55a7ce122ea1229bb65f9d41e7125"
|
||||
"gitHead": "c8df9e698c265568e0e5e8b2f352c0599542d744"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.28.4](https://github.com/certd/certd/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-iframe",
|
||||
"private": false,
|
||||
"version": "1.28.2",
|
||||
"version": "1.28.4",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -30,5 +30,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "a6cd532035f55a7ce122ea1229bb65f9d41e7125"
|
||||
"gitHead": "c8df9e698c265568e0e5e8b2f352c0599542d744"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.28.4](https://github.com/certd/certd/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-k8s",
|
||||
"private": false,
|
||||
"version": "1.28.2",
|
||||
"version": "1.28.4",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -16,7 +16,7 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.28.2",
|
||||
"@certd/basic": "^1.28.4",
|
||||
"@kubernetes/client-node": "0.21.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -31,5 +31,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "a6cd532035f55a7ce122ea1229bb65f9d41e7125"
|
||||
"gitHead": "c8df9e698c265568e0e5e8b2f352c0599542d744"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.28.4](https://github.com/certd/certd/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/lib-server",
|
||||
"version": "1.28.2",
|
||||
"version": "1.28.4",
|
||||
"description": "midway with flyway, sql upgrade way ",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
@@ -27,10 +27,10 @@
|
||||
],
|
||||
"license": "AGPL",
|
||||
"dependencies": {
|
||||
"@certd/acme-client": "^1.28.2",
|
||||
"@certd/basic": "^1.28.2",
|
||||
"@certd/pipeline": "^1.28.2",
|
||||
"@certd/plus-core": "^1.28.2",
|
||||
"@certd/acme-client": "^1.28.4",
|
||||
"@certd/basic": "^1.28.4",
|
||||
"@certd/pipeline": "^1.28.4",
|
||||
"@certd/plus-core": "^1.28.4",
|
||||
"@midwayjs/cache": "~3.14.0",
|
||||
"@midwayjs/core": "~3.17.1",
|
||||
"@midwayjs/i18n": "~3.17.3",
|
||||
@@ -61,5 +61,5 @@
|
||||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "a6cd532035f55a7ce122ea1229bb65f9d41e7125"
|
||||
"gitHead": "c8df9e698c265568e0e5e8b2f352c0599542d744"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.28.4](https://github.com/certd/certd/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/midway-flyway-js",
|
||||
"version": "1.28.2",
|
||||
"version": "1.28.4",
|
||||
"description": "midway with flyway, sql upgrade way ",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
@@ -46,5 +46,5 @@
|
||||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "a6cd532035f55a7ce122ea1229bb65f9d41e7125"
|
||||
"gitHead": "c8df9e698c265568e0e5e8b2f352c0599542d744"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,20 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.28.4](https://github.com/certd/certd/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复没有配置eab时,报order无法读取的问题 ([657a2ae](https://github.com/certd/certd/commit/657a2ae032e6f61ac27fbdd26c7bf169c041219e))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 通知标题优化 ([ff083ce](https://github.com/certd/certd/commit/ff083ce6848a8bee3c8248e4b881086ae1517c28))
|
||||
|
||||
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/plugin-cert",
|
||||
"private": false,
|
||||
"version": "1.28.2",
|
||||
"version": "1.28.4",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -15,9 +15,9 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/acme-client": "^1.28.2",
|
||||
"@certd/basic": "^1.28.2",
|
||||
"@certd/pipeline": "^1.28.2",
|
||||
"@certd/acme-client": "^1.28.4",
|
||||
"@certd/basic": "^1.28.4",
|
||||
"@certd/pipeline": "^1.28.4",
|
||||
"@google-cloud/publicca": "^1.3.0",
|
||||
"dayjs": "^1.11.7",
|
||||
"jszip": "^3.10.1",
|
||||
@@ -40,5 +40,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "a6cd532035f55a7ce122ea1229bb65f9d41e7125"
|
||||
"gitHead": "c8df9e698c265568e0e5e8b2f352c0599542d744"
|
||||
}
|
||||
|
||||
@@ -24,10 +24,11 @@ export type DomainsVerifyPlan = {
|
||||
};
|
||||
|
||||
export type CertInfo = {
|
||||
crt: string;
|
||||
key: string;
|
||||
csr: string;
|
||||
ic?: string;
|
||||
crt: string; //fullchain证书
|
||||
key: string; //私钥
|
||||
csr: string; //csr
|
||||
oc?: string; //仅证书,非fullchain证书
|
||||
ic?: string; //中间证书
|
||||
pfx?: string;
|
||||
der?: string;
|
||||
jks?: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AbstractTaskPlugin, IContext, NotificationBody, sendNotification, Step, TaskInput, TaskOutput } from "@certd/pipeline";
|
||||
import { AbstractTaskPlugin, IContext, NotificationBody, Step, TaskInput, TaskOutput } from "@certd/pipeline";
|
||||
import dayjs from "dayjs";
|
||||
import type { CertInfo } from "./acme.js";
|
||||
import { CertReader } from "./cert-reader.js";
|
||||
@@ -191,7 +191,7 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||
zip.file("cert.crt", cert.crt);
|
||||
zip.file("cert.key", cert.key);
|
||||
zip.file("intermediate.crt", cert.ic);
|
||||
|
||||
zip.file("origin.crt", cert.oc);
|
||||
if (cert.pfx) {
|
||||
zip.file("cert.pfx", Buffer.from(cert.pfx, "base64"));
|
||||
}
|
||||
@@ -201,6 +201,20 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||
if (cert.jks) {
|
||||
zip.file("cert.jks", Buffer.from(cert.jks, "base64"));
|
||||
}
|
||||
|
||||
zip.file(
|
||||
"说明.txt",
|
||||
`证书文件说明
|
||||
cert.crt:证书文件,包含证书链,pem格式
|
||||
cert.key:私钥文件,pem格式
|
||||
intermediate.crt:中间证书文件,pem格式
|
||||
origin.crt:原始证书文件,不含证书链,pem格式
|
||||
cert.pfx:pfx格式证书文件,iis服务器使用
|
||||
cert.der:der格式证书文件
|
||||
cert.jks:jks格式证书文件,java服务器使用
|
||||
`
|
||||
);
|
||||
|
||||
const content = await zip.generateAsync({ type: "nodebuffer" });
|
||||
this.saveFile(filename, content);
|
||||
this.logger.info(`已保存文件:${filename}`);
|
||||
@@ -295,7 +309,6 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||
* 检查是否过期,默认提前35天
|
||||
* @param expires
|
||||
* @param maxDays
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isWillExpire(expires: number, maxDays = 20) {
|
||||
if (expires == null) {
|
||||
@@ -312,39 +325,20 @@ export abstract class CertApplyBasePlugin extends AbstractTaskPlugin {
|
||||
this.logger.info("发送证书申请成功通知");
|
||||
const url = await this.ctx.urlService.getPipelineDetailUrl(this.pipeline.id, this.ctx.runtime.id);
|
||||
const body: NotificationBody = {
|
||||
title: `【Certd】证书申请成功【${this.pipeline.title}】`,
|
||||
title: `证书申请成功【${this.pipeline.title}】`,
|
||||
content: `域名:${this.domains.join(",")}`,
|
||||
url: url,
|
||||
};
|
||||
try {
|
||||
const defNotification = await this.ctx.notificationService.getDefault();
|
||||
if (defNotification) {
|
||||
this.logger.info(`通知渠道:${defNotification.name}`);
|
||||
const notificationCtx = {
|
||||
http: this.ctx.http,
|
||||
logger: this.logger,
|
||||
utils: this.ctx.utils,
|
||||
emailService: this.ctx.emailService,
|
||||
};
|
||||
await sendNotification({
|
||||
config: defNotification,
|
||||
ctx: notificationCtx,
|
||||
body,
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.logger.warn("未配置默认通知,将发送邮件通知");
|
||||
await this.sendSuccessEmail(body);
|
||||
await this.ctx.notificationService.send({
|
||||
useDefault: true,
|
||||
useEmail: true,
|
||||
emailAddress: this.email,
|
||||
logger: this.logger,
|
||||
body,
|
||||
});
|
||||
} catch (e) {
|
||||
this.logger.error("证书申请成功通知发送失败", e);
|
||||
}
|
||||
}
|
||||
async sendSuccessEmail(body: NotificationBody) {
|
||||
this.logger.info("发送邮件通知:" + this.email);
|
||||
await this.ctx.emailService.send({
|
||||
receivers: [this.email],
|
||||
subject: body.title,
|
||||
content: body.content,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ export type CertReaderHandleContext = {
|
||||
reader: CertReader;
|
||||
tmpCrtPath: string;
|
||||
tmpKeyPath: string;
|
||||
tmpOcPath?: string;
|
||||
tmpPfxPath?: string;
|
||||
tmpDerPath?: string;
|
||||
tmpIcPath?: string;
|
||||
@@ -19,6 +20,7 @@ export type CertReaderHandle = (ctx: CertReaderHandleContext) => Promise<void>;
|
||||
export type HandleOpts = { logger: ILogger; handle: CertReaderHandle };
|
||||
export class CertReader {
|
||||
cert: CertInfo;
|
||||
oc: string; //仅证书,非fullchain证书
|
||||
crt: string;
|
||||
key: string;
|
||||
csr: string;
|
||||
@@ -38,6 +40,12 @@ export class CertReader {
|
||||
this.cert.ic = this.ic;
|
||||
}
|
||||
|
||||
this.oc = certInfo.oc;
|
||||
if (!this.oc) {
|
||||
this.oc = this.getOc();
|
||||
this.cert.oc = this.oc;
|
||||
}
|
||||
|
||||
const { detail, expires } = this.getCrtDetail(this.cert.crt);
|
||||
this.detail = detail;
|
||||
this.expires = expires.getTime();
|
||||
@@ -56,6 +64,13 @@ export class CertReader {
|
||||
return ic.trim();
|
||||
}
|
||||
|
||||
getOc() {
|
||||
//原始证书 就是crt的第一个 -----END CERTIFICATE----- 之前的内容
|
||||
const endStr = "-----END CERTIFICATE-----";
|
||||
const arr = this.crt.split(endStr);
|
||||
return arr[0] + endStr;
|
||||
}
|
||||
|
||||
toCertInfo(): CertInfo {
|
||||
return this.cert;
|
||||
}
|
||||
@@ -73,7 +88,7 @@ export class CertReader {
|
||||
return domains;
|
||||
}
|
||||
|
||||
saveToFile(type: "crt" | "key" | "pfx" | "der" | "ic" | "jks", filepath?: string) {
|
||||
saveToFile(type: "crt" | "key" | "pfx" | "der" | "oc" | "ic" | "jks", filepath?: string) {
|
||||
if (!this.cert[type]) {
|
||||
return;
|
||||
}
|
||||
@@ -87,7 +102,7 @@ export class CertReader {
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
if (type === "crt" || type === "key" || type === "ic") {
|
||||
if (type === "crt" || type === "key" || type === "ic" || type === "oc") {
|
||||
fs.writeFileSync(filepath, this.cert[type]);
|
||||
} else {
|
||||
fs.writeFileSync(filepath, Buffer.from(this.cert[type], "base64"));
|
||||
@@ -102,9 +117,10 @@ export class CertReader {
|
||||
const tmpKeyPath = this.saveToFile("key");
|
||||
const tmpPfxPath = this.saveToFile("pfx");
|
||||
const tmpIcPath = this.saveToFile("ic");
|
||||
logger.info("本地文件写入成功");
|
||||
const tmpOcPath = this.saveToFile("oc");
|
||||
const tmpDerPath = this.saveToFile("der");
|
||||
const tmpJksPath = this.saveToFile("jks");
|
||||
logger.info("本地文件写入成功");
|
||||
try {
|
||||
return await opts.handle({
|
||||
reader: this,
|
||||
@@ -114,6 +130,7 @@ export class CertReader {
|
||||
tmpDerPath: tmpDerPath,
|
||||
tmpIcPath: tmpIcPath,
|
||||
tmpJksPath: tmpJksPath,
|
||||
tmpOcPath: tmpOcPath,
|
||||
});
|
||||
} catch (err) {
|
||||
throw err;
|
||||
@@ -128,6 +145,7 @@ export class CertReader {
|
||||
removeFile(tmpCrtPath);
|
||||
removeFile(tmpKeyPath);
|
||||
removeFile(tmpPfxPath);
|
||||
removeFile(tmpOcPath);
|
||||
removeFile(tmpDerPath);
|
||||
removeFile(tmpIcPath);
|
||||
removeFile(tmpJksPath);
|
||||
|
||||
@@ -271,8 +271,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
this.logger.info("当前正在使用 google公共EAB授权");
|
||||
eab = await this.ctx.accessService.getCommonById(this.googleCommonEabAccessId);
|
||||
} else {
|
||||
this.logger.error("google需要配置EAB授权或服务账号授权");
|
||||
return;
|
||||
throw new Error("google需要配置EAB授权或服务账号授权");
|
||||
}
|
||||
} else if (this.sslProvider === "zerossl") {
|
||||
if (this.eabAccessId) {
|
||||
@@ -282,8 +281,7 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
this.logger.info("当前正在使用 zerossl 公共EAB授权");
|
||||
eab = await this.ctx.accessService.getCommonById(this.zerosslCommonEabAccessId);
|
||||
} else {
|
||||
this.logger.error("zerossl需要配置EAB授权");
|
||||
return;
|
||||
throw new Error("zerossl需要配置EAB授权");
|
||||
}
|
||||
}
|
||||
this.eab = eab;
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.28.4](https://github.com/certd/certd/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-lib
|
||||
|
||||
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-lib
|
||||
|
||||
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-lib
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/plugin-lib",
|
||||
"private": false,
|
||||
"version": "1.28.2",
|
||||
"version": "1.28.4",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -16,9 +16,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@alicloud/pop-core": "^1.7.10",
|
||||
"@certd/basic": "^1.28.2",
|
||||
"@certd/pipeline": "^1.28.2",
|
||||
"@certd/plugin-cert": "^1.28.2",
|
||||
"@certd/basic": "^1.28.4",
|
||||
"@certd/pipeline": "^1.28.4",
|
||||
"@certd/plugin-cert": "^1.28.4",
|
||||
"@kubernetes/client-node": "0.21.0",
|
||||
"dayjs": "^1.11.7",
|
||||
"iconv-lite": "^0.6.3",
|
||||
@@ -44,5 +44,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "a6cd532035f55a7ce122ea1229bb65f9d41e7125"
|
||||
"gitHead": "c8df9e698c265568e0e5e8b2f352c0599542d744"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,21 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.28.4](https://github.com/certd/certd/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/ui-client
|
||||
|
||||
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复授权被删除后,无法清空的bug ([b45977c](https://github.com/certd/certd/commit/b45977c29a29084c11e496bec3415eaaebafdd74))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 点击版本红点按钮,跳转到升级帮助页面 ([454fbda](https://github.com/certd/certd/commit/454fbda581bbe22abca5b91e5086ea9d9d58a020))
|
||||
* 通知标题优化 ([ff083ce](https://github.com/certd/certd/commit/ff083ce6848a8bee3c8248e4b881086ae1517c28))
|
||||
|
||||
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/ui-client",
|
||||
"version": "1.28.2",
|
||||
"version": "1.28.4",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite --open",
|
||||
@@ -65,8 +65,8 @@
|
||||
"vuedraggable": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/lib-iframe": "^1.28.2",
|
||||
"@certd/pipeline": "^1.28.2",
|
||||
"@certd/lib-iframe": "^1.28.4",
|
||||
"@certd/pipeline": "^1.28.4",
|
||||
"@rollup/plugin-commonjs": "^25.0.7",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@types/chai": "^4.3.12",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="access-selector">
|
||||
<span v-if="target?.name" class="mr-5 cd-flex-inline">
|
||||
<a-tag class="mr-5" color="green">{{ target.name }}</a-tag>
|
||||
<span v-if="modelValue" class="mr-5 cd-flex-inline">
|
||||
<a-tag class="mr-5" color="green">{{ target.name || modelValue }}</a-tag>
|
||||
<fs-icon class="cd-icon-button" icon="ion:close-circle-outline" @click="clear"></fs-icon>
|
||||
</span>
|
||||
<span v-else class="mlr-5 text-gray">{{ placeholder }}</span>
|
||||
|
||||
@@ -126,6 +126,7 @@ function clear() {
|
||||
}
|
||||
|
||||
async function emitValue(value: any) {
|
||||
target.value = optionsDictRef.dataMap[value];
|
||||
if (value !== 0 && pipeline?.value && target && pipeline.value.userId !== target.value.userId) {
|
||||
message.error("对不起,您不能修改他人流水线的通知");
|
||||
return;
|
||||
|
||||
@@ -182,7 +182,8 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
|
||||
const downloadUrl = `${env.API}/pi/history/download?pipelineId=${row.id}&fileId=${file.id}`;
|
||||
children.push(
|
||||
<div>
|
||||
<div>
|
||||
<div class={"flex-o m-5"}>
|
||||
<fs-icon icon={"ant-design:cloud-download-outlined"} class={"mr-5 fs-16"}></fs-icon>
|
||||
<a href={downloadUrl} target={"_blank"}>
|
||||
{file.filename}
|
||||
</a>
|
||||
@@ -197,7 +198,6 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
|
||||
|
||||
return (
|
||||
<div class={"mt-3"}>
|
||||
<h3>点击链接下载</h3>
|
||||
<div> {children}</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<div>
|
||||
<a-tag color="green" class="flex-inline pointer"> <fs-icon icon="ion:time-outline" class="mr-5"></fs-icon> {{ now }}</a-tag>
|
||||
<a-badge v-if="userStore.isAdmin" :dot="hasNewVersion">
|
||||
<a-tag color="blue" class="flex-inline pointer" :title="'最新版本:' + latestVersion">
|
||||
<a-tag color="blue" class="flex-inline pointer" :title="'最新版本:' + latestVersion" @click="openUpgradeUrl()">
|
||||
<fs-icon icon="ion:rocket-outline" class="mr-5"></fs-icon>
|
||||
v{{ version }}
|
||||
</a-tag>
|
||||
@@ -210,6 +210,10 @@ onMounted(async () => {
|
||||
await loadCount();
|
||||
await loadPluginGroups();
|
||||
});
|
||||
|
||||
function openUpgradeUrl() {
|
||||
window.open("https://certd.docmirror.cn/guide/install/upgrade.html");
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.28.4](https://github.com/certd/certd/compare/v1.28.3...v1.28.4) (2024-12-12)
|
||||
|
||||
**Note:** Version bump only for package @certd/ui-server
|
||||
|
||||
## [1.28.3](https://github.com/certd/certd/compare/v1.28.2...v1.28.3) (2024-12-12)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* mysql下access.setting字段改成text ([b7f5740](https://github.com/certd/certd/commit/b7f5740c57743914f754f3b4fdd94b59a2e8338c))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 通知标题优化 ([ff083ce](https://github.com/certd/certd/commit/ff083ce6848a8bee3c8248e4b881086ae1517c28))
|
||||
* 支持腾讯虚拟机开关机([@wujingke](https://github.com/wujingke)) ([8039e8b](https://github.com/certd/certd/commit/8039e8baf83c82d03f1a6198cf61c372026b962b))
|
||||
* 支持aws cloudfront ([0ae39f1](https://github.com/certd/certd/commit/0ae39f160a7c6b6696b3bf513d68aa28905810ad))
|
||||
|
||||
## [1.28.2](https://github.com/certd/certd/compare/v1.28.1...v1.28.2) (2024-12-09)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE `cd_access` MODIFY COLUMN `setting` text NULL AFTER `type`;
|
||||
|
||||
ALTER TABLE `pi_pipeline` MODIFY COLUMN `content` longtext NULL AFTER `title`;
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/ui-server",
|
||||
"version": "1.28.2",
|
||||
"version": "1.28.4",
|
||||
"description": "fast-server base midway",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
@@ -31,18 +31,21 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@alicloud/pop-core": "^1.7.10",
|
||||
"@certd/acme-client": "^1.28.2",
|
||||
"@certd/basic": "^1.28.2",
|
||||
"@certd/commercial-core": "^1.28.2",
|
||||
"@certd/lib-huawei": "^1.28.2",
|
||||
"@certd/lib-k8s": "^1.28.2",
|
||||
"@certd/lib-server": "^1.28.2",
|
||||
"@certd/midway-flyway-js": "^1.28.2",
|
||||
"@certd/pipeline": "^1.28.2",
|
||||
"@certd/plugin-cert": "^1.28.2",
|
||||
"@certd/plugin-lib": "^1.28.2",
|
||||
"@certd/plugin-plus": "^1.28.2",
|
||||
"@certd/plus-core": "^1.28.2",
|
||||
"@aws-sdk/client-acm": "^3.699.0",
|
||||
"@aws-sdk/client-cloudfront": "^3.699.0",
|
||||
"@aws-sdk/client-s3": "^3.705.0",
|
||||
"@certd/acme-client": "^1.28.4",
|
||||
"@certd/basic": "^1.28.4",
|
||||
"@certd/commercial-core": "^1.28.4",
|
||||
"@certd/lib-huawei": "^1.28.4",
|
||||
"@certd/lib-k8s": "^1.28.4",
|
||||
"@certd/lib-server": "^1.28.4",
|
||||
"@certd/midway-flyway-js": "^1.28.4",
|
||||
"@certd/pipeline": "^1.28.4",
|
||||
"@certd/plugin-cert": "^1.28.4",
|
||||
"@certd/plugin-lib": "^1.28.4",
|
||||
"@certd/plugin-plus": "^1.28.4",
|
||||
"@certd/plus-core": "^1.28.4",
|
||||
"@huaweicloud/huaweicloud-sdk-cdn": "^3.1.120",
|
||||
"@huaweicloud/huaweicloud-sdk-core": "^3.1.120",
|
||||
"@koa/cors": "^5.0.0",
|
||||
|
||||
@@ -12,10 +12,7 @@ export class EmailController extends BaseController {
|
||||
emailService: EmailService;
|
||||
|
||||
@Post('/test', { summary: Constants.per.authOnly })
|
||||
public async test(
|
||||
@Body('receiver')
|
||||
receiver
|
||||
) {
|
||||
public async test(@Body('receiver') receiver) {
|
||||
const userId = super.getUserId();
|
||||
await this.emailService.test(userId, receiver);
|
||||
return this.ok({});
|
||||
|
||||
@@ -56,18 +56,6 @@ export class HandleController extends BaseController {
|
||||
@Post('/notification', { summary: Constants.per.authOnly })
|
||||
async notificationRequest(@Body(ALL) body: NotificationRequestHandleReq) {
|
||||
const input = body.input.body;
|
||||
// if (body.input.id > 0) {
|
||||
// const oldEntity = await this.notificationService.info(body.input.id);
|
||||
// if (oldEntity) {
|
||||
// if (oldEntity.userId !== this.getUserId()) {
|
||||
// throw new Error('notification not found');
|
||||
// }
|
||||
// const param: any = {
|
||||
// type: body.typeName,
|
||||
// setting: JSON.stringify(body.input.access),
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
|
||||
const notification = await newNotification(body.typeName, input, {
|
||||
http,
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { Inject, Provide } from '@midwayjs/core';
|
||||
import { cache, isDev, randomNumber } from '@certd/basic';
|
||||
import { SysSettingsService } from '@certd/lib-server';
|
||||
import { SysSettingsService, SysSiteInfo } from '@certd/lib-server';
|
||||
import { SmsServiceFactory } from '../sms/factory.js';
|
||||
import { ISmsService } from '../sms/api.js';
|
||||
import { CodeErrorException } from '@certd/lib-server/dist/basic/exception/code-error-exception.js';
|
||||
import { EmailService } from './email-service.js';
|
||||
import { AccessService } from '../../pipeline/service/access-service.js';
|
||||
import { AccessSysGetter } from '../../pipeline/service/access-sys-getter.js';
|
||||
import { isComm } from '@certd/plus-core';
|
||||
|
||||
// {data: '<svg.../svg>', text: 'abcd'}
|
||||
/**
|
||||
@@ -99,9 +100,17 @@ export class CodeService {
|
||||
throw new Error('randomStr不能为空');
|
||||
}
|
||||
|
||||
let siteTitle = 'Certd';
|
||||
if (isComm()) {
|
||||
const siteInfo = await this.sysSettingsService.getSetting<SysSiteInfo>(SysSiteInfo);
|
||||
if (siteInfo) {
|
||||
siteTitle = siteInfo.title || siteTitle;
|
||||
}
|
||||
}
|
||||
|
||||
const code = randomNumber(4);
|
||||
await this.emailService.send({
|
||||
subject: '【Certd】验证码',
|
||||
subject: `【${siteTitle}】验证码`,
|
||||
content: `您的验证码是${code},请勿泄露`,
|
||||
receivers: [email],
|
||||
});
|
||||
|
||||
@@ -88,10 +88,14 @@ export class EmailService implements IEmailService {
|
||||
sysTitle = siteInfo.title || sysTitle;
|
||||
}
|
||||
}
|
||||
let subject = email.subject;
|
||||
if (!subject.includes(`【${sysTitle}】`)) {
|
||||
subject = `【${sysTitle}】${subject}`;
|
||||
}
|
||||
const mailOptions = {
|
||||
from: `${sysTitle} <${emailConfig.sender}>`,
|
||||
to: email.receivers.join(', '), // list of receivers
|
||||
subject: email.subject,
|
||||
subject: subject,
|
||||
text: email.content,
|
||||
};
|
||||
await transporter.sendMail(mailOptions);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { INotificationService } from '@certd/pipeline';
|
||||
import { INotificationService, NotificationSendReq } from '@certd/pipeline';
|
||||
import { NotificationService } from './notification-service.js';
|
||||
|
||||
export class NotificationGetter implements INotificationService {
|
||||
@@ -17,4 +17,8 @@ export class NotificationGetter implements INotificationService {
|
||||
async getById(id: any) {
|
||||
return await this.notificationService.getById(id, this.userId);
|
||||
}
|
||||
|
||||
async send(req: NotificationSendReq): Promise<void> {
|
||||
return await this.notificationService.send(req, this.userId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import { BaseService, ValidateException } from '@certd/lib-server';
|
||||
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import { BaseService, SysSettingsService, SysSiteInfo, ValidateException } from '@certd/lib-server';
|
||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { NotificationEntity } from '../entity/notification.js';
|
||||
import { NotificationInstanceConfig, notificationRegistry } from '@certd/pipeline';
|
||||
import { NotificationInstanceConfig, notificationRegistry, NotificationSendReq, sendNotification } from '@certd/pipeline';
|
||||
import { http, utils } from '@certd/basic';
|
||||
import { EmailService } from '../../basic/service/email-service.js';
|
||||
import { isComm } from '@certd/plus-core';
|
||||
|
||||
@Provide()
|
||||
@Scope(ScopeEnum.Singleton)
|
||||
@@ -11,6 +14,12 @@ export class NotificationService extends BaseService<NotificationEntity> {
|
||||
@InjectEntityModel(NotificationEntity)
|
||||
repository: Repository<NotificationEntity>;
|
||||
|
||||
@Inject()
|
||||
emailService: EmailService;
|
||||
|
||||
@Inject()
|
||||
sysSettingsService: SysSettingsService;
|
||||
|
||||
//@ts-ignore
|
||||
getRepository() {
|
||||
return this.repository;
|
||||
@@ -124,4 +133,58 @@ export class NotificationService extends BaseService<NotificationEntity> {
|
||||
});
|
||||
return this.buildNotificationInstanceConfig(res);
|
||||
}
|
||||
|
||||
async send(req: NotificationSendReq, userId?: number) {
|
||||
const logger = req.logger;
|
||||
let notifyConfig: NotificationInstanceConfig = null;
|
||||
if (req.id && req.id > 0) {
|
||||
notifyConfig = await this.getById(req.id, userId);
|
||||
if (!notifyConfig) {
|
||||
logger.warn(`未找到通知配置<${req.id}>`);
|
||||
}
|
||||
}
|
||||
if (!notifyConfig) {
|
||||
if (req.id === 0 || req.useDefault) {
|
||||
notifyConfig = await this.getDefault(userId);
|
||||
if (!notifyConfig) {
|
||||
logger.warn(`未找到默认通知配置`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (notifyConfig) {
|
||||
//发送通知
|
||||
logger.info('发送通知, 使用通知渠道:' + notifyConfig.name);
|
||||
|
||||
if (notifyConfig.type != 'email') {
|
||||
//非邮件通知,需要加上站点名称
|
||||
let siteTitle = 'Certd';
|
||||
if (isComm()) {
|
||||
const siteInfo = await this.sysSettingsService.getSetting<SysSiteInfo>(SysSiteInfo);
|
||||
siteTitle = siteInfo?.title || siteTitle;
|
||||
}
|
||||
req.body.title = `【${siteTitle}】${req.body.title}`;
|
||||
}
|
||||
|
||||
await sendNotification({
|
||||
config: notifyConfig,
|
||||
ctx: {
|
||||
http: http,
|
||||
logger: logger,
|
||||
utils: utils,
|
||||
emailService: this.emailService,
|
||||
},
|
||||
body: req.body,
|
||||
});
|
||||
} else {
|
||||
if (req.useEmail && req.emailAddress) {
|
||||
logger.info('使用邮件通知');
|
||||
await this.emailService.send({
|
||||
receivers: [req.emailAddress],
|
||||
subject: req.body.title,
|
||||
content: req.body.content,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,3 +13,4 @@ export * from './plugin-woai/index.js';
|
||||
export * from './plugin-cachefly/index.js';
|
||||
export * from './plugin-gcore/index.js';
|
||||
export * from './plugin-qnap/index.js';
|
||||
export * from './plugin-aws/index.js';
|
||||
|
||||
66
packages/ui/certd-server/src/plugins/plugin-aws/access.ts
Normal file
66
packages/ui/certd-server/src/plugins/plugin-aws/access.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { AccessInput, BaseAccess, IsAccess } from '@certd/pipeline';
|
||||
|
||||
export const AwsRegions = [
|
||||
{ label: 'us-east-1', value: 'us-east-1' },
|
||||
{ label: 'us-east-2', value: 'us-east-2' },
|
||||
{ label: 'us-west-1', value: 'us-west-1' },
|
||||
{ label: 'us-west-2', value: 'us-west-2' },
|
||||
{ label: 'af-south-1', value: 'af-south-1' },
|
||||
{ label: 'ap-east-1', value: 'ap-east-1' },
|
||||
{ label: 'ap-northeast-1', value: 'ap-northeast-1' },
|
||||
{ label: 'ap-northeast-2', value: 'ap-northeast-2' },
|
||||
{ label: 'ap-northeast-3', value: 'ap-northeast-3' },
|
||||
{ label: 'ap-south-1', value: 'ap-south-1' },
|
||||
{ label: 'ap-south-2', value: 'ap-south-2' },
|
||||
{ label: 'ap-southeast-1', value: 'ap-southeast-1' },
|
||||
{ label: 'ap-southeast-2', value: 'ap-southeast-2' },
|
||||
{ label: 'ap-southeast-3', value: 'ap-southeast-3' },
|
||||
{ label: 'ap-southeast-4', value: 'ap-southeast-4' },
|
||||
{ label: 'ap-southeast-5', value: 'ap-southeast-5' },
|
||||
{ label: 'ca-central-1', value: 'ca-central-1' },
|
||||
{ label: 'ca-west-1', value: 'ca-west-1' },
|
||||
{ label: 'eu-central-1', value: 'eu-central-1' },
|
||||
{ label: 'eu-central-2', value: 'eu-central-2' },
|
||||
{ label: 'eu-north-1', value: 'eu-north-1' },
|
||||
{ label: 'eu-south-1', value: 'eu-south-1' },
|
||||
{ label: 'eu-south-2', value: 'eu-south-2' },
|
||||
{ label: 'eu-west-1', value: 'eu-west-1' },
|
||||
{ label: 'eu-west-2', value: 'eu-west-2' },
|
||||
{ label: 'eu-west-3', value: 'eu-west-3' },
|
||||
{ label: 'il-central-1', value: 'il-central-1' },
|
||||
{ label: 'me-central-1', value: 'me-central-1' },
|
||||
{ label: 'me-south-1', value: 'me-south-1' },
|
||||
{ label: 'sa-east-1', value: 'sa-east-1' },
|
||||
];
|
||||
|
||||
@IsAccess({
|
||||
name: 'aws',
|
||||
title: '亚马逊云aws授权',
|
||||
desc: '',
|
||||
icon: 'ant-design:aws-outlined',
|
||||
})
|
||||
export class AwsAccess extends BaseAccess {
|
||||
@AccessInput({
|
||||
title: 'accessKeyId',
|
||||
component: {
|
||||
placeholder: 'accessKeyId',
|
||||
},
|
||||
helper:
|
||||
'右上角->安全凭证->访问密钥,[点击前往](https://us-east-1.console.aws.amazon.com/iam/home?region=ap-east-1#/security_credentials/access-key-wizard)',
|
||||
required: true,
|
||||
})
|
||||
accessKeyId = '';
|
||||
|
||||
@AccessInput({
|
||||
title: 'secretAccessKey',
|
||||
component: {
|
||||
placeholder: 'secretAccessKey',
|
||||
},
|
||||
required: true,
|
||||
encrypt: true,
|
||||
helper: '请妥善保管您的安全访问密钥。您可以在AWS管理控制台的IAM中创建新的访问密钥。',
|
||||
})
|
||||
secretAccessKey = '';
|
||||
}
|
||||
|
||||
new AwsAccess();
|
||||
2
packages/ui/certd-server/src/plugins/plugin-aws/index.ts
Normal file
2
packages/ui/certd-server/src/plugins/plugin-aws/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './plugins/index.js';
|
||||
export * from './access.js';
|
||||
@@ -0,0 +1,40 @@
|
||||
// 导入所需的 SDK 模块
|
||||
import { AwsAccess } from '../access.js';
|
||||
import { CertInfo } from '@certd/plugin-cert';
|
||||
|
||||
type AwsAcmClientOptions = { access: AwsAccess; region: string };
|
||||
|
||||
export class AwsAcmClient {
|
||||
options: AwsAcmClientOptions;
|
||||
access: AwsAccess;
|
||||
region: string;
|
||||
constructor(options: AwsAcmClientOptions) {
|
||||
this.options = options;
|
||||
this.access = options.access;
|
||||
this.region = options.region;
|
||||
}
|
||||
async importCertificate(certInfo: CertInfo) {
|
||||
// 创建 ACM 客户端
|
||||
const { ACMClient, ImportCertificateCommand } = await import('@aws-sdk/client-acm');
|
||||
const acmClient = new ACMClient({
|
||||
region: this.region, // 替换为您的 AWS 区域
|
||||
credentials: {
|
||||
accessKeyId: this.access.accessKeyId, // 从环境变量中读取
|
||||
secretAccessKey: this.access.secretAccessKey,
|
||||
},
|
||||
});
|
||||
|
||||
const cert = certInfo.crt.split('-----END CERTIFICATE-----')[0] + '-----END CERTIFICATE-----';
|
||||
// 构建上传参数
|
||||
const data = await acmClient.send(
|
||||
new ImportCertificateCommand({
|
||||
Certificate: Buffer.from(cert),
|
||||
PrivateKey: Buffer.from(certInfo.key),
|
||||
// CertificateChain: certificateChain, // 可选
|
||||
})
|
||||
);
|
||||
console.log('Upload successful:', data);
|
||||
// 返回证书 ARN(Amazon Resource Name)
|
||||
return data.CertificateArn;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './plugin-deploy-to-cloudfront.js';
|
||||
@@ -0,0 +1,162 @@
|
||||
import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||
import { CertInfo } from '@certd/plugin-cert';
|
||||
import { AwsAccess, AwsRegions } from '../access.js';
|
||||
import { AwsAcmClient } from '../libs/aws-acm-client.js';
|
||||
import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from '@certd/plugin-lib';
|
||||
import { optionsUtils } from '@certd/basic/dist/utils/util.options.js';
|
||||
import { AbstractPlusTaskPlugin } from '@certd/plugin-plus';
|
||||
|
||||
@IsTaskPlugin({
|
||||
name: 'AwsDeployToCloudFront',
|
||||
title: '部署证书到 AWS CloudFront',
|
||||
desc: '部署证书到 AWS CloudFront',
|
||||
icon: 'clarity:plugin-line',
|
||||
group: pluginGroups.aws.key,
|
||||
needPlus: true,
|
||||
default: {
|
||||
strategy: {
|
||||
runStrategy: RunStrategy.SkipWhenSucceed,
|
||||
},
|
||||
},
|
||||
})
|
||||
export class AwsDeployToCloudFront extends AbstractPlusTaskPlugin {
|
||||
@TaskInput({
|
||||
title: '域名证书',
|
||||
helper: '请选择前置任务输出的域名证书',
|
||||
component: {
|
||||
name: 'output-selector',
|
||||
from: ['CertApply', 'CertApplyLego', 'AwsUploadToACM'],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
cert!: CertInfo | string;
|
||||
|
||||
@TaskInput(createCertDomainGetterInputDefine({ props: { required: false } }))
|
||||
certDomains!: string[];
|
||||
|
||||
@TaskInput({
|
||||
title: '区域',
|
||||
helper: '证书上传区域',
|
||||
component: {
|
||||
name: 'a-auto-complete',
|
||||
vModel: 'value',
|
||||
options: AwsRegions,
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
region!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: 'Access授权',
|
||||
helper: 'aws的授权',
|
||||
component: {
|
||||
name: 'access-selector',
|
||||
type: 'aws',
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
accessId!: string;
|
||||
|
||||
@TaskInput(
|
||||
createRemoteSelectInputDefine({
|
||||
title: '分配ID',
|
||||
helper: '请选择distributions id',
|
||||
action: AwsDeployToCloudFront.prototype.onGetDistributions.name,
|
||||
required: true,
|
||||
})
|
||||
)
|
||||
distributionIds!: string[];
|
||||
|
||||
async onInstance() {}
|
||||
|
||||
async execute(): Promise<void> {
|
||||
const access = await this.getAccess<AwsAccess>(this.accessId);
|
||||
|
||||
let certId = this.cert as string;
|
||||
if (typeof this.cert !== 'string') {
|
||||
//先上传
|
||||
certId = await this.uploadToACM(access, this.cert);
|
||||
}
|
||||
//部署到CloudFront
|
||||
|
||||
const { CloudFrontClient, UpdateDistributionCommand, GetDistributionConfigCommand } = await import('@aws-sdk/client-cloudfront');
|
||||
const cloudFrontClient = new CloudFrontClient({
|
||||
region: this.region,
|
||||
credentials: {
|
||||
accessKeyId: access.accessKeyId,
|
||||
secretAccessKey: access.secretAccessKey,
|
||||
},
|
||||
});
|
||||
|
||||
// update-distribution
|
||||
for (const distributionId of this.distributionIds) {
|
||||
// get-distribution-config
|
||||
const getDistributionConfigCommand = new GetDistributionConfigCommand({
|
||||
Id: distributionId,
|
||||
});
|
||||
|
||||
const configData = await cloudFrontClient.send(getDistributionConfigCommand);
|
||||
|
||||
const updateDistributionCommand = new UpdateDistributionCommand({
|
||||
DistributionConfig: {
|
||||
...configData.DistributionConfig,
|
||||
ViewerCertificate: {
|
||||
...configData.DistributionConfig.ViewerCertificate,
|
||||
CloudFrontDefaultCertificate: false,
|
||||
ACMCertificateArn: certId,
|
||||
},
|
||||
},
|
||||
Id: distributionId,
|
||||
IfMatch: configData.ETag,
|
||||
});
|
||||
await cloudFrontClient.send(updateDistributionCommand);
|
||||
this.logger.info(`部署${distributionId}完成:`);
|
||||
}
|
||||
this.logger.info('部署完成');
|
||||
}
|
||||
|
||||
private async uploadToACM(access: AwsAccess, cert: CertInfo) {
|
||||
const acmClient = new AwsAcmClient({
|
||||
access,
|
||||
region: this.region,
|
||||
});
|
||||
const awsCertARN = await acmClient.importCertificate(cert);
|
||||
this.logger.info('证书上传成功,id=', awsCertARN);
|
||||
return awsCertARN;
|
||||
}
|
||||
|
||||
//查找分配ID列表选项
|
||||
async onGetDistributions() {
|
||||
if (!this.accessId) {
|
||||
throw new Error('请选择Access授权');
|
||||
}
|
||||
|
||||
const access = await this.getAccess<AwsAccess>(this.accessId);
|
||||
const { CloudFrontClient, ListDistributionsCommand } = await import('@aws-sdk/client-cloudfront');
|
||||
const cloudFrontClient = new CloudFrontClient({
|
||||
region: this.region,
|
||||
credentials: {
|
||||
accessKeyId: access.accessKeyId,
|
||||
secretAccessKey: access.secretAccessKey,
|
||||
},
|
||||
});
|
||||
// list-distributions
|
||||
const listDistributionsCommand = new ListDistributionsCommand({});
|
||||
const data = await cloudFrontClient.send(listDistributionsCommand);
|
||||
const distributions = data.DistributionList?.Items;
|
||||
if (!distributions || distributions.length === 0) {
|
||||
throw new Error('找不到CloudFront分配ID,您可以手动输入');
|
||||
}
|
||||
|
||||
const options = distributions.map((item: any) => {
|
||||
return {
|
||||
value: item.Id,
|
||||
label: `${item.DomainName}<${item.Id}>`,
|
||||
domain: item.DomainName,
|
||||
};
|
||||
});
|
||||
return optionsUtils.buildGroupOptions(options, this.certDomains);
|
||||
}
|
||||
}
|
||||
|
||||
new AwsDeployToCloudFront();
|
||||
@@ -0,0 +1,71 @@
|
||||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput, TaskOutput } from '@certd/pipeline';
|
||||
import { CertInfo } from '@certd/plugin-cert';
|
||||
import { AwsAccess, AwsRegions } from '../access.js';
|
||||
import { AwsAcmClient } from '../libs/aws-acm-client.js';
|
||||
|
||||
@IsTaskPlugin({
|
||||
name: 'AwsUploadToACM',
|
||||
title: '上传证书 AWS ACM',
|
||||
desc: '上传证书 AWS ACM',
|
||||
icon: 'clarity:plugin-line',
|
||||
group: pluginGroups.aws.key,
|
||||
default: {
|
||||
strategy: {
|
||||
runStrategy: RunStrategy.SkipWhenSucceed,
|
||||
},
|
||||
},
|
||||
})
|
||||
export class AwsUploadToACM extends AbstractTaskPlugin {
|
||||
@TaskInput({
|
||||
title: '域名证书',
|
||||
helper: '请选择前置任务输出的域名证书',
|
||||
component: {
|
||||
name: 'output-selector',
|
||||
from: ['CertApply', 'CertApplyLego'],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
cert!: CertInfo;
|
||||
|
||||
@TaskInput({
|
||||
title: 'Access授权',
|
||||
helper: 'aws的授权',
|
||||
component: {
|
||||
name: 'access-selector',
|
||||
type: 'aws',
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
accessId!: string;
|
||||
@TaskInput({
|
||||
title: '区域',
|
||||
helper: '证书上传区域',
|
||||
component: {
|
||||
name: 'a-auto-complete',
|
||||
vModel: 'value',
|
||||
options: AwsRegions,
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
region!: string;
|
||||
|
||||
@TaskOutput({
|
||||
title: '证书ARN',
|
||||
})
|
||||
awsCertARN = '';
|
||||
|
||||
async onInstance() {}
|
||||
|
||||
async execute(): Promise<void> {
|
||||
const { cert, accessId, region } = this;
|
||||
const access = await this.accessService.getById<AwsAccess>(accessId);
|
||||
const acmClient = new AwsAcmClient({
|
||||
access,
|
||||
region,
|
||||
});
|
||||
this.awsCertARN = await acmClient.importCertificate(cert);
|
||||
this.logger.info('证书上传成功,id=', this.awsCertARN);
|
||||
}
|
||||
}
|
||||
|
||||
new AwsUploadToACM();
|
||||
@@ -26,7 +26,10 @@ export class DemoTest extends AbstractTaskPlugin {
|
||||
component: {
|
||||
//前端组件配置,具体配置见组件文档 https://www.antdv.com/components/input-cn
|
||||
name: 'a-input',
|
||||
vModel: 'value', //双向绑定组件的props名称
|
||||
},
|
||||
helper: '帮助说明,[链接](https://certd.docmirror.cn)',
|
||||
required: false, //是否必填
|
||||
})
|
||||
text!: string;
|
||||
|
||||
@@ -38,13 +41,29 @@ export class DemoTest extends AbstractTaskPlugin {
|
||||
name: 'a-auto-complete',
|
||||
vModel: 'value',
|
||||
options: [
|
||||
{ value: '1', label: '选项1' },
|
||||
{ value: '2', label: '选项2' },
|
||||
//选项列表
|
||||
{ value: 'show', label: '动态显' },
|
||||
{ value: 'hide', label: '动态隐' },
|
||||
],
|
||||
},
|
||||
})
|
||||
select!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '动态显隐',
|
||||
helper: '我会根据选择框的值进行显隐',
|
||||
show: true, //动态计算的值会覆盖它
|
||||
//动态计算脚本, mergeScript返回的对象会合并当前配置,此处演示 show的值会被动态计算结果覆盖,show的值根据用户选择的select的值决定
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.select === 'show';
|
||||
})
|
||||
}
|
||||
`,
|
||||
})
|
||||
showText!: string;
|
||||
|
||||
//测试参数
|
||||
@TaskInput({
|
||||
title: '多选框',
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||
import { utils } from '@certd/basic';
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
import { AbstractPlusTaskPlugin } from '@certd/plugin-plus';
|
||||
|
||||
@IsTaskPlugin({
|
||||
name: 'DeployCertToTencentTKEIngress',
|
||||
title: '部署到腾讯云TKE-ingress',
|
||||
needPlus: true,
|
||||
icon: 'svg:icon-tencentcloud',
|
||||
group: pluginGroups.tencent.key,
|
||||
desc: 'Qcloud类型需要【上传到腾讯云】作为前置任务;ApiServer未开启外网访问则需要做域名的内网IP映射',
|
||||
default: {
|
||||
strategy: {
|
||||
runStrategy: RunStrategy.SkipWhenSucceed,
|
||||
},
|
||||
},
|
||||
})
|
||||
export class DeployCertToTencentTKEIngressPlugin extends AbstractPlusTaskPlugin {
|
||||
@TaskInput({ title: '大区', value: 'ap-guangzhou', required: true })
|
||||
region!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '集群ID',
|
||||
required: true,
|
||||
desc: '例如:cls-6lbj1vee',
|
||||
request: true,
|
||||
})
|
||||
clusterId!: string;
|
||||
|
||||
@TaskInput({ title: '集群namespace', value: 'default', required: true })
|
||||
namespace!: string;
|
||||
|
||||
@TaskInput({ title: '证书的secret名称', required: true })
|
||||
secretName!: string | string[];
|
||||
|
||||
@TaskInput({ title: 'ingress名称', required: true })
|
||||
ingressName!: string | string[];
|
||||
|
||||
@TaskInput({
|
||||
title: 'ingress类型',
|
||||
component: {
|
||||
name: 'a-auto-complete',
|
||||
vModel: 'value',
|
||||
options: [{ value: 'qcloud' }, { value: 'nginx' }],
|
||||
},
|
||||
helper: '可选 qcloud / nginx',
|
||||
})
|
||||
ingressClass!: string;
|
||||
|
||||
// @TaskInput({ title: "集群内网ip", helper: "如果开启了外网的话,无需设置" })
|
||||
// clusterIp!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '集群域名',
|
||||
helper: '可不填,默认为:[clusterId].ccs.tencent-cloud.com',
|
||||
})
|
||||
clusterDomain!: string;
|
||||
|
||||
/**
|
||||
* AccessProvider的key,或者一个包含access的具体的对象
|
||||
*/
|
||||
@TaskInput({
|
||||
title: 'Access授权',
|
||||
helper: 'access授权',
|
||||
component: {
|
||||
name: 'access-selector',
|
||||
type: 'tencent',
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
accessId!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '腾讯云证书id',
|
||||
helper: '请选择“上传证书到腾讯云”前置任务的输出',
|
||||
component: {
|
||||
name: 'output-selector',
|
||||
from: 'UploadCertToTencent',
|
||||
},
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.ingressClass === "qcloud"
|
||||
})
|
||||
}
|
||||
`,
|
||||
required: true,
|
||||
})
|
||||
tencentCertId!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '域名证书',
|
||||
helper: '请选择前置任务输出的域名证书',
|
||||
component: {
|
||||
name: 'output-selector',
|
||||
from: ['CertApply', 'CertApplyLego'],
|
||||
},
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.ingressClass === "nginx"
|
||||
})
|
||||
}
|
||||
`,
|
||||
required: true,
|
||||
})
|
||||
cert!: any;
|
||||
|
||||
K8sClient: any;
|
||||
|
||||
async onInstance() {
|
||||
// const TkeClient = this.tencentcloud.tke.v20180525.Client;
|
||||
const k8sSdk = await import('@certd/lib-k8s');
|
||||
this.K8sClient = k8sSdk.K8sClient;
|
||||
}
|
||||
async execute(): Promise<void> {
|
||||
const accessProvider = await this.accessService.getById(this.accessId);
|
||||
const tkeClient = await this.getTkeClient(accessProvider, this.region);
|
||||
const kubeConfigStr = await this.getTkeKubeConfig(tkeClient, this.clusterId);
|
||||
|
||||
this.logger.info('kubeconfig已成功获取');
|
||||
const k8sClient = new this.K8sClient({
|
||||
kubeConfigStr,
|
||||
logger: this.logger,
|
||||
});
|
||||
// if (this.clusterIp != null) {
|
||||
// if (!this.clusterDomain) {
|
||||
// this.clusterDomain = `${this.clusterId}.ccs.tencent-cloud.com`;
|
||||
// }
|
||||
// // 修改内网解析ip地址
|
||||
// k8sClient.setLookup({ [this.clusterDomain]: { ip: this.clusterIp } });
|
||||
// }
|
||||
const ingressType = this.ingressClass || 'qcloud';
|
||||
if (ingressType === 'qcloud') {
|
||||
await this.patchQcloudCertSecret({ k8sClient });
|
||||
} else {
|
||||
await this.patchNginxCertSecret({ k8sClient });
|
||||
}
|
||||
|
||||
await utils.sleep(5000); // 停留2秒,等待secret部署完成
|
||||
await this.restartIngress({ k8sClient });
|
||||
}
|
||||
|
||||
async getTkeClient(accessProvider: any, region = 'ap-guangzhou') {
|
||||
const sdk = await import('tencentcloud-sdk-nodejs/tencentcloud/services/tke/v20180525/index.js');
|
||||
const TkeClient = sdk.v20180525.Client;
|
||||
const clientConfig = {
|
||||
credential: {
|
||||
secretId: accessProvider.secretId,
|
||||
secretKey: accessProvider.secretKey,
|
||||
},
|
||||
region,
|
||||
profile: {
|
||||
httpProfile: {
|
||||
endpoint: 'tke.tencentcloudapi.com',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return new TkeClient(clientConfig);
|
||||
}
|
||||
|
||||
async getTkeKubeConfig(client: any, clusterId: string) {
|
||||
// Depends on tencentcloud-sdk-nodejs version 4.0.3 or higher
|
||||
const params = {
|
||||
ClusterId: clusterId,
|
||||
};
|
||||
const ret = await client.DescribeClusterKubeconfig(params);
|
||||
this.checkRet(ret);
|
||||
this.logger.info('注意:后续操作需要在【集群->基本信息】中开启外网或内网访问,https://console.cloud.tencent.com/tke2/cluster');
|
||||
return ret.Kubeconfig;
|
||||
}
|
||||
|
||||
appendTimeSuffix(name: string) {
|
||||
if (name == null) {
|
||||
name = 'certd';
|
||||
}
|
||||
return name + '-' + dayjs().format('YYYYMMDD-HHmmss');
|
||||
}
|
||||
|
||||
async patchQcloudCertSecret(options: { k8sClient: any }) {
|
||||
if (this.tencentCertId == null) {
|
||||
throw new Error('请先将【上传证书到腾讯云】作为前置任务');
|
||||
}
|
||||
this.logger.info('腾讯云证书ID:', this.tencentCertId);
|
||||
const certIdBase64 = Buffer.from(this.tencentCertId).toString('base64');
|
||||
|
||||
const { namespace, secretName } = this;
|
||||
|
||||
const body = {
|
||||
data: {
|
||||
qcloud_cert_id: certIdBase64,
|
||||
},
|
||||
metadata: {
|
||||
labels: {
|
||||
certd: this.appendTimeSuffix('certd'),
|
||||
},
|
||||
},
|
||||
};
|
||||
let secretNames: any = secretName;
|
||||
if (typeof secretName === 'string') {
|
||||
secretNames = [secretName];
|
||||
}
|
||||
for (const secret of secretNames) {
|
||||
await options.k8sClient.patchSecret({
|
||||
namespace,
|
||||
secretName: secret,
|
||||
body,
|
||||
});
|
||||
this.logger.info(`CertSecret已更新:${secret}`);
|
||||
}
|
||||
}
|
||||
|
||||
async patchNginxCertSecret(options: { k8sClient: any }) {
|
||||
const { k8sClient } = options;
|
||||
const { cert } = this;
|
||||
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 } = this;
|
||||
|
||||
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(options: { k8sClient: any }) {
|
||||
const { k8sClient } = options;
|
||||
const { namespace, ingressName } = this;
|
||||
|
||||
const body = {
|
||||
metadata: {
|
||||
labels: {
|
||||
certd: this.appendTimeSuffix('certd'),
|
||||
},
|
||||
},
|
||||
};
|
||||
let ingressNames = this.ingressName;
|
||||
if (typeof ingressName === 'string') {
|
||||
ingressNames = [ingressName];
|
||||
}
|
||||
for (const ingress of ingressNames) {
|
||||
await k8sClient.patchIngress({ namespace, ingressName: ingress, body });
|
||||
this.logger.info(`ingress已重启:${ingress}`);
|
||||
}
|
||||
}
|
||||
checkRet(ret: any) {
|
||||
if (!ret || ret.Error) {
|
||||
throw new Error('执行失败:' + ret.Error.Code + ',' + ret.Error.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,3 +6,4 @@ export * from './upload-to-tencent/index.js';
|
||||
export * from './deploy-to-cos/index.js';
|
||||
export * from './deploy-to-eo/index.js';
|
||||
export * from './delete-expiring-cert/index.js';
|
||||
export * from './deploy-to-tke-ingress/index.js';
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
import { IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from '@certd/pipeline';
|
||||
import { AbstractTaskPlugin } from '@certd/pipeline';
|
||||
import { TencentAccess } from '@certd/plugin-plus';
|
||||
import { createRemoteSelectInputDefine } from '@certd/plugin-lib';
|
||||
|
||||
@IsTaskPlugin({
|
||||
name: 'TencentActionInstancesPlugin',
|
||||
title: '腾讯云实例开关机',
|
||||
icon: 'svg:icon-tencentcloud',
|
||||
group: pluginGroups.tencent.key,
|
||||
desc: '腾讯云实例开关机',
|
||||
default: {
|
||||
strategy: {
|
||||
runStrategy: RunStrategy.AlwaysRun,
|
||||
},
|
||||
},
|
||||
needPlus: false,
|
||||
})
|
||||
export class TencentActionInstancesPlugin extends AbstractTaskPlugin {
|
||||
@TaskInput({
|
||||
title: 'Access提供者',
|
||||
helper: 'access 授权',
|
||||
component: {
|
||||
name: 'access-selector',
|
||||
type: 'tencent',
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
accessId!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '所在地域',
|
||||
helper: '实例所在地域',
|
||||
component: {
|
||||
name: 'a-auto-complete',
|
||||
vModel: 'value',
|
||||
options: [
|
||||
{ value: '', label: '--------中国大陆地区-------', disabled: true },
|
||||
{ value: 'ap-beijing-1', label: '北京1区' },
|
||||
{ value: 'ap-beijing', label: '北京' },
|
||||
{ value: 'ap-nanjing', label: '南京' },
|
||||
{ value: 'ap-shanghai', label: '上海' },
|
||||
{ value: 'ap-guangzhou', label: '广州' },
|
||||
{ value: 'ap-chengdu', label: '成都' },
|
||||
{ value: 'ap-chongqing', label: '重庆' },
|
||||
{ value: 'ap-shenzhen-fsi', label: '深圳金融' },
|
||||
{ value: 'ap-shanghai-fsi', label: '上海金融' },
|
||||
{ value: 'ap-beijing-fsi', label: '北京金融' },
|
||||
{ value: '', label: '--------中国香港及境外-------', disabled: true },
|
||||
{ value: 'ap-hongkong', label: '中国香港' },
|
||||
{ value: 'ap-singapore', label: '新加坡' },
|
||||
{ value: 'ap-mumbai', label: '孟买' },
|
||||
{ value: 'ap-jakarta', label: '雅加达' },
|
||||
{ value: 'ap-seoul', label: '首尔' },
|
||||
{ value: 'ap-bangkok', label: '曼谷' },
|
||||
{ value: 'ap-tokyo', label: '东京' },
|
||||
{ value: 'na-siliconvalley', label: '硅谷' },
|
||||
{ value: 'na-ashburn', label: '弗吉尼亚' },
|
||||
{ value: 'sa-saopaulo', label: '圣保罗' },
|
||||
{ value: 'eu-frankfurt', label: '法兰克福' },
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
region!: string;
|
||||
|
||||
@TaskInput(
|
||||
createRemoteSelectInputDefine({
|
||||
title: '实列ID',
|
||||
helper: '请选择实列',
|
||||
typeName: 'TencentStartInstancesPlugin',
|
||||
action: TencentActionInstancesPlugin.prototype.onGetInstanceList.name,
|
||||
watches: ['region'],
|
||||
})
|
||||
)
|
||||
instanceId!: string[];
|
||||
|
||||
@TaskInput({
|
||||
title: '操作',
|
||||
component: {
|
||||
name: 'a-radio-group',
|
||||
vModel: 'value',
|
||||
options: [
|
||||
{ value: 'start', label: '开机' },
|
||||
{ value: 'stop', label: '关机' },
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
action!: string;
|
||||
|
||||
@TaskInput({
|
||||
title: '实例关机不收费',
|
||||
value: true,
|
||||
component: {
|
||||
name: 'a-switch',
|
||||
vModel: 'checked',
|
||||
placeholder: `按量计费实例关机不收费`,
|
||||
},
|
||||
required: false,
|
||||
mergeScript: `
|
||||
return {
|
||||
show: ctx.compute(({form})=>{
|
||||
return form.action === 'stop';
|
||||
})
|
||||
}
|
||||
`,
|
||||
})
|
||||
charging = true;
|
||||
|
||||
async onInstance() {}
|
||||
|
||||
async execute(): Promise<void> {
|
||||
const cvmClient = await this.getCvmClient();
|
||||
const params = {
|
||||
InstanceIds: this.instanceId,
|
||||
};
|
||||
let res: any;
|
||||
if (this.action === 'start') {
|
||||
res = await cvmClient.StartInstances(params);
|
||||
} else {
|
||||
res = await cvmClient.StopInstances(
|
||||
Object.assign(params, {
|
||||
StopType: 'SOFT_FIRST',
|
||||
StoppedMode: this.charging ? 'STOP_CHARGING' : 'KEEP_CHARGING',
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
this.checkRet(res);
|
||||
}
|
||||
|
||||
checkRet(ret: any) {
|
||||
if (!ret || ret.Error) {
|
||||
throw new Error('执行失败:' + ret.Error.Code + ',' + ret.Error.Message);
|
||||
}
|
||||
}
|
||||
|
||||
async getCvmClient() {
|
||||
const accessProvider = await this.accessService.getById<TencentAccess>(this.accessId);
|
||||
const sdk = await import('tencentcloud-sdk-nodejs/tencentcloud/services/cvm/v20170312/index.js');
|
||||
const CvmClient = sdk.v20170312.Client;
|
||||
|
||||
if (!this.region) {
|
||||
throw new Error('所在地域不能为空');
|
||||
}
|
||||
|
||||
const clientConfig = {
|
||||
credential: {
|
||||
secretId: accessProvider.secretId,
|
||||
secretKey: accessProvider.secretKey,
|
||||
},
|
||||
region: this.region,
|
||||
profile: {
|
||||
httpProfile: {
|
||||
endpoint: 'cvm.tencentcloudapi.com',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return new CvmClient(clientConfig);
|
||||
}
|
||||
|
||||
async onGetInstanceList(data: any) {
|
||||
const cvmClient = await this.getCvmClient();
|
||||
const res = await cvmClient.DescribeInstances({
|
||||
Limit: 100,
|
||||
});
|
||||
this.checkRet(res);
|
||||
|
||||
this.ctx.logger.info('获取实列列表:', res);
|
||||
return res.InstanceSet.map((item: any) => {
|
||||
return {
|
||||
label: item.InstanceName,
|
||||
value: item.InstanceId,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
new TencentActionInstancesPlugin();
|
||||
Reference in New Issue
Block a user