Compare commits
98 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3fb9b00f66 | ||
|
|
a492fbe18c | ||
|
|
0383233315 | ||
|
|
0434f95a1e | ||
|
|
769b24aa88 | ||
|
|
94a0292fad | ||
|
|
410231cd1f | ||
|
|
1d4e048777 | ||
|
|
c16fe1a807 | ||
|
|
e8ed831b28 | ||
|
|
c7c89efbe7 | ||
|
|
d7f3d9c512 | ||
|
|
ce67cc5a39 | ||
|
|
945d0da36f | ||
|
|
898311c6e5 | ||
|
|
5d6bc03f21 | ||
|
|
018743299b | ||
|
|
18e7238067 | ||
|
|
b7d1ff8960 | ||
|
|
0d44373de6 | ||
|
|
3d680e50e2 | ||
|
|
9542079e20 | ||
|
|
081e83e0bf | ||
|
|
9c8ab98efb | ||
|
|
bf26db77cb | ||
|
|
08ea915d24 | ||
|
|
fb62f1e105 | ||
|
|
261b3a8546 | ||
|
|
563adbec2a | ||
|
|
c6dfe11bdb | ||
|
|
e4bfa90a77 | ||
|
|
b833d09466 | ||
|
|
3ec0ba7052 | ||
|
|
57eb66b889 | ||
|
|
a048eb95a9 | ||
|
|
23e58b914e | ||
|
|
1170f635fd | ||
|
|
553aceac44 | ||
|
|
e24de70c02 | ||
|
|
bba2b25757 | ||
|
|
4132ec3617 | ||
|
|
9b3c7e16c0 | ||
|
|
0448538073 | ||
|
|
80157496d5 | ||
|
|
62e2ed2fb8 | ||
|
|
a750592eb5 | ||
|
|
5e6d729631 | ||
|
|
24fe824757 | ||
|
|
84a3f3346a | ||
|
|
bd26dfecb8 | ||
|
|
43182de732 | ||
|
|
d58109f4be | ||
|
|
59935df6b1 | ||
|
|
252da5d7e1 | ||
|
|
c3e7590f53 | ||
|
|
65cd1dc850 | ||
|
|
2203bb5268 | ||
|
|
8e5c36968a | ||
|
|
9ad0e6fb57 | ||
|
|
7d55383cf7 | ||
|
|
6dc65eea2f | ||
|
|
7210f63884 | ||
|
|
f94db675fb | ||
|
|
e6cf4d3e07 | ||
|
|
cc5098c4bc | ||
|
|
025e606db4 | ||
|
|
d3e8bacd58 | ||
|
|
308b21bb33 | ||
|
|
262c1d7fcb | ||
|
|
722c3a0e83 | ||
|
|
f885b49daf | ||
|
|
6731c465e7 | ||
|
|
28811c46d8 | ||
|
|
599cf17c9e | ||
|
|
f0af36b59e | ||
|
|
e73e2739c1 | ||
|
|
efdeacf01a | ||
|
|
3a829ad53b | ||
|
|
605de595b1 | ||
|
|
daf22b7f15 | ||
|
|
0e8ebaa885 | ||
|
|
829fa29cf1 | ||
|
|
ddb46f9dda | ||
|
|
df1f216b5b | ||
|
|
b8b94dfd77 | ||
|
|
4489096e57 | ||
|
|
9cdc59b272 | ||
|
|
75326b1ddd | ||
|
|
7d8dd523a2 | ||
|
|
993ca36755 | ||
|
|
faad7cb6d7 | ||
|
|
97d692910b | ||
|
|
b546cf3ad0 | ||
|
|
6353f0139b | ||
|
|
1e67e9333e | ||
|
|
6f054ee594 | ||
|
|
05d43f38ce | ||
|
|
b8ab077b57 |
199
.github/workflows/release.yml
vendored
199
.github/workflows/release.yml
vendored
@@ -6,7 +6,7 @@ on:
|
||||
- "v[0-9]*"
|
||||
|
||||
jobs:
|
||||
goreleaser:
|
||||
prepare-ui:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -19,33 +19,186 @@ jobs:
|
||||
with:
|
||||
node-version: 20.11.0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: "go.mod"
|
||||
|
||||
- name: Install upx (optional)
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y upx
|
||||
|
||||
- name: Build WebUI
|
||||
run: |
|
||||
npm --prefix=./ui ci
|
||||
npm --prefix=./ui run build
|
||||
npm cache clean --force
|
||||
rm -rf ./ui/node_modules
|
||||
|
||||
- name: Check disk usage
|
||||
run: |
|
||||
df -h
|
||||
du -sh /opt/hostedtoolcache/go/*
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v5
|
||||
- name: Upload UI build artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
distribution: goreleaser
|
||||
version: latest
|
||||
args: release --clean
|
||||
name: ui-build
|
||||
path: ./ui/dist
|
||||
retention-days: 1
|
||||
|
||||
build-linux:
|
||||
needs: prepare-ui
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: "go.mod"
|
||||
|
||||
- name: Download UI build artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ui-build
|
||||
path: ./ui/dist
|
||||
|
||||
- name: Build Linux binaries
|
||||
env:
|
||||
CGO_ENABLED: 0
|
||||
GOOS: linux
|
||||
run: |
|
||||
mkdir -p dist/linux
|
||||
for ARCH in amd64 arm64 armv7; do
|
||||
if [ "$ARCH" == "armv7" ]; then
|
||||
export GOARM=7
|
||||
fi
|
||||
go build -ldflags="-s -w -X github.com/usual2970/certimate.Version=${GITHUB_REF#refs/tags/}" -o dist/linux/certimate_${GITHUB_REF#refs/tags/}_linux_$ARCH
|
||||
done
|
||||
|
||||
- name: Upload Linux binaries
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: linux-binaries
|
||||
path: dist/linux/
|
||||
retention-days: 1
|
||||
|
||||
build-macos:
|
||||
needs: prepare-ui
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: "go.mod"
|
||||
|
||||
- name: Download UI build artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ui-build
|
||||
path: ./ui/dist
|
||||
|
||||
- name: Build macOS binaries
|
||||
env:
|
||||
CGO_ENABLED: 0
|
||||
GOOS: darwin
|
||||
run: |
|
||||
mkdir -p dist/darwin
|
||||
for ARCH in amd64 arm64; do
|
||||
go build -ldflags="-s -w -X github.com/usual2970/certimate.Version=${GITHUB_REF#refs/tags/}" -o dist/darwin/certimate_${GITHUB_REF#refs/tags/}_darwin_$ARCH
|
||||
done
|
||||
|
||||
- name: Upload macOS binaries
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: macos-binaries
|
||||
path: dist/darwin/
|
||||
retention-days: 1
|
||||
|
||||
build-windows:
|
||||
needs: prepare-ui
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: "go.mod"
|
||||
|
||||
- name: Download UI build artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ui-build
|
||||
path: ./ui/dist
|
||||
|
||||
- name: Build Windows binaries
|
||||
env:
|
||||
CGO_ENABLED: 0
|
||||
GOOS: windows
|
||||
run: |
|
||||
mkdir -p dist/windows
|
||||
for ARCH in amd64 arm64; do
|
||||
go build -ldflags="-s -w -X github.com/usual2970/certimate.Version=${GITHUB_REF#refs/tags/}" -o dist/windows/certimate_${GITHUB_REF#refs/tags/}_windows_$ARCH.exe
|
||||
done
|
||||
|
||||
- name: Upload Windows binaries
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: windows-binaries
|
||||
path: dist/windows/
|
||||
retention-days: 1
|
||||
|
||||
create-release:
|
||||
needs: [build-linux, build-macos, build-windows]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download all binaries
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ./artifacts
|
||||
|
||||
- name: Prepare release assets
|
||||
run: |
|
||||
mkdir -p dist
|
||||
cp -r artifacts/linux-binaries/* dist/
|
||||
cp -r artifacts/macos-binaries/* dist/
|
||||
cp -r artifacts/windows-binaries/* dist/
|
||||
|
||||
find dist -type f -not -name "*.exe" -exec chmod +x {} \;
|
||||
|
||||
# 为每个二进制文件创建 zip 包
|
||||
cd dist
|
||||
for bin in certimate_*; do
|
||||
if [[ "$bin" == *".exe" ]]; then
|
||||
entrypoint="certimate.exe"
|
||||
else
|
||||
entrypoint="certimate"
|
||||
fi
|
||||
|
||||
tmpdir=$(mktemp -d)
|
||||
cp "$bin" "${tmpdir}/${entrypoint}"
|
||||
cp ../README.md ../LICENSE.md ../CHANGELOG.md "$tmpdir"
|
||||
|
||||
if [[ "$bin" == *".exe" ]]; then
|
||||
zip -j "${bin%.exe}.zip" "$tmpdir"/*
|
||||
else
|
||||
zip -j -X "${bin}.zip" "$tmpdir"/*
|
||||
fi
|
||||
|
||||
rm -rf "$tmpdir"
|
||||
done
|
||||
|
||||
# 创建校验和文件
|
||||
sha256sum *.zip > checksums.txt
|
||||
|
||||
- name: Create Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: |
|
||||
dist/*.zip
|
||||
dist/checksums.txt
|
||||
draft: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
|
||||
@@ -30,8 +30,8 @@ builds:
|
||||
- goos: darwin
|
||||
goarch: arm
|
||||
|
||||
upx:
|
||||
- enabled: true
|
||||
# upx:
|
||||
# - enabled: true
|
||||
|
||||
release:
|
||||
draft: true
|
||||
|
||||
@@ -35,6 +35,8 @@ git clone https://github.com/your_username/certimate.git
|
||||
|
||||
这将启动一个 Web 服务器,默认运行在 `http://localhost:8090`,并使用来自 `ui/dist` 的预构建管理页面。
|
||||
|
||||
> 如果你遇到报错 `ui/embed.go:10:12: pattern all:dist: no matching files found` 请先参考 [构建 Admin UI](#修改管理页面-admin-ui)
|
||||
|
||||
**在向主仓库提交 PR 之前,建议你:**
|
||||
|
||||
- 使用 [gofumpt](https://github.com/mvdan/gofumpt) 对你的代码进行格式化。
|
||||
|
||||
@@ -36,6 +36,8 @@ Once you have made changes to the Go code in Certimate, follow these steps to ru
|
||||
|
||||
This will start a web server at `http://localhost:8090` using the prebuilt Admin UI located in `ui/dist`.
|
||||
|
||||
> if you encounter an error `ui/embed.go:10:12: pattern all:dist: no matching files found`, please refer to [build Admin UI](#making-changes-in-the-admin-ui)
|
||||
|
||||
**Before submitting a PR to the main repository, consider:**
|
||||
|
||||
- Format your source code by using [gofumpt](https://github.com/mvdan/gofumpt).
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
做个人产品或者在中小企业里负责运维的同学,会遇到要管理多个域名的情况,需要给域名申请证书。但是手动申请证书有以下缺点:
|
||||
|
||||
- 😱 麻烦:申请证书并部署到服务的流程虽不复杂,但也挺麻烦的,犹其是你有多个域名需要维护的时候。
|
||||
- 😱 麻烦:申请证书并部署到服务的流程虽不复杂,但也挺麻烦的,尤其是你有多个域名需要维护的时候。
|
||||
- 😭 易忘:另外当前免费证书的有效期只有 90 天,这就要求你定期的操作,增加了工作量的同时,你也很容易忘掉续期,从而导致网站访问不了。
|
||||
|
||||
Certimate 就是为了解决上述问题而产生的,它具有以下优势:
|
||||
@@ -39,7 +39,7 @@ Certimate 旨在为用户提供一个安全、简便的 SSL 证书管理解决
|
||||
- 支持单域名、多域名、泛域名证书,可选 RSA、ECC 签名算法;
|
||||
- 支持 PEM、PFX、JKS 等多种格式输出证书;
|
||||
- 支持 30+ 域名托管商(如阿里云、腾讯云、Cloudflare 等,[点此查看完整清单](https://docs.certimate.me/docs/reference/providers#supported-dns-providers));
|
||||
- 支持 90+ 部署目标(如 Kubernetes、CDN、WAF、负载均衡等,[点此查看完整清单](https://docs.certimate.me/docs/reference/providers#supported-hosting-providers));
|
||||
- 支持 100+ 部署目标(如 Kubernetes、CDN、WAF、负载均衡等,[点此查看完整清单](https://docs.certimate.me/docs/reference/providers#supported-hosting-providers));
|
||||
- 支持邮件、钉钉、飞书、企业微信、Webhook 等多种通知渠道;
|
||||
- 支持 Let's Encrypt、Buypass、Google Trust Services、SSL.com、ZeroSSL 等多种 ACME 证书颁发机构;
|
||||
- 更多特性等待探索。
|
||||
|
||||
@@ -39,7 +39,7 @@ Certimate aims to provide users with a secure and user-friendly SSL certificate
|
||||
- Supports single-domain, multi-domain, wildcard certificates, with options for RSA or ECC.
|
||||
- Supports various certificate formats such as PEM, PFX, JKS.
|
||||
- Supports more than 30+ domain registrars (e.g., Alibaba Cloud, Tencent Cloud, Cloudflare, etc. [Check out this link](https://docs.certimate.me/en/docs/reference/providers#supported-dns-providers));
|
||||
- Supports more than 90+ deployment targets (e.g., Kubernetes, CDN, WAF, load balancers, etc. [Check out this link](https://docs.certimate.me/en/docs/reference/providers#supported-hosting-providers));
|
||||
- Supports more than 100+ deployment targets (e.g., Kubernetes, CDN, WAF, load balancers, etc. [Check out this link](https://docs.certimate.me/en/docs/reference/providers#supported-hosting-providers));
|
||||
- Supports multiple notification channels including email, DingTalk, Feishu, WeCom, Webhook, and more;
|
||||
- Supports multiple ACME CAs including Let's Encrypt, Buypass, Google Trust Services,SSL.com, ZeroSSL, and more;
|
||||
- More features waiting to be discovered.
|
||||
|
||||
2
go.mod
2
go.mod
@@ -30,6 +30,7 @@ require (
|
||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
|
||||
github.com/aws/aws-sdk-go-v2/service/acm v1.32.0
|
||||
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.46.1
|
||||
github.com/aws/aws-sdk-go-v2/service/iam v1.42.0
|
||||
github.com/baidubce/bce-sdk-go v0.9.228
|
||||
github.com/blinkbean/dingtalk v1.1.3
|
||||
github.com/byteplus-sdk/byteplus-sdk-golang v1.0.46
|
||||
@@ -51,6 +52,7 @@ require (
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1155
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1166
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1173
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/gaap v1.0.1163
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1150
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1172
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1169
|
||||
|
||||
5
go.sum
5
go.sum
@@ -235,6 +235,8 @@ github.com/aws/aws-sdk-go-v2/service/acm v1.32.0/go.mod h1:3sKYAgRbuBa2QMYGh/WEc
|
||||
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.46.1 h1:6xZNYtuVwzBs8k+TmraERt0vL68Ppg9aUi+aTQmPaVM=
|
||||
github.com/aws/aws-sdk-go-v2/service/cloudfront v1.46.1/go.mod h1:FIBJ48TS+qJb+Ne4qJ+0NeIhtPTVXItXooTeNeVI4Po=
|
||||
github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o=
|
||||
github.com/aws/aws-sdk-go-v2/service/iam v1.42.0 h1:G6+UzGvubaet9QOh0664E9JeT+b6Zvop3AChozRqkrA=
|
||||
github.com/aws/aws-sdk-go-v2/service/iam v1.42.0/go.mod h1:mPJkGQzeCoPs82ElNILor2JzZgYENr4UaSKUT8K27+c=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM=
|
||||
@@ -834,6 +836,7 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1166/go.mod h1
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1128/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1150/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1155/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1163/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1164/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1166/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1169/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
@@ -843,6 +846,8 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1173 h1:W5b
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1173/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1128 h1:mrJ5Fbkd7sZIJ5F6oRfh5zebPQaudPH9Y0+GUmFytYU=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1128/go.mod h1:zbsYIBT+VTX4z4ocjTAdLBIWyNYj3z0BRqd0iPdnjsk=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/gaap v1.0.1163 h1:putqrH5n1SVRqFWHOylVqYI5yLQUjRTkHqZPLT2yeVY=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/gaap v1.0.1163/go.mod h1:aEWRXlAvovPUUoS3kVB/LVWEQ19WqzTj2lXGvR1YArY=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1150 h1:RQQYfZOFYlkxKR2+xp8el3+8xs9DhxBy+ajlHtapqtQ=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1150/go.mod h1:zpfr6EBWy7ClASTGUgIy01Gn4R79UXf+2QGQeyR124A=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1172 h1:6SUO0hTie3zxnUEMxmhnS1iRIXpAukSZV27Nrx4NwIk=
|
||||
|
||||
@@ -53,35 +53,35 @@ func NewWithWorkflowNode(config ApplicantWithWorkflowNodeConfig) (Applicant, err
|
||||
return nil, fmt.Errorf("node type is not '%s'", string(domain.WorkflowNodeTypeApply))
|
||||
}
|
||||
|
||||
nodeConfig := config.Node.GetConfigForApply()
|
||||
nodeCfg := config.Node.GetConfigForApply()
|
||||
options := &applicantProviderOptions{
|
||||
Domains: sliceutil.Filter(strings.Split(nodeConfig.Domains, ";"), func(s string) bool { return s != "" }),
|
||||
ContactEmail: nodeConfig.ContactEmail,
|
||||
Provider: domain.ACMEDns01ProviderType(nodeConfig.Provider),
|
||||
Domains: sliceutil.Filter(strings.Split(nodeCfg.Domains, ";"), func(s string) bool { return s != "" }),
|
||||
ContactEmail: nodeCfg.ContactEmail,
|
||||
Provider: domain.ACMEDns01ProviderType(nodeCfg.Provider),
|
||||
ProviderAccessConfig: make(map[string]any),
|
||||
ProviderServiceConfig: nodeConfig.ProviderConfig,
|
||||
CAProvider: domain.CAProviderType(nodeConfig.CAProvider),
|
||||
ProviderServiceConfig: nodeCfg.ProviderConfig,
|
||||
CAProvider: domain.CAProviderType(nodeCfg.CAProvider),
|
||||
CAProviderAccessConfig: make(map[string]any),
|
||||
CAProviderServiceConfig: nodeConfig.CAProviderConfig,
|
||||
KeyAlgorithm: nodeConfig.KeyAlgorithm,
|
||||
Nameservers: sliceutil.Filter(strings.Split(nodeConfig.Nameservers, ";"), func(s string) bool { return s != "" }),
|
||||
DnsPropagationWait: nodeConfig.DnsPropagationWait,
|
||||
DnsPropagationTimeout: nodeConfig.DnsPropagationTimeout,
|
||||
DnsTTL: nodeConfig.DnsTTL,
|
||||
DisableFollowCNAME: nodeConfig.DisableFollowCNAME,
|
||||
CAProviderServiceConfig: nodeCfg.CAProviderConfig,
|
||||
KeyAlgorithm: nodeCfg.KeyAlgorithm,
|
||||
Nameservers: sliceutil.Filter(strings.Split(nodeCfg.Nameservers, ";"), func(s string) bool { return s != "" }),
|
||||
DnsPropagationWait: nodeCfg.DnsPropagationWait,
|
||||
DnsPropagationTimeout: nodeCfg.DnsPropagationTimeout,
|
||||
DnsTTL: nodeCfg.DnsTTL,
|
||||
DisableFollowCNAME: nodeCfg.DisableFollowCNAME,
|
||||
}
|
||||
|
||||
accessRepo := repository.NewAccessRepository()
|
||||
if nodeConfig.ProviderAccessId != "" {
|
||||
if access, err := accessRepo.GetById(context.Background(), nodeConfig.ProviderAccessId); err != nil {
|
||||
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeConfig.ProviderAccessId, err)
|
||||
if nodeCfg.ProviderAccessId != "" {
|
||||
if access, err := accessRepo.GetById(context.Background(), nodeCfg.ProviderAccessId); err != nil {
|
||||
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeCfg.ProviderAccessId, err)
|
||||
} else {
|
||||
options.ProviderAccessConfig = access.Config
|
||||
}
|
||||
}
|
||||
if nodeConfig.CAProviderAccessId != "" {
|
||||
if access, err := accessRepo.GetById(context.Background(), nodeConfig.CAProviderAccessId); err != nil {
|
||||
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeConfig.CAProviderAccessId, err)
|
||||
if nodeCfg.CAProviderAccessId != "" {
|
||||
if access, err := accessRepo.GetById(context.Background(), nodeCfg.CAProviderAccessId); err != nil {
|
||||
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeCfg.CAProviderAccessId, err)
|
||||
} else {
|
||||
options.CAProviderAccessId = access.Id
|
||||
options.CAProviderAccessConfig = access.Config
|
||||
|
||||
@@ -16,6 +16,8 @@ import (
|
||||
pCloudflare "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/cloudflare"
|
||||
pClouDNS "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/cloudns"
|
||||
pCMCCCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/cmcccloud"
|
||||
pConstellix "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/constellix"
|
||||
pCTCCCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/ctcccloud"
|
||||
pDeSEC "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/desec"
|
||||
pDigitalOcean "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/digitalocean"
|
||||
pDNSLA "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/dnsla"
|
||||
@@ -38,6 +40,7 @@ import (
|
||||
pRainYun "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/rainyun"
|
||||
pTencentCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/tencentcloud"
|
||||
pTencentCloudEO "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/tencentcloud-eo"
|
||||
pUCloudUDNR "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/ucloud-udnr"
|
||||
pVercel "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/vercel"
|
||||
pVolcEngine "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/volcengine"
|
||||
pWestcn "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/westcn"
|
||||
@@ -218,7 +221,7 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi
|
||||
return applicant, err
|
||||
}
|
||||
|
||||
case domain.ACMEDns01ProviderTypeCMCCCloud:
|
||||
case domain.ACMEDns01ProviderTypeCMCCCloud, domain.ACMEDns01ProviderTypeCMCCCloudDNS:
|
||||
{
|
||||
access := domain.AccessConfigForCMCCCloud{}
|
||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||
@@ -234,6 +237,38 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi
|
||||
return applicant, err
|
||||
}
|
||||
|
||||
case domain.ACMEDns01ProviderTypeConstellix:
|
||||
{
|
||||
access := domain.AccessConfigForConstellix{}
|
||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||
}
|
||||
|
||||
applicant, err := pConstellix.NewChallengeProvider(&pConstellix.ChallengeProviderConfig{
|
||||
ApiKey: access.ApiKey,
|
||||
SecretKey: access.SecretKey,
|
||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||
DnsTTL: options.DnsTTL,
|
||||
})
|
||||
return applicant, err
|
||||
}
|
||||
|
||||
case domain.ACMEDns01ProviderTypeCTCCCloud, domain.ACMEDns01ProviderTypeCTCCCloudSmartDNS:
|
||||
{
|
||||
access := domain.AccessConfigForCTCCCloud{}
|
||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||
}
|
||||
|
||||
applicant, err := pCTCCCloud.NewChallengeProvider(&pCTCCCloud.ChallengeProviderConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||
DnsTTL: options.DnsTTL,
|
||||
})
|
||||
return applicant, err
|
||||
}
|
||||
|
||||
case domain.ACMEDns01ProviderTypeDeSEC:
|
||||
{
|
||||
access := domain.AccessConfigForDeSEC{}
|
||||
@@ -579,6 +614,22 @@ func createApplicantProvider(options *applicantProviderOptions) (challenge.Provi
|
||||
}
|
||||
}
|
||||
|
||||
case domain.ACMEDns01ProviderTypeUCloudUDNR:
|
||||
{
|
||||
access := domain.AccessConfigForUCloud{}
|
||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||
}
|
||||
|
||||
applicant, err := pUCloudUDNR.NewChallengeProvider(&pUCloudUDNR.ChallengeProviderConfig{
|
||||
PrivateKey: access.PrivateKey,
|
||||
PublicKey: access.PublicKey,
|
||||
DnsPropagationTimeout: options.DnsPropagationTimeout,
|
||||
DnsTTL: options.DnsTTL,
|
||||
})
|
||||
return applicant, err
|
||||
}
|
||||
|
||||
case domain.ACMEDns01ProviderTypeVercel:
|
||||
{
|
||||
access := domain.AccessConfigForVercel{}
|
||||
|
||||
@@ -29,18 +29,18 @@ func NewWithWorkflowNode(config DeployerWithWorkflowNodeConfig) (Deployer, error
|
||||
return nil, fmt.Errorf("node type is not '%s'", string(domain.WorkflowNodeTypeDeploy))
|
||||
}
|
||||
|
||||
nodeConfig := config.Node.GetConfigForDeploy()
|
||||
nodeCfg := config.Node.GetConfigForDeploy()
|
||||
options := &deployerProviderOptions{
|
||||
Provider: domain.DeploymentProviderType(nodeConfig.Provider),
|
||||
Provider: domain.DeploymentProviderType(nodeCfg.Provider),
|
||||
ProviderAccessConfig: make(map[string]any),
|
||||
ProviderServiceConfig: nodeConfig.ProviderConfig,
|
||||
ProviderServiceConfig: nodeCfg.ProviderConfig,
|
||||
}
|
||||
|
||||
accessRepo := repository.NewAccessRepository()
|
||||
if nodeConfig.ProviderAccessId != "" {
|
||||
access, err := accessRepo.GetById(context.Background(), nodeConfig.ProviderAccessId)
|
||||
if nodeCfg.ProviderAccessId != "" {
|
||||
access, err := accessRepo.GetById(context.Background(), nodeCfg.ProviderAccessId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeConfig.ProviderAccessId, err)
|
||||
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeCfg.ProviderAccessId, err)
|
||||
} else {
|
||||
options.ProviderAccessConfig = access.Config
|
||||
}
|
||||
|
||||
@@ -25,8 +25,10 @@ import (
|
||||
pAliyunOSS "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-oss"
|
||||
pAliyunVOD "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-vod"
|
||||
pAliyunWAF "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-waf"
|
||||
pAPISIX "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/apisix"
|
||||
pAWSACM "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aws-acm"
|
||||
pAWSCloudFront "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aws-cloudfront"
|
||||
pAWSIAM "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aws-iam"
|
||||
pAzureKeyVault "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/azure-keyvault"
|
||||
pBaiduCloudAppBLB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baiducloud-appblb"
|
||||
pBaiduCloudBLB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baiducloud-blb"
|
||||
@@ -41,6 +43,12 @@ import (
|
||||
pBytePlusCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/byteplus-cdn"
|
||||
pCacheFly "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/cachefly"
|
||||
pCdnfly "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/cdnfly"
|
||||
pCTCCCloudAO "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-ao"
|
||||
pCTCCCloudCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-cdn"
|
||||
pCTCCCloudCMS "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-cms"
|
||||
pCTCCCloudELB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-elb"
|
||||
pCTCCCloudICDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-icdn"
|
||||
pCTCCCloudLVDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-lvdn"
|
||||
pDogeCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/dogecloud-cdn"
|
||||
pEdgioApplications "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/edgio-applications"
|
||||
pFlexCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/flexcdn"
|
||||
@@ -72,6 +80,7 @@ import (
|
||||
pTencentCloudCSS "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-css"
|
||||
pTencentCloudECDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-ecdn"
|
||||
pTencentCloudEO "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-eo"
|
||||
pTencentCloudGAAP "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-gaap"
|
||||
pTencentCloudSCF "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-scf"
|
||||
pTencentCloudSSL "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-ssl"
|
||||
pTencentCloudSSLDeploy "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-ssl-deploy"
|
||||
@@ -157,6 +166,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
||||
deployer, err := pAliyunALB.NewDeployer(&pAliyunALB.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
AccessKeySecret: access.AccessKeySecret,
|
||||
ResourceGroupId: access.ResourceGroupId,
|
||||
Region: maputil.GetString(options.ProviderServiceConfig, "region"),
|
||||
ResourceType: pAliyunALB.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
|
||||
LoadbalancerId: maputil.GetString(options.ProviderServiceConfig, "loadbalancerId"),
|
||||
@@ -169,6 +179,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
||||
deployer, err := pAliyunAPIGW.NewDeployer(&pAliyunAPIGW.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
AccessKeySecret: access.AccessKeySecret,
|
||||
ResourceGroupId: access.ResourceGroupId,
|
||||
Region: maputil.GetString(options.ProviderServiceConfig, "region"),
|
||||
ServiceType: pAliyunAPIGW.ServiceType(maputil.GetString(options.ProviderServiceConfig, "serviceType")),
|
||||
GatewayId: maputil.GetString(options.ProviderServiceConfig, "gatewayId"),
|
||||
@@ -181,6 +192,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
||||
deployer, err := pAliyunCAS.NewDeployer(&pAliyunCAS.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
AccessKeySecret: access.AccessKeySecret,
|
||||
ResourceGroupId: access.ResourceGroupId,
|
||||
Region: maputil.GetString(options.ProviderServiceConfig, "region"),
|
||||
})
|
||||
return deployer, err
|
||||
@@ -189,6 +201,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
||||
deployer, err := pAliyunCASDeploy.NewDeployer(&pAliyunCASDeploy.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
AccessKeySecret: access.AccessKeySecret,
|
||||
ResourceGroupId: access.ResourceGroupId,
|
||||
Region: maputil.GetString(options.ProviderServiceConfig, "region"),
|
||||
ResourceIds: sliceutil.Filter(strings.Split(maputil.GetString(options.ProviderServiceConfig, "resourceIds"), ";"), func(s string) bool { return s != "" }),
|
||||
ContactIds: sliceutil.Filter(strings.Split(maputil.GetString(options.ProviderServiceConfig, "contactIds"), ";"), func(s string) bool { return s != "" }),
|
||||
@@ -199,6 +212,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
||||
deployer, err := pAliyunCDN.NewDeployer(&pAliyunCDN.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
AccessKeySecret: access.AccessKeySecret,
|
||||
ResourceGroupId: access.ResourceGroupId,
|
||||
Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
|
||||
})
|
||||
return deployer, err
|
||||
@@ -207,6 +221,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
||||
deployer, err := pAliyunCLB.NewDeployer(&pAliyunCLB.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
AccessKeySecret: access.AccessKeySecret,
|
||||
ResourceGroupId: access.ResourceGroupId,
|
||||
Region: maputil.GetString(options.ProviderServiceConfig, "region"),
|
||||
ResourceType: pAliyunCLB.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
|
||||
LoadbalancerId: maputil.GetString(options.ProviderServiceConfig, "loadbalancerId"),
|
||||
@@ -219,6 +234,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
||||
deployer, err := pAliyunDCDN.NewDeployer(&pAliyunDCDN.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
AccessKeySecret: access.AccessKeySecret,
|
||||
ResourceGroupId: access.ResourceGroupId,
|
||||
Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
|
||||
})
|
||||
return deployer, err
|
||||
@@ -227,6 +243,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
||||
deployer, err := pAliyunDDoS.NewDeployer(&pAliyunDDoS.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
AccessKeySecret: access.AccessKeySecret,
|
||||
ResourceGroupId: access.ResourceGroupId,
|
||||
Region: maputil.GetString(options.ProviderServiceConfig, "region"),
|
||||
Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
|
||||
})
|
||||
@@ -245,6 +262,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
||||
deployer, err := pAliyunFC.NewDeployer(&pAliyunFC.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
AccessKeySecret: access.AccessKeySecret,
|
||||
ResourceGroupId: access.ResourceGroupId,
|
||||
Region: maputil.GetString(options.ProviderServiceConfig, "region"),
|
||||
ServiceVersion: maputil.GetOrDefaultString(options.ProviderServiceConfig, "serviceVersion", "3.0"),
|
||||
Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
|
||||
@@ -255,6 +273,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
||||
deployer, err := pAliyunGA.NewDeployer(&pAliyunGA.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
AccessKeySecret: access.AccessKeySecret,
|
||||
ResourceGroupId: access.ResourceGroupId,
|
||||
ResourceType: pAliyunGA.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
|
||||
AcceleratorId: maputil.GetString(options.ProviderServiceConfig, "acceleratorId"),
|
||||
ListenerId: maputil.GetString(options.ProviderServiceConfig, "listenerId"),
|
||||
@@ -275,6 +294,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
||||
deployer, err := pAliyunNLB.NewDeployer(&pAliyunNLB.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
AccessKeySecret: access.AccessKeySecret,
|
||||
ResourceGroupId: access.ResourceGroupId,
|
||||
Region: maputil.GetString(options.ProviderServiceConfig, "region"),
|
||||
ResourceType: pAliyunNLB.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
|
||||
LoadbalancerId: maputil.GetString(options.ProviderServiceConfig, "loadbalancerId"),
|
||||
@@ -286,6 +306,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
||||
deployer, err := pAliyunOSS.NewDeployer(&pAliyunOSS.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
AccessKeySecret: access.AccessKeySecret,
|
||||
ResourceGroupId: access.ResourceGroupId,
|
||||
Region: maputil.GetString(options.ProviderServiceConfig, "region"),
|
||||
Bucket: maputil.GetString(options.ProviderServiceConfig, "bucket"),
|
||||
Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
|
||||
@@ -296,6 +317,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
||||
deployer, err := pAliyunVOD.NewDeployer(&pAliyunVOD.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
AccessKeySecret: access.AccessKeySecret,
|
||||
ResourceGroupId: access.ResourceGroupId,
|
||||
Region: maputil.GetString(options.ProviderServiceConfig, "region"),
|
||||
Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
|
||||
})
|
||||
@@ -305,6 +327,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
||||
deployer, err := pAliyunWAF.NewDeployer(&pAliyunWAF.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
AccessKeySecret: access.AccessKeySecret,
|
||||
ResourceGroupId: access.ResourceGroupId,
|
||||
Region: maputil.GetString(options.ProviderServiceConfig, "region"),
|
||||
ServiceVersion: maputil.GetOrDefaultString(options.ProviderServiceConfig, "serviceVersion", "3.0"),
|
||||
InstanceId: maputil.GetString(options.ProviderServiceConfig, "instanceId"),
|
||||
@@ -317,7 +340,24 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
||||
}
|
||||
}
|
||||
|
||||
case domain.DeploymentProviderTypeAWSACM, domain.DeploymentProviderTypeAWSCloudFront:
|
||||
case domain.DeploymentProviderTypeAPISIX:
|
||||
{
|
||||
access := domain.AccessConfigForAPISIX{}
|
||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||
}
|
||||
|
||||
deployer, err := pAPISIX.NewDeployer(&pAPISIX.DeployerConfig{
|
||||
ServerUrl: access.ServerUrl,
|
||||
ApiKey: access.ApiKey,
|
||||
AllowInsecureConnections: access.AllowInsecureConnections,
|
||||
ResourceType: pAPISIX.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
|
||||
CertificateId: maputil.GetString(options.ProviderServiceConfig, "certificateId"),
|
||||
})
|
||||
return deployer, err
|
||||
}
|
||||
|
||||
case domain.DeploymentProviderTypeAWSACM, domain.DeploymentProviderTypeAWSCloudFront, domain.DeploymentProviderTypeAWSIAM:
|
||||
{
|
||||
access := domain.AccessConfigForAWS{}
|
||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||
@@ -336,10 +376,20 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
||||
|
||||
case domain.DeploymentProviderTypeAWSCloudFront:
|
||||
deployer, err := pAWSCloudFront.NewDeployer(&pAWSCloudFront.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
Region: maputil.GetString(options.ProviderServiceConfig, "region"),
|
||||
DistributionId: maputil.GetString(options.ProviderServiceConfig, "distributionId"),
|
||||
CertificateSource: maputil.GetOrDefaultString(options.ProviderServiceConfig, "certificateSource", "ACM"),
|
||||
})
|
||||
return deployer, err
|
||||
|
||||
case domain.DeploymentProviderTypeAWSIAM:
|
||||
deployer, err := pAWSIAM.NewDeployer(&pAWSIAM.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
Region: maputil.GetString(options.ProviderServiceConfig, "region"),
|
||||
DistributionId: maputil.GetString(options.ProviderServiceConfig, "distributionId"),
|
||||
CertificatePath: maputil.GetOrDefaultString(options.ProviderServiceConfig, "certificatePath", "/"),
|
||||
})
|
||||
return deployer, err
|
||||
|
||||
@@ -577,6 +627,69 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
||||
return deployer, err
|
||||
}
|
||||
|
||||
case domain.DeploymentProviderTypeCTCCCloudAO, domain.DeploymentProviderTypeCTCCCloudCDN, domain.DeploymentProviderTypeCTCCCloudCMS, domain.DeploymentProviderTypeCTCCCloudELB, domain.DeploymentProviderTypeCTCCCloudICDN, domain.DeploymentProviderTypeCTCCCloudLVDN:
|
||||
{
|
||||
access := domain.AccessConfigForCTCCCloud{}
|
||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||
}
|
||||
|
||||
switch options.Provider {
|
||||
case domain.DeploymentProviderTypeCTCCCloudAO:
|
||||
deployer, err := pCTCCCloudAO.NewDeployer(&pCTCCCloudAO.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
|
||||
})
|
||||
return deployer, err
|
||||
|
||||
case domain.DeploymentProviderTypeCTCCCloudCDN:
|
||||
deployer, err := pCTCCCloudCDN.NewDeployer(&pCTCCCloudCDN.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
|
||||
})
|
||||
return deployer, err
|
||||
|
||||
case domain.DeploymentProviderTypeCTCCCloudCMS:
|
||||
deployer, err := pCTCCCloudCMS.NewDeployer(&pCTCCCloudCMS.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
})
|
||||
return deployer, err
|
||||
|
||||
case domain.DeploymentProviderTypeCTCCCloudELB:
|
||||
deployer, err := pCTCCCloudELB.NewDeployer(&pCTCCCloudELB.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
RegionId: maputil.GetString(options.ProviderServiceConfig, "regionId"),
|
||||
ResourceType: pCTCCCloudELB.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
|
||||
LoadbalancerId: maputil.GetString(options.ProviderServiceConfig, "loadbalancerId"),
|
||||
ListenerId: maputil.GetString(options.ProviderServiceConfig, "listenerId"),
|
||||
})
|
||||
return deployer, err
|
||||
|
||||
case domain.DeploymentProviderTypeCTCCCloudICDN:
|
||||
deployer, err := pCTCCCloudICDN.NewDeployer(&pCTCCCloudICDN.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
|
||||
})
|
||||
return deployer, err
|
||||
|
||||
case domain.DeploymentProviderTypeCTCCCloudLVDN:
|
||||
deployer, err := pCTCCCloudLVDN.NewDeployer(&pCTCCCloudLVDN.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
|
||||
})
|
||||
return deployer, err
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
case domain.DeploymentProviderTypeDogeCloudCDN:
|
||||
{
|
||||
access := domain.AccessConfigForDogeCloud{}
|
||||
@@ -676,40 +789,44 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
||||
switch options.Provider {
|
||||
case domain.DeploymentProviderTypeHuaweiCloudCDN:
|
||||
deployer, err := pHuaweiCloudCDN.NewDeployer(&pHuaweiCloudCDN.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
Region: maputil.GetString(options.ProviderServiceConfig, "region"),
|
||||
Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
EnterpriseProjectId: access.EnterpriseProjectId,
|
||||
Region: maputil.GetString(options.ProviderServiceConfig, "region"),
|
||||
Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
|
||||
})
|
||||
return deployer, err
|
||||
|
||||
case domain.DeploymentProviderTypeHuaweiCloudELB:
|
||||
deployer, err := pHuaweiCloudELB.NewDeployer(&pHuaweiCloudELB.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
Region: maputil.GetString(options.ProviderServiceConfig, "region"),
|
||||
ResourceType: pHuaweiCloudELB.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
|
||||
CertificateId: maputil.GetString(options.ProviderServiceConfig, "certificateId"),
|
||||
LoadbalancerId: maputil.GetString(options.ProviderServiceConfig, "loadbalancerId"),
|
||||
ListenerId: maputil.GetString(options.ProviderServiceConfig, "listenerId"),
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
EnterpriseProjectId: access.EnterpriseProjectId,
|
||||
Region: maputil.GetString(options.ProviderServiceConfig, "region"),
|
||||
ResourceType: pHuaweiCloudELB.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
|
||||
CertificateId: maputil.GetString(options.ProviderServiceConfig, "certificateId"),
|
||||
LoadbalancerId: maputil.GetString(options.ProviderServiceConfig, "loadbalancerId"),
|
||||
ListenerId: maputil.GetString(options.ProviderServiceConfig, "listenerId"),
|
||||
})
|
||||
return deployer, err
|
||||
|
||||
case domain.DeploymentProviderTypeHuaweiCloudSCM:
|
||||
deployer, err := pHuaweiCloudSCM.NewDeployer(&pHuaweiCloudSCM.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
EnterpriseProjectId: access.EnterpriseProjectId,
|
||||
})
|
||||
return deployer, err
|
||||
|
||||
case domain.DeploymentProviderTypeHuaweiCloudWAF:
|
||||
deployer, err := pHuaweiCloudWAF.NewDeployer(&pHuaweiCloudWAF.DeployerConfig{
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
Region: maputil.GetString(options.ProviderServiceConfig, "region"),
|
||||
ResourceType: pHuaweiCloudWAF.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
|
||||
CertificateId: maputil.GetString(options.ProviderServiceConfig, "certificateId"),
|
||||
Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
|
||||
AccessKeyId: access.AccessKeyId,
|
||||
SecretAccessKey: access.SecretAccessKey,
|
||||
EnterpriseProjectId: access.EnterpriseProjectId,
|
||||
Region: maputil.GetString(options.ProviderServiceConfig, "region"),
|
||||
ResourceType: pHuaweiCloudWAF.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
|
||||
CertificateId: maputil.GetString(options.ProviderServiceConfig, "certificateId"),
|
||||
Domain: maputil.GetString(options.ProviderServiceConfig, "domain"),
|
||||
})
|
||||
return deployer, err
|
||||
|
||||
@@ -968,6 +1085,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
||||
jumpServers[i] = pSSH.JumpServerConfig{
|
||||
SshHost: jumpServer.Host,
|
||||
SshPort: jumpServer.Port,
|
||||
SshAuthMethod: jumpServer.AuthMethod,
|
||||
SshUsername: jumpServer.Username,
|
||||
SshPassword: jumpServer.Password,
|
||||
SshKey: jumpServer.Key,
|
||||
@@ -978,6 +1096,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
||||
deployer, err := pSSH.NewDeployer(&pSSH.DeployerConfig{
|
||||
SshHost: access.Host,
|
||||
SshPort: access.Port,
|
||||
SshAuthMethod: access.AuthMethod,
|
||||
SshUsername: access.Username,
|
||||
SshPassword: access.Password,
|
||||
SshKey: access.Key,
|
||||
@@ -999,7 +1118,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
||||
return deployer, err
|
||||
}
|
||||
|
||||
case domain.DeploymentProviderTypeTencentCloudCDN, domain.DeploymentProviderTypeTencentCloudCLB, domain.DeploymentProviderTypeTencentCloudCOS, domain.DeploymentProviderTypeTencentCloudCSS, domain.DeploymentProviderTypeTencentCloudECDN, domain.DeploymentProviderTypeTencentCloudEO, domain.DeploymentProviderTypeTencentCloudSCF, domain.DeploymentProviderTypeTencentCloudSSL, domain.DeploymentProviderTypeTencentCloudSSLDeploy, domain.DeploymentProviderTypeTencentCloudVOD, domain.DeploymentProviderTypeTencentCloudWAF:
|
||||
case domain.DeploymentProviderTypeTencentCloudCDN, domain.DeploymentProviderTypeTencentCloudCLB, domain.DeploymentProviderTypeTencentCloudCOS, domain.DeploymentProviderTypeTencentCloudCSS, domain.DeploymentProviderTypeTencentCloudECDN, domain.DeploymentProviderTypeTencentCloudEO, domain.DeploymentProviderTypeTencentCloudGAAP, domain.DeploymentProviderTypeTencentCloudSCF, domain.DeploymentProviderTypeTencentCloudSSL, domain.DeploymentProviderTypeTencentCloudSSLDeploy, domain.DeploymentProviderTypeTencentCloudVOD, domain.DeploymentProviderTypeTencentCloudWAF:
|
||||
{
|
||||
access := domain.AccessConfigForTencentCloud{}
|
||||
if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil {
|
||||
@@ -1062,6 +1181,16 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer
|
||||
})
|
||||
return deployer, err
|
||||
|
||||
case domain.DeploymentProviderTypeTencentCloudGAAP:
|
||||
deployer, err := pTencentCloudGAAP.NewDeployer(&pTencentCloudGAAP.DeployerConfig{
|
||||
SecretId: access.SecretId,
|
||||
SecretKey: access.SecretKey,
|
||||
ResourceType: pTencentCloudGAAP.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")),
|
||||
ProxyId: maputil.GetString(options.ProviderServiceConfig, "proxyId"),
|
||||
ListenerId: maputil.GetString(options.ProviderServiceConfig, "listenerId"),
|
||||
})
|
||||
return deployer, err
|
||||
|
||||
case domain.DeploymentProviderTypeTencentCloudSCF:
|
||||
deployer, err := pTencentCloudSCF.NewDeployer(&pTencentCloudSCF.DeployerConfig{
|
||||
SecretId: access.SecretId,
|
||||
|
||||
@@ -38,6 +38,13 @@ type AccessConfigForACMEHttpReq struct {
|
||||
type AccessConfigForAliyun struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||
}
|
||||
|
||||
type AccessConfigForAPISIX struct {
|
||||
ServerUrl string `json:"serverUrl"`
|
||||
ApiKey string `json:"apiKey"`
|
||||
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||
}
|
||||
|
||||
type AccessConfigForAWS struct {
|
||||
@@ -108,6 +115,16 @@ type AccessConfigForCMCCCloud struct {
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
}
|
||||
|
||||
type AccessConfigForConstellix struct {
|
||||
ApiKey string `json:"apiKey"`
|
||||
SecretKey string `json:"secretKey"`
|
||||
}
|
||||
|
||||
type AccessConfigForCTCCCloud struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
}
|
||||
|
||||
type AccessConfigForDeSEC struct {
|
||||
Token string `json:"token"`
|
||||
}
|
||||
@@ -156,6 +173,7 @@ type AccessConfigForEmail struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
DefaultSenderAddress string `json:"defaultSenderAddress,omitempty"`
|
||||
DefaultSenderName string `json:"defaultSenderName,omitempty"`
|
||||
DefaultReceiverAddress string `json:"defaultReceiverAddress,omitempty"`
|
||||
}
|
||||
|
||||
@@ -199,8 +217,9 @@ type AccessConfigForHetzner struct {
|
||||
}
|
||||
|
||||
type AccessConfigForHuaweiCloud struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
EnterpriseProjectId string `json:"enterpriseProjectId,omitempty"`
|
||||
}
|
||||
|
||||
type AccessConfigForJDCloud struct {
|
||||
@@ -308,14 +327,16 @@ type AccessConfigForSlackBot struct {
|
||||
type AccessConfigForSSH struct {
|
||||
Host string `json:"host"`
|
||||
Port int32 `json:"port"`
|
||||
Username string `json:"username"`
|
||||
AuthMethod string `json:"authMethod,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
KeyPassphrase string `json:"keyPassphrase,omitempty"`
|
||||
JumpServers []struct {
|
||||
Host string `json:"host"`
|
||||
Port int32 `json:"port"`
|
||||
Username string `json:"username"`
|
||||
AuthMethod string `json:"authMethod,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
KeyPassphrase string `json:"keyPassphrase,omitempty"`
|
||||
@@ -384,7 +405,7 @@ type AccessConfigForWeComBot struct {
|
||||
|
||||
type AccessConfigForWestcn struct {
|
||||
Username string `json:"username"`
|
||||
ApiPassword string `json:"password"`
|
||||
ApiPassword string `json:"apiPassword"`
|
||||
}
|
||||
|
||||
type AccessConfigForZeroSSL struct {
|
||||
|
||||
630
internal/domain/expr/expr.go
Normal file
630
internal/domain/expr/expr.go
Normal file
@@ -0,0 +1,630 @@
|
||||
package expr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type (
|
||||
ExprType string
|
||||
ExprComparisonOperator string
|
||||
ExprLogicalOperator string
|
||||
ExprValueType string
|
||||
)
|
||||
|
||||
const (
|
||||
GreaterThan ExprComparisonOperator = "gt"
|
||||
GreaterOrEqual ExprComparisonOperator = "gte"
|
||||
LessThan ExprComparisonOperator = "lt"
|
||||
LessOrEqual ExprComparisonOperator = "lte"
|
||||
Equal ExprComparisonOperator = "eq"
|
||||
NotEqual ExprComparisonOperator = "neq"
|
||||
|
||||
And ExprLogicalOperator = "and"
|
||||
Or ExprLogicalOperator = "or"
|
||||
Not ExprLogicalOperator = "not"
|
||||
|
||||
Number ExprValueType = "number"
|
||||
String ExprValueType = "string"
|
||||
Boolean ExprValueType = "boolean"
|
||||
|
||||
ConstantExprType ExprType = "const"
|
||||
VariantExprType ExprType = "var"
|
||||
ComparisonExprType ExprType = "comparison"
|
||||
LogicalExprType ExprType = "logical"
|
||||
NotExprType ExprType = "not"
|
||||
)
|
||||
|
||||
type EvalResult struct {
|
||||
Type ExprValueType
|
||||
Value any
|
||||
}
|
||||
|
||||
func (e *EvalResult) GetFloat64() (float64, error) {
|
||||
if e.Type != Number {
|
||||
return 0, fmt.Errorf("type mismatch: %s", e.Type)
|
||||
}
|
||||
|
||||
stringValue, ok := e.Value.(string)
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("value is not a string: %v", e.Value)
|
||||
}
|
||||
|
||||
floatValue, err := strconv.ParseFloat(stringValue, 64)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to parse float64: %v", err)
|
||||
}
|
||||
return floatValue, nil
|
||||
}
|
||||
|
||||
func (e *EvalResult) GetBool() (bool, error) {
|
||||
if e.Type != Boolean {
|
||||
return false, fmt.Errorf("type mismatch: %s", e.Type)
|
||||
}
|
||||
|
||||
strValue, ok := e.Value.(string)
|
||||
if ok {
|
||||
if strValue == "true" {
|
||||
return true, nil
|
||||
} else if strValue == "false" {
|
||||
return false, nil
|
||||
}
|
||||
return false, fmt.Errorf("value is not a boolean: %v", e.Value)
|
||||
}
|
||||
|
||||
boolValue, ok := e.Value.(bool)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("value is not a boolean: %v", e.Value)
|
||||
}
|
||||
|
||||
return boolValue, nil
|
||||
}
|
||||
|
||||
func (e *EvalResult) GreaterThan(other *EvalResult) (*EvalResult, error) {
|
||||
if e.Type != other.Type {
|
||||
return nil, fmt.Errorf("type mismatch: %s vs %s", e.Type, other.Type)
|
||||
}
|
||||
|
||||
switch e.Type {
|
||||
case String:
|
||||
return &EvalResult{
|
||||
Type: Boolean,
|
||||
Value: e.Value.(string) > other.Value.(string),
|
||||
}, nil
|
||||
|
||||
case Number:
|
||||
left, err := e.GetFloat64()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
right, err := other.GetFloat64()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &EvalResult{
|
||||
Type: Boolean,
|
||||
Value: left > right,
|
||||
}, nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported value type: %s", e.Type)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *EvalResult) GreaterOrEqual(other *EvalResult) (*EvalResult, error) {
|
||||
if e.Type != other.Type {
|
||||
return nil, fmt.Errorf("type mismatch: %s vs %s", e.Type, other.Type)
|
||||
}
|
||||
|
||||
switch e.Type {
|
||||
case String:
|
||||
return &EvalResult{
|
||||
Type: Boolean,
|
||||
Value: e.Value.(string) >= other.Value.(string),
|
||||
}, nil
|
||||
|
||||
case Number:
|
||||
left, err := e.GetFloat64()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
right, err := other.GetFloat64()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &EvalResult{
|
||||
Type: Boolean,
|
||||
Value: left >= right,
|
||||
}, nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported value type: %s", e.Type)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *EvalResult) LessThan(other *EvalResult) (*EvalResult, error) {
|
||||
if e.Type != other.Type {
|
||||
return nil, fmt.Errorf("type mismatch: %s vs %s", e.Type, other.Type)
|
||||
}
|
||||
|
||||
switch e.Type {
|
||||
case String:
|
||||
return &EvalResult{
|
||||
Type: Boolean,
|
||||
Value: e.Value.(string) < other.Value.(string),
|
||||
}, nil
|
||||
|
||||
case Number:
|
||||
left, err := e.GetFloat64()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
right, err := other.GetFloat64()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &EvalResult{
|
||||
Type: Boolean,
|
||||
Value: left < right,
|
||||
}, nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported value type: %s", e.Type)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *EvalResult) LessOrEqual(other *EvalResult) (*EvalResult, error) {
|
||||
if e.Type != other.Type {
|
||||
return nil, fmt.Errorf("type mismatch: %s vs %s", e.Type, other.Type)
|
||||
}
|
||||
|
||||
switch e.Type {
|
||||
case String:
|
||||
return &EvalResult{
|
||||
Type: Boolean,
|
||||
Value: e.Value.(string) <= other.Value.(string),
|
||||
}, nil
|
||||
|
||||
case Number:
|
||||
left, err := e.GetFloat64()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
right, err := other.GetFloat64()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &EvalResult{
|
||||
Type: Boolean,
|
||||
Value: left <= right,
|
||||
}, nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported value type: %s", e.Type)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *EvalResult) Equal(other *EvalResult) (*EvalResult, error) {
|
||||
if e.Type != other.Type {
|
||||
return nil, fmt.Errorf("type mismatch: %s vs %s", e.Type, other.Type)
|
||||
}
|
||||
|
||||
switch e.Type {
|
||||
case String:
|
||||
return &EvalResult{
|
||||
Type: Boolean,
|
||||
Value: e.Value.(string) == other.Value.(string),
|
||||
}, nil
|
||||
|
||||
case Number:
|
||||
left, err := e.GetFloat64()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
right, err := other.GetFloat64()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &EvalResult{
|
||||
Type: Boolean,
|
||||
Value: left == right,
|
||||
}, nil
|
||||
|
||||
case Boolean:
|
||||
left, err := e.GetBool()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
right, err := other.GetBool()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &EvalResult{
|
||||
Type: Boolean,
|
||||
Value: left == right,
|
||||
}, nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported value type: %s", e.Type)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *EvalResult) NotEqual(other *EvalResult) (*EvalResult, error) {
|
||||
if e.Type != other.Type {
|
||||
return nil, fmt.Errorf("type mismatch: %s vs %s", e.Type, other.Type)
|
||||
}
|
||||
|
||||
switch e.Type {
|
||||
case String:
|
||||
return &EvalResult{
|
||||
Type: Boolean,
|
||||
Value: e.Value.(string) != other.Value.(string),
|
||||
}, nil
|
||||
|
||||
case Number:
|
||||
left, err := e.GetFloat64()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
right, err := other.GetFloat64()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &EvalResult{
|
||||
Type: Boolean,
|
||||
Value: left != right,
|
||||
}, nil
|
||||
|
||||
case Boolean:
|
||||
left, err := e.GetBool()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
right, err := other.GetBool()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &EvalResult{
|
||||
Type: Boolean,
|
||||
Value: left != right,
|
||||
}, nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported value type: %s", e.Type)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *EvalResult) And(other *EvalResult) (*EvalResult, error) {
|
||||
if e.Type != other.Type {
|
||||
return nil, fmt.Errorf("type mismatch: %s vs %s", e.Type, other.Type)
|
||||
}
|
||||
|
||||
switch e.Type {
|
||||
case Boolean:
|
||||
left, err := e.GetBool()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
right, err := other.GetBool()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &EvalResult{
|
||||
Type: Boolean,
|
||||
Value: left && right,
|
||||
}, nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported value type: %s", e.Type)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *EvalResult) Or(other *EvalResult) (*EvalResult, error) {
|
||||
if e.Type != other.Type {
|
||||
return nil, fmt.Errorf("type mismatch: %s vs %s", e.Type, other.Type)
|
||||
}
|
||||
|
||||
switch e.Type {
|
||||
case Boolean:
|
||||
left, err := e.GetBool()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
right, err := other.GetBool()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &EvalResult{
|
||||
Type: Boolean,
|
||||
Value: left || right,
|
||||
}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported value type: %s", e.Type)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *EvalResult) Not() (*EvalResult, error) {
|
||||
if e.Type != Boolean {
|
||||
return nil, fmt.Errorf("type mismatch: %s", e.Type)
|
||||
}
|
||||
|
||||
boolValue, err := e.GetBool()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &EvalResult{
|
||||
Type: Boolean,
|
||||
Value: !boolValue,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type Expr interface {
|
||||
GetType() ExprType
|
||||
Eval(variables map[string]map[string]any) (*EvalResult, error)
|
||||
}
|
||||
|
||||
type ExprValueSelector struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type ExprValueType `json:"type"`
|
||||
}
|
||||
|
||||
type ConstantExpr struct {
|
||||
Type ExprType `json:"type"`
|
||||
Value string `json:"value"`
|
||||
ValueType ExprValueType `json:"valueType"`
|
||||
}
|
||||
|
||||
func (c ConstantExpr) GetType() ExprType { return c.Type }
|
||||
|
||||
func (c ConstantExpr) Eval(variables map[string]map[string]any) (*EvalResult, error) {
|
||||
return &EvalResult{
|
||||
Type: c.ValueType,
|
||||
Value: c.Value,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type VariantExpr struct {
|
||||
Type ExprType `json:"type"`
|
||||
Selector ExprValueSelector `json:"selector"`
|
||||
}
|
||||
|
||||
func (v VariantExpr) GetType() ExprType { return v.Type }
|
||||
|
||||
func (v VariantExpr) Eval(variables map[string]map[string]any) (*EvalResult, error) {
|
||||
if v.Selector.Id == "" {
|
||||
return nil, fmt.Errorf("node id is empty")
|
||||
}
|
||||
if v.Selector.Name == "" {
|
||||
return nil, fmt.Errorf("name is empty")
|
||||
}
|
||||
|
||||
if _, ok := variables[v.Selector.Id]; !ok {
|
||||
return nil, fmt.Errorf("node %s not found", v.Selector.Id)
|
||||
}
|
||||
|
||||
if _, ok := variables[v.Selector.Id][v.Selector.Name]; !ok {
|
||||
return nil, fmt.Errorf("variable %s not found in node %s", v.Selector.Name, v.Selector.Id)
|
||||
}
|
||||
return &EvalResult{
|
||||
Type: v.Selector.Type,
|
||||
Value: variables[v.Selector.Id][v.Selector.Name],
|
||||
}, nil
|
||||
}
|
||||
|
||||
type ComparisonExpr struct {
|
||||
Type ExprType `json:"type"` // compare
|
||||
Operator ExprComparisonOperator `json:"operator"`
|
||||
Left Expr `json:"left"`
|
||||
Right Expr `json:"right"`
|
||||
}
|
||||
|
||||
func (c ComparisonExpr) GetType() ExprType { return c.Type }
|
||||
|
||||
func (c ComparisonExpr) Eval(variables map[string]map[string]any) (*EvalResult, error) {
|
||||
left, err := c.Left.Eval(variables)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
right, err := c.Right.Eval(variables)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch c.Operator {
|
||||
case GreaterThan:
|
||||
return left.GreaterThan(right)
|
||||
case LessThan:
|
||||
return left.LessThan(right)
|
||||
case GreaterOrEqual:
|
||||
return left.GreaterOrEqual(right)
|
||||
case LessOrEqual:
|
||||
return left.LessOrEqual(right)
|
||||
case Equal:
|
||||
return left.Equal(right)
|
||||
case NotEqual:
|
||||
return left.NotEqual(right)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown expression operator: %s", c.Operator)
|
||||
}
|
||||
}
|
||||
|
||||
type LogicalExpr struct {
|
||||
Type ExprType `json:"type"` // logical
|
||||
Operator ExprLogicalOperator `json:"operator"`
|
||||
Left Expr `json:"left"`
|
||||
Right Expr `json:"right"`
|
||||
}
|
||||
|
||||
func (l LogicalExpr) GetType() ExprType { return l.Type }
|
||||
|
||||
func (l LogicalExpr) Eval(variables map[string]map[string]any) (*EvalResult, error) {
|
||||
left, err := l.Left.Eval(variables)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
right, err := l.Right.Eval(variables)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch l.Operator {
|
||||
case And:
|
||||
return left.And(right)
|
||||
case Or:
|
||||
return left.Or(right)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown expression operator: %s", l.Operator)
|
||||
}
|
||||
}
|
||||
|
||||
type NotExpr struct {
|
||||
Type ExprType `json:"type"` // not
|
||||
Expr Expr `json:"expr"`
|
||||
}
|
||||
|
||||
func (n NotExpr) GetType() ExprType { return n.Type }
|
||||
|
||||
func (n NotExpr) Eval(variables map[string]map[string]any) (*EvalResult, error) {
|
||||
inner, err := n.Expr.Eval(variables)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return inner.Not()
|
||||
}
|
||||
|
||||
type rawExpr struct {
|
||||
Type ExprType `json:"type"`
|
||||
}
|
||||
|
||||
func MarshalExpr(e Expr) ([]byte, error) {
|
||||
return json.Marshal(e)
|
||||
}
|
||||
|
||||
func UnmarshalExpr(data []byte) (Expr, error) {
|
||||
var typ rawExpr
|
||||
if err := json.Unmarshal(data, &typ); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch typ.Type {
|
||||
case ConstantExprType:
|
||||
var e ConstantExpr
|
||||
if err := json.Unmarshal(data, &e); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e, nil
|
||||
case VariantExprType:
|
||||
var e VariantExpr
|
||||
if err := json.Unmarshal(data, &e); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e, nil
|
||||
case ComparisonExprType:
|
||||
var e ComparisonExprRaw
|
||||
if err := json.Unmarshal(data, &e); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e.ToComparisonExpr()
|
||||
case LogicalExprType:
|
||||
var e LogicalExprRaw
|
||||
if err := json.Unmarshal(data, &e); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e.ToLogicalExpr()
|
||||
case NotExprType:
|
||||
var e NotExprRaw
|
||||
if err := json.Unmarshal(data, &e); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e.ToNotExpr()
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown expression type: %s", typ.Type)
|
||||
}
|
||||
}
|
||||
|
||||
type ComparisonExprRaw struct {
|
||||
Type ExprType `json:"type"`
|
||||
Operator ExprComparisonOperator `json:"operator"`
|
||||
Left json.RawMessage `json:"left"`
|
||||
Right json.RawMessage `json:"right"`
|
||||
}
|
||||
|
||||
func (r ComparisonExprRaw) ToComparisonExpr() (ComparisonExpr, error) {
|
||||
leftExpr, err := UnmarshalExpr(r.Left)
|
||||
if err != nil {
|
||||
return ComparisonExpr{}, err
|
||||
}
|
||||
rightExpr, err := UnmarshalExpr(r.Right)
|
||||
if err != nil {
|
||||
return ComparisonExpr{}, err
|
||||
}
|
||||
return ComparisonExpr{
|
||||
Type: r.Type,
|
||||
Operator: r.Operator,
|
||||
Left: leftExpr,
|
||||
Right: rightExpr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type LogicalExprRaw struct {
|
||||
Type ExprType `json:"type"`
|
||||
Operator ExprLogicalOperator `json:"operator"`
|
||||
Left json.RawMessage `json:"left"`
|
||||
Right json.RawMessage `json:"right"`
|
||||
}
|
||||
|
||||
func (r LogicalExprRaw) ToLogicalExpr() (LogicalExpr, error) {
|
||||
left, err := UnmarshalExpr(r.Left)
|
||||
if err != nil {
|
||||
return LogicalExpr{}, err
|
||||
}
|
||||
right, err := UnmarshalExpr(r.Right)
|
||||
if err != nil {
|
||||
return LogicalExpr{}, err
|
||||
}
|
||||
return LogicalExpr{
|
||||
Type: r.Type,
|
||||
Operator: r.Operator,
|
||||
Left: left,
|
||||
Right: right,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type NotExprRaw struct {
|
||||
Type ExprType `json:"type"`
|
||||
Expr json.RawMessage `json:"expr"`
|
||||
}
|
||||
|
||||
func (r NotExprRaw) ToNotExpr() (NotExpr, error) {
|
||||
inner, err := UnmarshalExpr(r.Expr)
|
||||
if err != nil {
|
||||
return NotExpr{}, err
|
||||
}
|
||||
return NotExpr{
|
||||
Type: r.Type,
|
||||
Expr: inner,
|
||||
}, nil
|
||||
}
|
||||
127
internal/domain/expr/expr_test.go
Normal file
127
internal/domain/expr/expr_test.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package expr
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLogicalEval(t *testing.T) {
|
||||
// 测试逻辑表达式 and
|
||||
logicalExpr := LogicalExpr{
|
||||
Left: ConstantExpr{
|
||||
Type: "const",
|
||||
Value: "true",
|
||||
ValueType: "boolean",
|
||||
},
|
||||
Operator: And,
|
||||
Right: ConstantExpr{
|
||||
Type: "const",
|
||||
Value: "true",
|
||||
ValueType: "boolean",
|
||||
},
|
||||
}
|
||||
result, err := logicalExpr.Eval(nil)
|
||||
if err != nil {
|
||||
t.Errorf("failed to evaluate logical expression: %v", err)
|
||||
}
|
||||
if result.Value != true {
|
||||
t.Errorf("expected true, got %v", result)
|
||||
}
|
||||
|
||||
// 测试逻辑表达式 or
|
||||
orExpr := LogicalExpr{
|
||||
Left: ConstantExpr{
|
||||
Type: "const",
|
||||
Value: "true",
|
||||
ValueType: "boolean",
|
||||
},
|
||||
Operator: Or,
|
||||
Right: ConstantExpr{
|
||||
Type: "const",
|
||||
Value: "true",
|
||||
ValueType: "boolean",
|
||||
},
|
||||
}
|
||||
result, err = orExpr.Eval(nil)
|
||||
if err != nil {
|
||||
t.Errorf("failed to evaluate logical expression: %v", err)
|
||||
}
|
||||
if result.Value != true {
|
||||
t.Errorf("expected true, got %v", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalExpr(t *testing.T) {
|
||||
type args struct {
|
||||
data []byte
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want Expr
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "test1",
|
||||
args: args{
|
||||
data: []byte(`{"left":{"left":{"selector":{"id":"ODnYSOXB6HQP2_vz6JcZE","name":"certificate.validity","type":"boolean"},"type":"var"},"operator":"is","right":{"type":"const","value":true,"valueType":"boolean"},"type":"comparison"},"operator":"and","right":{"left":{"selector":{"id":"ODnYSOXB6HQP2_vz6JcZE","name":"certificate.daysLeft","type":"number"},"type":"var"},"operator":"eq","right":{"type":"const","value":2,"valueType":"number"},"type":"comparison"},"type":"logical"}`),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := UnmarshalExpr(tt.args.data)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("UnmarshalExpr() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got == nil {
|
||||
t.Errorf("UnmarshalExpr() got = nil, want %v", tt.want)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExpr_Eval(t *testing.T) {
|
||||
type args struct {
|
||||
variables map[string]map[string]any
|
||||
data []byte
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *EvalResult
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "test1",
|
||||
args: args{
|
||||
variables: map[string]map[string]any{
|
||||
"ODnYSOXB6HQP2_vz6JcZE": {
|
||||
"certificate.validity": true,
|
||||
"certificate.daysLeft": 2,
|
||||
},
|
||||
},
|
||||
data: []byte(`{"left":{"left":{"selector":{"id":"ODnYSOXB6HQP2_vz6JcZE","name":"certificate.validity","type":"boolean"},"type":"var"},"operator":"is","right":{"type":"const","value":true,"valueType":"boolean"},"type":"comparison"},"operator":"and","right":{"left":{"selector":{"id":"ODnYSOXB6HQP2_vz6JcZE","name":"certificate.daysLeft","type":"number"},"type":"var"},"operator":"eq","right":{"type":"const","value":2,"valueType":"number"},"type":"comparison"},"type":"logical"}`),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c, err := UnmarshalExpr(tt.args.data)
|
||||
if err != nil {
|
||||
t.Errorf("UnmarshalExpr() error = %v", err)
|
||||
return
|
||||
}
|
||||
got, err := c.Eval(tt.args.variables)
|
||||
t.Log("got:", got)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ConstExpr.Eval() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got.Value != true {
|
||||
t.Errorf("ConstExpr.Eval() got = %v, want %v", got.Value, true)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ const (
|
||||
AccessProviderTypeACMEHttpReq = AccessProviderType("acmehttpreq")
|
||||
AccessProviderTypeAkamai = AccessProviderType("akamai") // Akamai(预留)
|
||||
AccessProviderTypeAliyun = AccessProviderType("aliyun")
|
||||
AccessProviderTypeAPISIX = AccessProviderType("apisix")
|
||||
AccessProviderTypeAWS = AccessProviderType("aws")
|
||||
AccessProviderTypeAzure = AccessProviderType("azure")
|
||||
AccessProviderTypeBaiduCloud = AccessProviderType("baiducloud")
|
||||
@@ -28,7 +29,8 @@ const (
|
||||
AccessProviderTypeCloudflare = AccessProviderType("cloudflare")
|
||||
AccessProviderTypeClouDNS = AccessProviderType("cloudns")
|
||||
AccessProviderTypeCMCCCloud = AccessProviderType("cmcccloud")
|
||||
AccessProviderTypeCTCCCloud = AccessProviderType("ctcccloud") // 天翼云(预留)
|
||||
AccessProviderTypeConstellix = AccessProviderType("constellix")
|
||||
AccessProviderTypeCTCCCloud = AccessProviderType("ctcccloud")
|
||||
AccessProviderTypeCUCCCloud = AccessProviderType("cucccloud") // 联通云(预留)
|
||||
AccessProviderTypeDeSEC = AccessProviderType("desec")
|
||||
AccessProviderTypeDigitalOcean = AccessProviderType("digitalocean")
|
||||
@@ -117,49 +119,54 @@ ACME DNS-01 提供商常量值。
|
||||
NOTICE: If you add new constant, please keep ASCII order.
|
||||
*/
|
||||
const (
|
||||
ACMEDns01ProviderTypeACMEHttpReq = ACMEDns01ProviderType(AccessProviderTypeACMEHttpReq)
|
||||
ACMEDns01ProviderTypeAliyun = ACMEDns01ProviderType(AccessProviderTypeAliyun) // 兼容旧值,等同于 [ACMEDns01ProviderTypeAliyunDNS]
|
||||
ACMEDns01ProviderTypeAliyunDNS = ACMEDns01ProviderType(AccessProviderTypeAliyun + "-dns")
|
||||
ACMEDns01ProviderTypeAliyunESA = ACMEDns01ProviderType(AccessProviderTypeAliyun + "-esa")
|
||||
ACMEDns01ProviderTypeAWS = ACMEDns01ProviderType(AccessProviderTypeAWS) // 兼容旧值,等同于 [ACMEDns01ProviderTypeAWSRoute53]
|
||||
ACMEDns01ProviderTypeAWSRoute53 = ACMEDns01ProviderType(AccessProviderTypeAWS + "-route53")
|
||||
ACMEDns01ProviderTypeAzure = ACMEDns01ProviderType(AccessProviderTypeAzure) // 兼容旧值,等同于 [ACMEDns01ProviderTypeAzure]
|
||||
ACMEDns01ProviderTypeAzureDNS = ACMEDns01ProviderType(AccessProviderTypeAzure + "-dns")
|
||||
ACMEDns01ProviderTypeBaiduCloud = ACMEDns01ProviderType(AccessProviderTypeBaiduCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeBaiduCloudDNS]
|
||||
ACMEDns01ProviderTypeBaiduCloudDNS = ACMEDns01ProviderType(AccessProviderTypeBaiduCloud + "-dns")
|
||||
ACMEDns01ProviderTypeBunny = ACMEDns01ProviderType(AccessProviderTypeBunny)
|
||||
ACMEDns01ProviderTypeCloudflare = ACMEDns01ProviderType(AccessProviderTypeCloudflare)
|
||||
ACMEDns01ProviderTypeClouDNS = ACMEDns01ProviderType(AccessProviderTypeClouDNS)
|
||||
ACMEDns01ProviderTypeCMCCCloud = ACMEDns01ProviderType(AccessProviderTypeCMCCCloud)
|
||||
ACMEDns01ProviderTypeDeSEC = ACMEDns01ProviderType(AccessProviderTypeDeSEC)
|
||||
ACMEDns01ProviderTypeDigitalOcean = ACMEDns01ProviderType(AccessProviderTypeDigitalOcean)
|
||||
ACMEDns01ProviderTypeDNSLA = ACMEDns01ProviderType(AccessProviderTypeDNSLA)
|
||||
ACMEDns01ProviderTypeDuckDNS = ACMEDns01ProviderType(AccessProviderTypeDuckDNS)
|
||||
ACMEDns01ProviderTypeDynv6 = ACMEDns01ProviderType(AccessProviderTypeDynv6)
|
||||
ACMEDns01ProviderTypeGcore = ACMEDns01ProviderType(AccessProviderTypeGcore)
|
||||
ACMEDns01ProviderTypeGname = ACMEDns01ProviderType(AccessProviderTypeGname)
|
||||
ACMEDns01ProviderTypeGoDaddy = ACMEDns01ProviderType(AccessProviderTypeGoDaddy)
|
||||
ACMEDns01ProviderTypeHetzner = ACMEDns01ProviderType(AccessProviderTypeHetzner)
|
||||
ACMEDns01ProviderTypeHuaweiCloud = ACMEDns01ProviderType(AccessProviderTypeHuaweiCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeHuaweiCloudDNS]
|
||||
ACMEDns01ProviderTypeHuaweiCloudDNS = ACMEDns01ProviderType(AccessProviderTypeHuaweiCloud + "-dns")
|
||||
ACMEDns01ProviderTypeJDCloud = ACMEDns01ProviderType(AccessProviderTypeJDCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeJDCloudDNS]
|
||||
ACMEDns01ProviderTypeJDCloudDNS = ACMEDns01ProviderType(AccessProviderTypeJDCloud + "-dns")
|
||||
ACMEDns01ProviderTypeNamecheap = ACMEDns01ProviderType(AccessProviderTypeNamecheap)
|
||||
ACMEDns01ProviderTypeNameDotCom = ACMEDns01ProviderType(AccessProviderTypeNameDotCom)
|
||||
ACMEDns01ProviderTypeNameSilo = ACMEDns01ProviderType(AccessProviderTypeNameSilo)
|
||||
ACMEDns01ProviderTypeNetcup = ACMEDns01ProviderType(AccessProviderTypeNetcup)
|
||||
ACMEDns01ProviderTypeNetlify = ACMEDns01ProviderType(AccessProviderTypeNetlify)
|
||||
ACMEDns01ProviderTypeNS1 = ACMEDns01ProviderType(AccessProviderTypeNS1)
|
||||
ACMEDns01ProviderTypePorkbun = ACMEDns01ProviderType(AccessProviderTypePorkbun)
|
||||
ACMEDns01ProviderTypePowerDNS = ACMEDns01ProviderType(AccessProviderTypePowerDNS)
|
||||
ACMEDns01ProviderTypeRainYun = ACMEDns01ProviderType(AccessProviderTypeRainYun)
|
||||
ACMEDns01ProviderTypeTencentCloud = ACMEDns01ProviderType(AccessProviderTypeTencentCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeTencentCloudDNS]
|
||||
ACMEDns01ProviderTypeTencentCloudDNS = ACMEDns01ProviderType(AccessProviderTypeTencentCloud + "-dns")
|
||||
ACMEDns01ProviderTypeTencentCloudEO = ACMEDns01ProviderType(AccessProviderTypeTencentCloud + "-eo")
|
||||
ACMEDns01ProviderTypeVercel = ACMEDns01ProviderType(AccessProviderTypeVercel)
|
||||
ACMEDns01ProviderTypeVolcEngine = ACMEDns01ProviderType(AccessProviderTypeVolcEngine) // 兼容旧值,等同于 [ACMEDns01ProviderTypeVolcEngineDNS]
|
||||
ACMEDns01ProviderTypeVolcEngineDNS = ACMEDns01ProviderType(AccessProviderTypeVolcEngine + "-dns")
|
||||
ACMEDns01ProviderTypeWestcn = ACMEDns01ProviderType(AccessProviderTypeWestcn)
|
||||
ACMEDns01ProviderTypeACMEHttpReq = ACMEDns01ProviderType(AccessProviderTypeACMEHttpReq)
|
||||
ACMEDns01ProviderTypeAliyun = ACMEDns01ProviderType(AccessProviderTypeAliyun) // 兼容旧值,等同于 [ACMEDns01ProviderTypeAliyunDNS]
|
||||
ACMEDns01ProviderTypeAliyunDNS = ACMEDns01ProviderType(AccessProviderTypeAliyun + "-dns")
|
||||
ACMEDns01ProviderTypeAliyunESA = ACMEDns01ProviderType(AccessProviderTypeAliyun + "-esa")
|
||||
ACMEDns01ProviderTypeAWS = ACMEDns01ProviderType(AccessProviderTypeAWS) // 兼容旧值,等同于 [ACMEDns01ProviderTypeAWSRoute53]
|
||||
ACMEDns01ProviderTypeAWSRoute53 = ACMEDns01ProviderType(AccessProviderTypeAWS + "-route53")
|
||||
ACMEDns01ProviderTypeAzure = ACMEDns01ProviderType(AccessProviderTypeAzure) // 兼容旧值,等同于 [ACMEDns01ProviderTypeAzure]
|
||||
ACMEDns01ProviderTypeAzureDNS = ACMEDns01ProviderType(AccessProviderTypeAzure + "-dns")
|
||||
ACMEDns01ProviderTypeBaiduCloud = ACMEDns01ProviderType(AccessProviderTypeBaiduCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeBaiduCloudDNS]
|
||||
ACMEDns01ProviderTypeBaiduCloudDNS = ACMEDns01ProviderType(AccessProviderTypeBaiduCloud + "-dns")
|
||||
ACMEDns01ProviderTypeBunny = ACMEDns01ProviderType(AccessProviderTypeBunny)
|
||||
ACMEDns01ProviderTypeCloudflare = ACMEDns01ProviderType(AccessProviderTypeCloudflare)
|
||||
ACMEDns01ProviderTypeClouDNS = ACMEDns01ProviderType(AccessProviderTypeClouDNS)
|
||||
ACMEDns01ProviderTypeCMCCCloud = ACMEDns01ProviderType(AccessProviderTypeCMCCCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeCMCCCloudDNS]
|
||||
ACMEDns01ProviderTypeCMCCCloudDNS = ACMEDns01ProviderType(AccessProviderTypeCMCCCloud + "-dns")
|
||||
ACMEDns01ProviderTypeConstellix = ACMEDns01ProviderType(AccessProviderTypeConstellix)
|
||||
ACMEDns01ProviderTypeCTCCCloud = ACMEDns01ProviderType(AccessProviderTypeCTCCCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeCTCCCloudSmartDNS]
|
||||
ACMEDns01ProviderTypeCTCCCloudSmartDNS = ACMEDns01ProviderType(AccessProviderTypeCTCCCloud + "-smartdns")
|
||||
ACMEDns01ProviderTypeDeSEC = ACMEDns01ProviderType(AccessProviderTypeDeSEC)
|
||||
ACMEDns01ProviderTypeDigitalOcean = ACMEDns01ProviderType(AccessProviderTypeDigitalOcean)
|
||||
ACMEDns01ProviderTypeDNSLA = ACMEDns01ProviderType(AccessProviderTypeDNSLA)
|
||||
ACMEDns01ProviderTypeDuckDNS = ACMEDns01ProviderType(AccessProviderTypeDuckDNS)
|
||||
ACMEDns01ProviderTypeDynv6 = ACMEDns01ProviderType(AccessProviderTypeDynv6)
|
||||
ACMEDns01ProviderTypeGcore = ACMEDns01ProviderType(AccessProviderTypeGcore)
|
||||
ACMEDns01ProviderTypeGname = ACMEDns01ProviderType(AccessProviderTypeGname)
|
||||
ACMEDns01ProviderTypeGoDaddy = ACMEDns01ProviderType(AccessProviderTypeGoDaddy)
|
||||
ACMEDns01ProviderTypeHetzner = ACMEDns01ProviderType(AccessProviderTypeHetzner)
|
||||
ACMEDns01ProviderTypeHuaweiCloud = ACMEDns01ProviderType(AccessProviderTypeHuaweiCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeHuaweiCloudDNS]
|
||||
ACMEDns01ProviderTypeHuaweiCloudDNS = ACMEDns01ProviderType(AccessProviderTypeHuaweiCloud + "-dns")
|
||||
ACMEDns01ProviderTypeJDCloud = ACMEDns01ProviderType(AccessProviderTypeJDCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeJDCloudDNS]
|
||||
ACMEDns01ProviderTypeJDCloudDNS = ACMEDns01ProviderType(AccessProviderTypeJDCloud + "-dns")
|
||||
ACMEDns01ProviderTypeNamecheap = ACMEDns01ProviderType(AccessProviderTypeNamecheap)
|
||||
ACMEDns01ProviderTypeNameDotCom = ACMEDns01ProviderType(AccessProviderTypeNameDotCom)
|
||||
ACMEDns01ProviderTypeNameSilo = ACMEDns01ProviderType(AccessProviderTypeNameSilo)
|
||||
ACMEDns01ProviderTypeNetcup = ACMEDns01ProviderType(AccessProviderTypeNetcup)
|
||||
ACMEDns01ProviderTypeNetlify = ACMEDns01ProviderType(AccessProviderTypeNetlify)
|
||||
ACMEDns01ProviderTypeNS1 = ACMEDns01ProviderType(AccessProviderTypeNS1)
|
||||
ACMEDns01ProviderTypePorkbun = ACMEDns01ProviderType(AccessProviderTypePorkbun)
|
||||
ACMEDns01ProviderTypePowerDNS = ACMEDns01ProviderType(AccessProviderTypePowerDNS)
|
||||
ACMEDns01ProviderTypeRainYun = ACMEDns01ProviderType(AccessProviderTypeRainYun)
|
||||
ACMEDns01ProviderTypeTencentCloud = ACMEDns01ProviderType(AccessProviderTypeTencentCloud) // 兼容旧值,等同于 [ACMEDns01ProviderTypeTencentCloudDNS]
|
||||
ACMEDns01ProviderTypeTencentCloudDNS = ACMEDns01ProviderType(AccessProviderTypeTencentCloud + "-dns")
|
||||
ACMEDns01ProviderTypeTencentCloudEO = ACMEDns01ProviderType(AccessProviderTypeTencentCloud + "-eo")
|
||||
ACMEDns01ProviderTypeUCloudUDNR = ACMEDns01ProviderType(AccessProviderTypeUCloud + "-udnr")
|
||||
ACMEDns01ProviderTypeVercel = ACMEDns01ProviderType(AccessProviderTypeVercel)
|
||||
ACMEDns01ProviderTypeVolcEngine = ACMEDns01ProviderType(AccessProviderTypeVolcEngine) // 兼容旧值,等同于 [ACMEDns01ProviderTypeVolcEngineDNS]
|
||||
ACMEDns01ProviderTypeVolcEngineDNS = ACMEDns01ProviderType(AccessProviderTypeVolcEngine + "-dns")
|
||||
ACMEDns01ProviderTypeWestcn = ACMEDns01ProviderType(AccessProviderTypeWestcn)
|
||||
)
|
||||
|
||||
type DeploymentProviderType string
|
||||
@@ -190,8 +197,10 @@ const (
|
||||
DeploymentProviderTypeAliyunOSS = DeploymentProviderType(AccessProviderTypeAliyun + "-oss")
|
||||
DeploymentProviderTypeAliyunVOD = DeploymentProviderType(AccessProviderTypeAliyun + "-vod")
|
||||
DeploymentProviderTypeAliyunWAF = DeploymentProviderType(AccessProviderTypeAliyun + "-waf")
|
||||
DeploymentProviderTypeAPISIX = DeploymentProviderType(AccessProviderTypeAWS + "-apisix")
|
||||
DeploymentProviderTypeAWSACM = DeploymentProviderType(AccessProviderTypeAWS + "-acm")
|
||||
DeploymentProviderTypeAWSCloudFront = DeploymentProviderType(AccessProviderTypeAWS + "-cloudfront")
|
||||
DeploymentProviderTypeAWSIAM = DeploymentProviderType(AccessProviderTypeAWS + "-iam")
|
||||
DeploymentProviderTypeAzureKeyVault = DeploymentProviderType(AccessProviderTypeAzure + "-keyvault")
|
||||
DeploymentProviderTypeBaiduCloudAppBLB = DeploymentProviderType(AccessProviderTypeBaiduCloud + "-appblb")
|
||||
DeploymentProviderTypeBaiduCloudBLB = DeploymentProviderType(AccessProviderTypeBaiduCloud + "-blb")
|
||||
@@ -206,6 +215,12 @@ const (
|
||||
DeploymentProviderTypeBytePlusCDN = DeploymentProviderType(AccessProviderTypeBytePlus + "-cdn")
|
||||
DeploymentProviderTypeCacheFly = DeploymentProviderType(AccessProviderTypeCacheFly)
|
||||
DeploymentProviderTypeCdnfly = DeploymentProviderType(AccessProviderTypeCdnfly)
|
||||
DeploymentProviderTypeCTCCCloudAO = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-ao")
|
||||
DeploymentProviderTypeCTCCCloudCDN = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-cdn")
|
||||
DeploymentProviderTypeCTCCCloudCMS = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-cms")
|
||||
DeploymentProviderTypeCTCCCloudELB = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-elb")
|
||||
DeploymentProviderTypeCTCCCloudICDN = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-icdn")
|
||||
DeploymentProviderTypeCTCCCloudLVDN = DeploymentProviderType(AccessProviderTypeCTCCCloud + "-ldvn")
|
||||
DeploymentProviderTypeDogeCloudCDN = DeploymentProviderType(AccessProviderTypeDogeCloud + "-cdn")
|
||||
DeploymentProviderTypeEdgioApplications = DeploymentProviderType(AccessProviderTypeEdgio + "-applications")
|
||||
DeploymentProviderTypeFlexCDN = DeploymentProviderType(AccessProviderTypeFlexCDN)
|
||||
@@ -238,6 +253,7 @@ const (
|
||||
DeploymentProviderTypeTencentCloudCSS = DeploymentProviderType(AccessProviderTypeTencentCloud + "-css")
|
||||
DeploymentProviderTypeTencentCloudECDN = DeploymentProviderType(AccessProviderTypeTencentCloud + "-ecdn")
|
||||
DeploymentProviderTypeTencentCloudEO = DeploymentProviderType(AccessProviderTypeTencentCloud + "-eo")
|
||||
DeploymentProviderTypeTencentCloudGAAP = DeploymentProviderType(AccessProviderTypeTencentCloud + "-gaap")
|
||||
DeploymentProviderTypeTencentCloudSCF = DeploymentProviderType(AccessProviderTypeTencentCloud + "-scf")
|
||||
DeploymentProviderTypeTencentCloudSSL = DeploymentProviderType(AccessProviderTypeTencentCloud + "-ssl")
|
||||
DeploymentProviderTypeTencentCloudSSLDeploy = DeploymentProviderType(AccessProviderTypeTencentCloud + "-ssldeploy")
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/usual2970/certimate/internal/domain/expr"
|
||||
maputil "github.com/usual2970/certimate/internal/pkg/utils/map"
|
||||
)
|
||||
|
||||
@@ -30,6 +32,7 @@ const (
|
||||
WorkflowNodeTypeEnd = WorkflowNodeType("end")
|
||||
WorkflowNodeTypeApply = WorkflowNodeType("apply")
|
||||
WorkflowNodeTypeUpload = WorkflowNodeType("upload")
|
||||
WorkflowNodeTypeMonitor = WorkflowNodeType("monitor")
|
||||
WorkflowNodeTypeDeploy = WorkflowNodeType("deploy")
|
||||
WorkflowNodeTypeNotify = WorkflowNodeType("notify")
|
||||
WorkflowNodeTypeBranch = WorkflowNodeType("branch")
|
||||
@@ -68,23 +71,30 @@ type WorkflowNodeConfigForApply struct {
|
||||
Provider string `json:"provider"` // DNS 提供商
|
||||
ProviderAccessId string `json:"providerAccessId"` // DNS 提供商授权记录 ID
|
||||
ProviderConfig map[string]any `json:"providerConfig"` // DNS 提供商额外配置
|
||||
CAProvider string `json:"caProvider,omitempty"` // CA 提供商(零值将使用全局配置)
|
||||
CAProvider string `json:"caProvider,omitempty"` // CA 提供商(零值时使用全局配置)
|
||||
CAProviderAccessId string `json:"caProviderAccessId,omitempty"` // CA 提供商授权记录 ID
|
||||
CAProviderConfig map[string]any `json:"caProviderConfig,omitempty"` // CA 提供商额外配置
|
||||
KeyAlgorithm string `json:"keyAlgorithm"` // 证书算法
|
||||
Nameservers string `json:"nameservers,omitempty"` // DNS 服务器列表,以半角分号分隔
|
||||
DnsPropagationWait int32 `json:"dnsPropagationWait,omitempty"` // DNS 传播等待时间,等同于 lego 的 `--dns-propagation-wait` 参数
|
||||
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` // DNS 传播检查超时时间(零值取决于提供商的默认值)
|
||||
DnsTTL int32 `json:"dnsTTL,omitempty"` // DNS 解析记录 TTL(零值取决于提供商的默认值)
|
||||
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` // DNS 传播检查超时时间(零值时使用提供商的默认值)
|
||||
DnsTTL int32 `json:"dnsTTL,omitempty"` // DNS 解析记录 TTL(零值时使用提供商的默认值)
|
||||
DisableFollowCNAME bool `json:"disableFollowCNAME,omitempty"` // 是否关闭 CNAME 跟随
|
||||
DisableARI bool `json:"disableARI,omitempty"` // 是否关闭 ARI
|
||||
SkipBeforeExpiryDays int32 `json:"skipBeforeExpiryDays,omitempty"` // 证书到期前多少天前跳过续期(零值将使用默认值 30)
|
||||
SkipBeforeExpiryDays int32 `json:"skipBeforeExpiryDays,omitempty"` // 证书到期前多少天前跳过续期(零值时默认值 30)
|
||||
}
|
||||
|
||||
type WorkflowNodeConfigForUpload struct {
|
||||
Certificate string `json:"certificate"`
|
||||
PrivateKey string `json:"privateKey"`
|
||||
Domains string `json:"domains"`
|
||||
Certificate string `json:"certificate"` // 证书 PEM 内容
|
||||
PrivateKey string `json:"privateKey"` // 私钥 PEM 内容
|
||||
Domains string `json:"domains,omitempty"`
|
||||
}
|
||||
|
||||
type WorkflowNodeConfigForMonitor struct {
|
||||
Host string `json:"host"` // 主机地址
|
||||
Port int32 `json:"port,omitempty"` // 端口(零值时默认值 443)
|
||||
Domain string `json:"domain,omitempty"` // 域名(零值时默认值 [Host])
|
||||
RequestPath string `json:"requestPath,omitempty"` // 请求路径
|
||||
}
|
||||
|
||||
type WorkflowNodeConfigForDeploy struct {
|
||||
@@ -96,12 +106,17 @@ type WorkflowNodeConfigForDeploy struct {
|
||||
}
|
||||
|
||||
type WorkflowNodeConfigForNotify struct {
|
||||
Channel string `json:"channel,omitempty"` // Deprecated: v0.4.x 将废弃
|
||||
Provider string `json:"provider"` // 通知提供商
|
||||
ProviderAccessId string `json:"providerAccessId"` // 通知提供商授权记录 ID
|
||||
ProviderConfig map[string]any `json:"providerConfig,omitempty"` // 通知提供商额外配置
|
||||
Subject string `json:"subject"` // 通知主题
|
||||
Message string `json:"message"` // 通知内容
|
||||
Channel string `json:"channel,omitempty"` // Deprecated: v0.4.x 将废弃
|
||||
Provider string `json:"provider"` // 通知提供商
|
||||
ProviderAccessId string `json:"providerAccessId"` // 通知提供商授权记录 ID
|
||||
ProviderConfig map[string]any `json:"providerConfig,omitempty"` // 通知提供商额外配置
|
||||
Subject string `json:"subject"` // 通知主题
|
||||
Message string `json:"message"` // 通知内容
|
||||
SkipOnAllPrevSkipped bool `json:"skipOnAllPrevSkipped"` // 前序节点均已跳过时是否跳过
|
||||
}
|
||||
|
||||
type WorkflowNodeConfigForCondition struct {
|
||||
Expression expr.Expr `json:"expression"` // 条件表达式
|
||||
}
|
||||
|
||||
func (n *WorkflowNode) GetConfigForApply() WorkflowNodeConfigForApply {
|
||||
@@ -114,7 +129,7 @@ func (n *WorkflowNode) GetConfigForApply() WorkflowNodeConfigForApply {
|
||||
CAProvider: maputil.GetString(n.Config, "caProvider"),
|
||||
CAProviderAccessId: maputil.GetString(n.Config, "caProviderAccessId"),
|
||||
CAProviderConfig: maputil.GetKVMapAny(n.Config, "caProviderConfig"),
|
||||
KeyAlgorithm: maputil.GetString(n.Config, "keyAlgorithm"),
|
||||
KeyAlgorithm: maputil.GetOrDefaultString(n.Config, "keyAlgorithm", string(CertificateKeyAlgorithmTypeRSA2048)),
|
||||
Nameservers: maputil.GetString(n.Config, "nameservers"),
|
||||
DnsPropagationWait: maputil.GetInt32(n.Config, "dnsPropagationWait"),
|
||||
DnsPropagationTimeout: maputil.GetInt32(n.Config, "dnsPropagationTimeout"),
|
||||
@@ -133,6 +148,16 @@ func (n *WorkflowNode) GetConfigForUpload() WorkflowNodeConfigForUpload {
|
||||
}
|
||||
}
|
||||
|
||||
func (n *WorkflowNode) GetConfigForMonitor() WorkflowNodeConfigForMonitor {
|
||||
host := maputil.GetString(n.Config, "host")
|
||||
return WorkflowNodeConfigForMonitor{
|
||||
Host: host,
|
||||
Port: maputil.GetOrDefaultInt32(n.Config, "port", 443),
|
||||
Domain: maputil.GetOrDefaultString(n.Config, "domain", host),
|
||||
RequestPath: maputil.GetString(n.Config, "path"),
|
||||
}
|
||||
}
|
||||
|
||||
func (n *WorkflowNode) GetConfigForDeploy() WorkflowNodeConfigForDeploy {
|
||||
return WorkflowNodeConfigForDeploy{
|
||||
Certificate: maputil.GetString(n.Config, "certificate"),
|
||||
@@ -145,12 +170,30 @@ func (n *WorkflowNode) GetConfigForDeploy() WorkflowNodeConfigForDeploy {
|
||||
|
||||
func (n *WorkflowNode) GetConfigForNotify() WorkflowNodeConfigForNotify {
|
||||
return WorkflowNodeConfigForNotify{
|
||||
Channel: maputil.GetString(n.Config, "channel"),
|
||||
Provider: maputil.GetString(n.Config, "provider"),
|
||||
ProviderAccessId: maputil.GetString(n.Config, "providerAccessId"),
|
||||
ProviderConfig: maputil.GetKVMapAny(n.Config, "providerConfig"),
|
||||
Subject: maputil.GetString(n.Config, "subject"),
|
||||
Message: maputil.GetString(n.Config, "message"),
|
||||
Channel: maputil.GetString(n.Config, "channel"),
|
||||
Provider: maputil.GetString(n.Config, "provider"),
|
||||
ProviderAccessId: maputil.GetString(n.Config, "providerAccessId"),
|
||||
ProviderConfig: maputil.GetKVMapAny(n.Config, "providerConfig"),
|
||||
Subject: maputil.GetString(n.Config, "subject"),
|
||||
Message: maputil.GetString(n.Config, "message"),
|
||||
SkipOnAllPrevSkipped: maputil.GetBool(n.Config, "skipOnAllPrevSkipped"),
|
||||
}
|
||||
}
|
||||
|
||||
func (n *WorkflowNode) GetConfigForCondition() WorkflowNodeConfigForCondition {
|
||||
expression := n.Config["expression"]
|
||||
if expression == nil {
|
||||
return WorkflowNodeConfigForCondition{}
|
||||
}
|
||||
|
||||
exprRaw, _ := json.Marshal(expression)
|
||||
expr, err := expr.UnmarshalExpr([]byte(exprRaw))
|
||||
if err != nil {
|
||||
return WorkflowNodeConfigForCondition{}
|
||||
}
|
||||
|
||||
return WorkflowNodeConfigForCondition{
|
||||
Expression: expr,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,9 +206,6 @@ type WorkflowNodeIO struct {
|
||||
ValueSelector WorkflowNodeIOValueSelector `json:"valueSelector"`
|
||||
}
|
||||
|
||||
type WorkflowNodeIOValueSelector struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
type WorkflowNodeIOValueSelector = expr.ExprValueSelector
|
||||
|
||||
const WorkflowNodeIONameCertificate string = "certificate"
|
||||
|
||||
@@ -29,18 +29,18 @@ func NewWithWorkflowNode(config NotifierWithWorkflowNodeConfig) (Notifier, error
|
||||
return nil, fmt.Errorf("node type is not '%s'", string(domain.WorkflowNodeTypeNotify))
|
||||
}
|
||||
|
||||
nodeConfig := config.Node.GetConfigForNotify()
|
||||
nodeCfg := config.Node.GetConfigForNotify()
|
||||
options := ¬ifierProviderOptions{
|
||||
Provider: domain.NotificationProviderType(nodeConfig.Provider),
|
||||
Provider: domain.NotificationProviderType(nodeCfg.Provider),
|
||||
ProviderAccessConfig: make(map[string]any),
|
||||
ProviderServiceConfig: nodeConfig.ProviderConfig,
|
||||
ProviderServiceConfig: nodeCfg.ProviderConfig,
|
||||
}
|
||||
|
||||
accessRepo := repository.NewAccessRepository()
|
||||
if nodeConfig.ProviderAccessId != "" {
|
||||
access, err := accessRepo.GetById(context.Background(), nodeConfig.ProviderAccessId)
|
||||
if nodeCfg.ProviderAccessId != "" {
|
||||
access, err := accessRepo.GetById(context.Background(), nodeCfg.ProviderAccessId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeConfig.ProviderAccessId, err)
|
||||
return nil, fmt.Errorf("failed to get access #%s record: %w", nodeCfg.ProviderAccessId, err)
|
||||
} else {
|
||||
options.ProviderAccessConfig = access.Config
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ func createNotifierProvider(options *notifierProviderOptions) (notifier.Notifier
|
||||
Username: access.Username,
|
||||
Password: access.Password,
|
||||
SenderAddress: maputil.GetOrDefaultString(options.ProviderServiceConfig, "senderAddress", access.DefaultSenderAddress),
|
||||
SenderName: maputil.GetOrDefaultString(options.ProviderServiceConfig, "senderName", access.DefaultSenderName),
|
||||
ReceiverAddress: maputil.GetOrDefaultString(options.ProviderServiceConfig, "receiverAddress", access.DefaultReceiverAddress),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package lego_aliyunesa
|
||||
package internal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -102,13 +101,13 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
return fmt.Errorf("alicloud-esa: could not find zone for domain %q: %w", domain, err)
|
||||
}
|
||||
|
||||
siteName := strings.TrimRight(authZone, ".")
|
||||
siteName := dns01.UnFqdn(authZone)
|
||||
siteId, err := d.getSiteId(siteName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("alicloud-esa: could not find site for zone %q: %w", siteName, err)
|
||||
}
|
||||
|
||||
if err := d.addOrUpdateDNSRecord(siteId, strings.TrimRight(info.EffectiveFQDN, "."), info.Value); err != nil {
|
||||
if err := d.addOrUpdateDNSRecord(siteId, dns01.UnFqdn(info.EffectiveFQDN), info.Value); err != nil {
|
||||
return fmt.Errorf("alicloud-esa: %w", err)
|
||||
}
|
||||
|
||||
@@ -123,13 +122,13 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
return fmt.Errorf("alicloud-esa: could not find zone for domain %q: %w", domain, err)
|
||||
}
|
||||
|
||||
siteName := strings.TrimRight(authZone, ".")
|
||||
siteName := dns01.UnFqdn(authZone)
|
||||
siteId, err := d.getSiteId(siteName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("alicloud-esa: could not find site for zone %q: %w", siteName, err)
|
||||
}
|
||||
|
||||
if err := d.removeDNSRecord(siteId, strings.TrimRight(info.EffectiveFQDN, ".")); err != nil {
|
||||
if err := d.removeDNSRecord(siteId, dns01.UnFqdn(info.EffectiveFQDN)); err != nil {
|
||||
return fmt.Errorf("alicloud-esa: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package lego_baiducloud
|
||||
package internal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package cmcccloud
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/challenge"
|
||||
@@ -18,7 +17,7 @@ type ChallengeProviderConfig struct {
|
||||
|
||||
func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) {
|
||||
if config == nil {
|
||||
return nil, errors.New("config is nil")
|
||||
panic("config is nil")
|
||||
}
|
||||
|
||||
providerConfig := internal.NewDefaultConfig()
|
||||
|
||||
@@ -18,8 +18,9 @@ import (
|
||||
const (
|
||||
envNamespace = "CMCCCLOUD_"
|
||||
|
||||
EnvAccessKey = envNamespace + "ACCESS_KEY"
|
||||
EnvSecretKey = envNamespace + "SECRET_KEY"
|
||||
EnvAccessKey = envNamespace + "ACCESS_KEY"
|
||||
EnvSecretKey = envNamespace + "SECRET_KEY"
|
||||
|
||||
EnvTTL = envNamespace + "TTL"
|
||||
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
|
||||
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
|
||||
@@ -30,13 +31,14 @@ const (
|
||||
var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
|
||||
|
||||
type Config struct {
|
||||
AccessKey string
|
||||
SecretKey string
|
||||
ReadTimeOut int
|
||||
ConnectTimeout int
|
||||
AccessKey string
|
||||
SecretKey string
|
||||
|
||||
PropagationTimeout time.Duration
|
||||
PollingInterval time.Duration
|
||||
TTL int32
|
||||
ReadTimeOut int
|
||||
ConnectTimeout int
|
||||
}
|
||||
|
||||
type DNSProvider struct {
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package cloudns
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/challenge"
|
||||
"github.com/go-acme/lego/v4/providers/dns/constellix"
|
||||
)
|
||||
|
||||
type ChallengeProviderConfig struct {
|
||||
ApiKey string `json:"apiKey"`
|
||||
SecretKey string `json:"secretKey"`
|
||||
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||
DnsTTL int32 `json:"dnsTTL,omitempty"`
|
||||
}
|
||||
|
||||
func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) {
|
||||
if config == nil {
|
||||
panic("config is nil")
|
||||
}
|
||||
|
||||
providerConfig := constellix.NewDefaultConfig()
|
||||
providerConfig.APIKey = config.ApiKey
|
||||
providerConfig.SecretKey = config.SecretKey
|
||||
if config.DnsPropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||
}
|
||||
if config.DnsTTL != 0 {
|
||||
providerConfig.TTL = int(config.DnsTTL)
|
||||
}
|
||||
|
||||
provider, err := constellix.NewDNSProviderConfig(providerConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return provider, nil
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package ctcccloud
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/challenge"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/ctcccloud/internal"
|
||||
)
|
||||
|
||||
type ChallengeProviderConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||
DnsTTL int32 `json:"dnsTTL,omitempty"`
|
||||
}
|
||||
|
||||
func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) {
|
||||
if config == nil {
|
||||
panic("config is nil")
|
||||
}
|
||||
|
||||
providerConfig := internal.NewDefaultConfig()
|
||||
providerConfig.AccessKeyId = config.AccessKeyId
|
||||
providerConfig.SecretAccessKey = config.SecretAccessKey
|
||||
if config.DnsTTL != 0 {
|
||||
providerConfig.TTL = int(config.DnsTTL)
|
||||
}
|
||||
if config.DnsPropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||
}
|
||||
|
||||
provider, err := internal.NewDNSProviderConfig(providerConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return provider, nil
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/challenge"
|
||||
"github.com/go-acme/lego/v4/challenge/dns01"
|
||||
"github.com/go-acme/lego/v4/platform/config/env"
|
||||
|
||||
ctyundns "github.com/usual2970/certimate/internal/pkg/sdk3rd/ctyun/dns"
|
||||
typeutil "github.com/usual2970/certimate/internal/pkg/utils/type"
|
||||
)
|
||||
|
||||
const (
|
||||
envNamespace = "CTYUNSMARTDNS_"
|
||||
|
||||
EnvAccessKeyID = envNamespace + "ACCESS_KEY_ID"
|
||||
EnvSecretAccessKey = envNamespace + "SECRET_ACCESS_KEY"
|
||||
|
||||
EnvTTL = envNamespace + "TTL"
|
||||
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
|
||||
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
|
||||
EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
|
||||
)
|
||||
|
||||
var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
|
||||
|
||||
type Config struct {
|
||||
AccessKeyId string
|
||||
SecretAccessKey string
|
||||
|
||||
PropagationTimeout time.Duration
|
||||
PollingInterval time.Duration
|
||||
TTL int
|
||||
HTTPTimeout time.Duration
|
||||
}
|
||||
|
||||
type DNSProvider struct {
|
||||
client *ctyundns.Client
|
||||
config *Config
|
||||
}
|
||||
|
||||
func NewDefaultConfig() *Config {
|
||||
return &Config{
|
||||
TTL: env.GetOrDefaultInt(EnvTTL, 600),
|
||||
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 2*time.Minute),
|
||||
HTTPTimeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
|
||||
}
|
||||
}
|
||||
|
||||
func NewDNSProvider() (*DNSProvider, error) {
|
||||
values, err := env.Get(EnvAccessKeyID, EnvSecretAccessKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ctyun: %w", err)
|
||||
}
|
||||
|
||||
config := NewDefaultConfig()
|
||||
config.AccessKeyId = values[EnvAccessKeyID]
|
||||
config.SecretAccessKey = values[EnvSecretAccessKey]
|
||||
|
||||
return NewDNSProviderConfig(config)
|
||||
}
|
||||
|
||||
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
||||
if config == nil {
|
||||
return nil, errors.New("ctyun: the configuration of the DNS provider is nil")
|
||||
}
|
||||
|
||||
client, err := ctyundns.NewClient(config.AccessKeyId, config.SecretAccessKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
client.SetTimeout(config.HTTPTimeout)
|
||||
}
|
||||
|
||||
return &DNSProvider{
|
||||
client: client,
|
||||
config: config,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
info := dns01.GetChallengeInfo(domain, keyAuth)
|
||||
|
||||
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ctyun: could not find zone for domain %q: %w", domain, err)
|
||||
}
|
||||
|
||||
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ctyun: %w", err)
|
||||
}
|
||||
|
||||
if err := d.addOrUpdateDNSRecord(dns01.UnFqdn(authZone), subDomain, info.Value); err != nil {
|
||||
return fmt.Errorf("ctyun: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
info := dns01.GetChallengeInfo(domain, keyAuth)
|
||||
|
||||
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ctyun: could not find zone for domain %q: %w", domain, err)
|
||||
}
|
||||
|
||||
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ctyun: %w", err)
|
||||
}
|
||||
|
||||
if err := d.removeDNSRecord(dns01.UnFqdn(authZone), subDomain); err != nil {
|
||||
return fmt.Errorf("ctyun: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
||||
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||
}
|
||||
|
||||
func (d *DNSProvider) findDNSRecordId(zoneName, subDomain string) (int32, error) {
|
||||
// 查询解析记录列表
|
||||
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=122&api=11264&data=181&isNormal=1&vid=259
|
||||
request := &ctyundns.QueryRecordListRequest{}
|
||||
request.Domain = typeutil.ToPtr(zoneName)
|
||||
request.Host = typeutil.ToPtr(subDomain)
|
||||
request.Type = typeutil.ToPtr("TXT")
|
||||
|
||||
response, err := d.client.QueryRecordList(request)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if response.ReturnObj == nil || response.ReturnObj.Records == nil || len(response.ReturnObj.Records) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
return response.ReturnObj.Records[0].RecordId, nil
|
||||
}
|
||||
|
||||
func (d *DNSProvider) addOrUpdateDNSRecord(zoneName, subDomain, value string) error {
|
||||
recordId, err := d.findDNSRecordId(zoneName, subDomain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if recordId == 0 {
|
||||
// 新增解析记录
|
||||
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=122&api=11259&data=181&isNormal=1&vid=259
|
||||
request := &ctyundns.AddRecordRequest{
|
||||
Domain: typeutil.ToPtr(zoneName),
|
||||
Host: typeutil.ToPtr(subDomain),
|
||||
Type: typeutil.ToPtr("TXT"),
|
||||
LineCode: typeutil.ToPtr("Default"),
|
||||
Value: typeutil.ToPtr(value),
|
||||
State: typeutil.ToPtr(int32(1)),
|
||||
TTL: typeutil.ToPtr(int32(d.config.TTL)),
|
||||
}
|
||||
_, err := d.client.AddRecord(request)
|
||||
return err
|
||||
} else {
|
||||
// 修改解析记录
|
||||
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=122&api=11261&data=181&isNormal=1&vid=259
|
||||
request := &ctyundns.UpdateRecordRequest{
|
||||
RecordId: typeutil.ToPtr(recordId),
|
||||
Domain: typeutil.ToPtr(zoneName),
|
||||
Host: typeutil.ToPtr(subDomain),
|
||||
Type: typeutil.ToPtr("TXT"),
|
||||
LineCode: typeutil.ToPtr("Default"),
|
||||
Value: typeutil.ToPtr(value),
|
||||
State: typeutil.ToPtr(int32(1)),
|
||||
TTL: typeutil.ToPtr(int32(d.config.TTL)),
|
||||
}
|
||||
_, err := d.client.UpdateRecord(request)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DNSProvider) removeDNSRecord(zoneName, subDomain string) error {
|
||||
recordId, err := d.findDNSRecordId(zoneName, subDomain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if recordId == 0 {
|
||||
return nil
|
||||
} else {
|
||||
// 删除解析记录
|
||||
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=122&api=11262&data=181&isNormal=1&vid=259
|
||||
request := &ctyundns.DeleteRecordRequest{
|
||||
RecordId: typeutil.ToPtr(recordId),
|
||||
}
|
||||
_, err = d.client.DeleteRecord(request)
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package lego_dnsla
|
||||
package internal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package lego_dynv6
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package lego_gname
|
||||
package internal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package lego_jdcloud
|
||||
package internal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
@@ -29,6 +29,7 @@ func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider,
|
||||
providerConfig.APIKey = config.ApiKey
|
||||
if config.AllowInsecureConnections {
|
||||
providerConfig.HTTPClient.Transport = &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package lego_tencentcloudeo
|
||||
package internal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/challenge"
|
||||
@@ -91,7 +90,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
info := dns01.GetChallengeInfo(domain, keyAuth)
|
||||
|
||||
if err := d.addOrUpdateDNSRecord(strings.TrimRight(info.EffectiveFQDN, "."), info.Value); err != nil {
|
||||
if err := d.addOrUpdateDNSRecord(dns01.UnFqdn(info.EffectiveFQDN), info.Value); err != nil {
|
||||
return fmt.Errorf("tencentcloud-eo: %w", err)
|
||||
}
|
||||
|
||||
@@ -101,7 +100,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
info := dns01.GetChallengeInfo(domain, keyAuth)
|
||||
|
||||
if err := d.removeDNSRecord(strings.TrimRight(info.EffectiveFQDN, ".")); err != nil {
|
||||
if err := d.removeDNSRecord(dns01.UnFqdn(info.EffectiveFQDN)); err != nil {
|
||||
return fmt.Errorf("tencentcloud-eo: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/challenge"
|
||||
"github.com/go-acme/lego/v4/challenge/dns01"
|
||||
"github.com/go-acme/lego/v4/platform/config/env"
|
||||
"github.com/ucloud/ucloud-sdk-go/ucloud"
|
||||
"github.com/ucloud/ucloud-sdk-go/ucloud/auth"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/sdk3rd/ucloud/udnr"
|
||||
)
|
||||
|
||||
const (
|
||||
envNamespace = "UCLOUDUDNR_"
|
||||
|
||||
EnvPublicKey = envNamespace + "PUBLIC_KEY"
|
||||
EnvPrivateKey = envNamespace + "PRIVATE_KEY"
|
||||
|
||||
EnvTTL = envNamespace + "TTL"
|
||||
EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT"
|
||||
EnvPollingInterval = envNamespace + "POLLING_INTERVAL"
|
||||
EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT"
|
||||
)
|
||||
|
||||
var _ challenge.ProviderTimeout = (*DNSProvider)(nil)
|
||||
|
||||
type Config struct {
|
||||
PrivateKey string
|
||||
PublicKey string
|
||||
|
||||
PropagationTimeout time.Duration
|
||||
PollingInterval time.Duration
|
||||
TTL int32
|
||||
HTTPTimeout time.Duration
|
||||
}
|
||||
|
||||
type DNSProvider struct {
|
||||
client *udnr.UDNRClient
|
||||
config *Config
|
||||
}
|
||||
|
||||
func NewDefaultConfig() *Config {
|
||||
return &Config{
|
||||
TTL: int32(env.GetOrDefaultInt(EnvTTL, 300)),
|
||||
PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 2*time.Minute),
|
||||
PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval),
|
||||
HTTPTimeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second),
|
||||
}
|
||||
}
|
||||
|
||||
func NewDNSProvider() (*DNSProvider, error) {
|
||||
values, err := env.Get(EnvPrivateKey, EnvPublicKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ucloud-udnr: %w", err)
|
||||
}
|
||||
|
||||
config := NewDefaultConfig()
|
||||
config.PrivateKey = values[EnvPrivateKey]
|
||||
config.PublicKey = values[EnvPublicKey]
|
||||
|
||||
return NewDNSProviderConfig(config)
|
||||
}
|
||||
|
||||
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
|
||||
if config == nil {
|
||||
return nil, errors.New("ucloud-udnr: the configuration of the DNS provider is nil")
|
||||
}
|
||||
|
||||
cfg := ucloud.NewConfig()
|
||||
credential := auth.NewCredential()
|
||||
credential.PrivateKey = config.PrivateKey
|
||||
credential.PublicKey = config.PublicKey
|
||||
client := udnr.NewClient(&cfg, &credential)
|
||||
|
||||
return &DNSProvider{
|
||||
client: client,
|
||||
config: config,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
|
||||
info := dns01.GetChallengeInfo(domain, keyAuth)
|
||||
|
||||
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ucloud-udnr: could not find zone for domain %q: %w", domain, err)
|
||||
}
|
||||
|
||||
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ucloud-udnr: %w", err)
|
||||
}
|
||||
|
||||
udnrDomainDNSQueryReq := d.client.NewQueryDomainDNSRequest()
|
||||
udnrDomainDNSQueryReq.Dn = ucloud.String(authZone)
|
||||
if udnrDomainDNSQueryResp, err := d.client.QueryDomainDNS(udnrDomainDNSQueryReq); err != nil {
|
||||
return fmt.Errorf("ucloud-udnr: %w", err)
|
||||
} else {
|
||||
for _, record := range udnrDomainDNSQueryResp.Data {
|
||||
if record.DnsType == "TXT" && record.RecordName == subDomain {
|
||||
udnrDomainDNSDeleteReq := d.client.NewDeleteDomainDNSRequest()
|
||||
udnrDomainDNSDeleteReq.Dn = ucloud.String(authZone)
|
||||
udnrDomainDNSDeleteReq.DnsType = ucloud.String(record.DnsType)
|
||||
udnrDomainDNSDeleteReq.RecordName = ucloud.String(record.RecordName)
|
||||
udnrDomainDNSDeleteReq.Content = ucloud.String(record.Content)
|
||||
d.client.DeleteDomainDNS(udnrDomainDNSDeleteReq)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
udnrDomainDNSAddReq := d.client.NewAddDomainDNSRequest()
|
||||
udnrDomainDNSAddReq.Dn = ucloud.String(authZone)
|
||||
udnrDomainDNSAddReq.DnsType = ucloud.String("TXT")
|
||||
udnrDomainDNSAddReq.RecordName = ucloud.String(subDomain)
|
||||
udnrDomainDNSAddReq.Content = ucloud.String(info.Value)
|
||||
udnrDomainDNSAddReq.TTL = ucloud.Int(int(d.config.TTL))
|
||||
if _, err := d.client.AddDomainDNS(udnrDomainDNSAddReq); err != nil {
|
||||
return fmt.Errorf("ucloud-udnr: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
info := dns01.GetChallengeInfo(domain, keyAuth)
|
||||
|
||||
authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ucloud-udnr: could not find zone for domain %q: %w", domain, err)
|
||||
}
|
||||
|
||||
subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ucloud-udnr: %w", err)
|
||||
}
|
||||
|
||||
udnrDomainDNSQueryReq := d.client.NewQueryDomainDNSRequest()
|
||||
udnrDomainDNSQueryReq.Dn = ucloud.String(authZone)
|
||||
if udnrDomainDNSQueryResp, err := d.client.QueryDomainDNS(udnrDomainDNSQueryReq); err != nil {
|
||||
return fmt.Errorf("ucloud-udnr: %w", err)
|
||||
} else {
|
||||
for _, record := range udnrDomainDNSQueryResp.Data {
|
||||
if record.DnsType == "TXT" && record.RecordName == subDomain {
|
||||
udnrDomainDNSDeleteReq := d.client.NewDeleteDomainDNSRequest()
|
||||
udnrDomainDNSDeleteReq.Dn = ucloud.String(authZone)
|
||||
udnrDomainDNSDeleteReq.DnsType = ucloud.String(record.DnsType)
|
||||
udnrDomainDNSDeleteReq.RecordName = ucloud.String(record.RecordName)
|
||||
udnrDomainDNSDeleteReq.Content = ucloud.String(record.Content)
|
||||
d.client.DeleteDomainDNS(udnrDomainDNSDeleteReq)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
|
||||
return d.config.PropagationTimeout, d.config.PollingInterval
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package ucloududnr
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/challenge"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/ucloud-udnr/internal"
|
||||
)
|
||||
|
||||
type ChallengeProviderConfig struct {
|
||||
PrivateKey string `json:"privateKey"`
|
||||
PublicKey string `json:"publicKey"`
|
||||
DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"`
|
||||
DnsTTL int32 `json:"dnsTTL,omitempty"`
|
||||
}
|
||||
|
||||
func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) {
|
||||
if config == nil {
|
||||
return nil, errors.New("config is nil")
|
||||
}
|
||||
|
||||
providerConfig := internal.NewDefaultConfig()
|
||||
providerConfig.PrivateKey = config.PrivateKey
|
||||
providerConfig.PublicKey = config.PublicKey
|
||||
if config.DnsTTL != 0 {
|
||||
providerConfig.TTL = config.DnsTTL
|
||||
}
|
||||
if config.DnsPropagationTimeout != 0 {
|
||||
providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second
|
||||
}
|
||||
|
||||
provider, err := internal.NewDNSProviderConfig(providerConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return provider, nil
|
||||
}
|
||||
@@ -20,7 +20,7 @@ type Deployer interface {
|
||||
// 出参:
|
||||
// - res:部署结果。
|
||||
// - err: 错误。
|
||||
Deploy(ctx context.Context, certPEM string, privkeyPEM string) (res *DeployResult, err error)
|
||||
Deploy(ctx context.Context, certPEM string, privkeyPEM string) (_res *DeployResult, _err error)
|
||||
}
|
||||
|
||||
// 表示证书部署结果的数据结构。
|
||||
|
||||
@@ -53,7 +53,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
@@ -62,10 +62,15 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
|
||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||
// 设置面板 SSL 证书
|
||||
SSLEnable := "enable"
|
||||
if d.config.ApiVersion == "v2" {
|
||||
SSLEnable = "Enable"
|
||||
}
|
||||
|
||||
updateSystemSSLReq := &onepanelsdk.UpdateSystemSSLRequest{
|
||||
Cert: certPEM,
|
||||
Key: privkeyPEM,
|
||||
SSL: "enable",
|
||||
SSL: SSLEnable,
|
||||
SSLType: "import-paste",
|
||||
}
|
||||
if d.config.AutoRestart {
|
||||
|
||||
@@ -74,7 +74,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ type DeployerConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 阿里云 AccessKeySecret。
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
// 阿里云资源组 ID。
|
||||
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||
// 阿里云地域。
|
||||
Region string `json:"region"`
|
||||
// 部署资源类型。
|
||||
@@ -64,7 +66,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
return nil, fmt.Errorf("failed to create sdk clients: %w", err)
|
||||
}
|
||||
|
||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.Region)
|
||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.ResourceGroupId, config.Region)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
}
|
||||
@@ -79,7 +81,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
@@ -423,7 +425,7 @@ func createSdkClients(accessKeyId, accessKeySecret, region string) (*wSdkClients
|
||||
// 接入点一览 https://api.aliyun.com/product/Alb
|
||||
var albEndpoint string
|
||||
switch region {
|
||||
case "cn-hangzhou-finance":
|
||||
case "", "cn-hangzhou-finance":
|
||||
albEndpoint = "alb.cn-hangzhou.aliyuncs.com"
|
||||
default:
|
||||
albEndpoint = fmt.Sprintf("alb.%s.aliyuncs.com", region)
|
||||
@@ -463,7 +465,7 @@ func createSdkClients(accessKeyId, accessKeySecret, region string) (*wSdkClients
|
||||
}, nil
|
||||
}
|
||||
|
||||
func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Uploader, error) {
|
||||
func createSslUploader(accessKeyId, accessKeySecret, resourceGroupId, region string) (uploader.Uploader, error) {
|
||||
casRegion := region
|
||||
if casRegion != "" {
|
||||
// 阿里云 CAS 服务接入点是独立于 ALB 服务的
|
||||
@@ -479,6 +481,7 @@ func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Up
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: accessKeyId,
|
||||
AccessKeySecret: accessKeySecret,
|
||||
ResourceGroupId: resourceGroupId,
|
||||
Region: casRegion,
|
||||
})
|
||||
return uploader, err
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aliyun-cas"
|
||||
typeutil "github.com/usual2970/certimate/internal/pkg/utils/type"
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
@@ -23,6 +24,8 @@ type DeployerConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 阿里云 AccessKeySecret。
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
// 阿里云资源组 ID。
|
||||
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||
// 阿里云地域。
|
||||
Region string `json:"region"`
|
||||
// 服务类型。
|
||||
@@ -61,7 +64,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
return nil, fmt.Errorf("failed to create sdk clients: %w", err)
|
||||
}
|
||||
|
||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.Region)
|
||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.ResourceGroupId, config.Region)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
}
|
||||
@@ -76,7 +79,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
@@ -149,10 +152,11 @@ func (d *DeployerProvider) deployToCloudNative(ctx context.Context, certPEM stri
|
||||
}
|
||||
|
||||
listDomainsReq := &aliapig.ListDomainsRequest{
|
||||
GatewayId: tea.String(d.config.GatewayId),
|
||||
NameLike: tea.String(d.config.Domain),
|
||||
PageNumber: tea.Int32(listDomainsPageNumber),
|
||||
PageSize: tea.Int32(listDomainsPageSize),
|
||||
ResourceGroupId: typeutil.ToPtrOrZeroNil(d.config.ResourceGroupId),
|
||||
GatewayId: tea.String(d.config.GatewayId),
|
||||
NameLike: tea.String(d.config.Domain),
|
||||
PageNumber: tea.Int32(listDomainsPageNumber),
|
||||
PageSize: tea.Int32(listDomainsPageSize),
|
||||
}
|
||||
listDomainsResp, err := d.sdkClients.CloudNativeAPIGateway.ListDomains(listDomainsReq)
|
||||
d.logger.Debug("sdk request 'apig.ListDomains'", slog.Any("request", listDomainsReq), slog.Any("response", listDomainsResp))
|
||||
@@ -223,7 +227,7 @@ func (d *DeployerProvider) deployToCloudNative(ctx context.Context, certPEM stri
|
||||
|
||||
func createSdkClients(accessKeyId, accessKeySecret, region string) (*wSdkClients, error) {
|
||||
// 接入点一览 https://api.aliyun.com/product/APIG
|
||||
cloudNativeAPIGEndpoint := fmt.Sprintf("apig.%s.aliyuncs.com", region)
|
||||
cloudNativeAPIGEndpoint := strings.ReplaceAll(fmt.Sprintf("apig.%s.aliyuncs.com", region), "..", ".")
|
||||
cloudNativeAPIGConfig := &aliopen.Config{
|
||||
AccessKeyId: tea.String(accessKeyId),
|
||||
AccessKeySecret: tea.String(accessKeySecret),
|
||||
@@ -235,7 +239,7 @@ func createSdkClients(accessKeyId, accessKeySecret, region string) (*wSdkClients
|
||||
}
|
||||
|
||||
// 接入点一览 https://api.aliyun.com/product/CloudAPI
|
||||
traditionalAPIGEndpoint := fmt.Sprintf("apigateway.%s.aliyuncs.com", region)
|
||||
traditionalAPIGEndpoint := strings.ReplaceAll(fmt.Sprintf("apigateway.%s.aliyuncs.com", region), "..", ".")
|
||||
traditionalAPIGConfig := &aliopen.Config{
|
||||
AccessKeyId: tea.String(accessKeyId),
|
||||
AccessKeySecret: tea.String(accessKeySecret),
|
||||
@@ -252,7 +256,7 @@ func createSdkClients(accessKeyId, accessKeySecret, region string) (*wSdkClients
|
||||
}, nil
|
||||
}
|
||||
|
||||
func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Uploader, error) {
|
||||
func createSslUploader(accessKeyId, accessKeySecret, resourceGroupId, region string) (uploader.Uploader, error) {
|
||||
casRegion := region
|
||||
if casRegion != "" {
|
||||
// 阿里云 CAS 服务接入点是独立于 APIGateway 服务的
|
||||
@@ -268,6 +272,7 @@ func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Up
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: accessKeyId,
|
||||
AccessKeySecret: accessKeySecret,
|
||||
ResourceGroupId: resourceGroupId,
|
||||
Region: casRegion,
|
||||
})
|
||||
return uploader, err
|
||||
|
||||
@@ -22,12 +22,14 @@ type DeployerConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 阿里云 AccessKeySecret。
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
// 阿里云资源组 ID。
|
||||
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||
// 阿里云地域。
|
||||
Region string `json:"region"`
|
||||
// 阿里云云产品资源 ID 数组。
|
||||
ResourceIds []string `json:"resourceIds"`
|
||||
// 阿里云云联系人 ID 数组。
|
||||
// 零值时默认使用账号下第一个联系人。
|
||||
// 零值时使用账号下第一个联系人。
|
||||
ContactIds []string `json:"contactIds"`
|
||||
}
|
||||
|
||||
@@ -50,11 +52,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
AccessKeySecret: config.AccessKeySecret,
|
||||
Region: config.Region,
|
||||
})
|
||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.ResourceGroupId, config.Region)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
}
|
||||
@@ -69,7 +67,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
@@ -94,9 +92,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
||||
if len(contactIds) == 0 {
|
||||
// 获取联系人列表
|
||||
// REF: https://help.aliyun.com/zh/ssl-certificate/developer-reference/api-cas-2020-04-07-listcontact
|
||||
listContactReq := &alicas.ListContactRequest{}
|
||||
listContactReq.ShowSize = tea.Int32(1)
|
||||
listContactReq.CurrentPage = tea.Int32(1)
|
||||
listContactReq := &alicas.ListContactRequest{
|
||||
ShowSize: tea.Int32(1),
|
||||
CurrentPage: tea.Int32(1),
|
||||
}
|
||||
listContactResp, err := d.sdkClient.ListContact(listContactReq)
|
||||
d.logger.Debug("sdk request 'cas.ListContact'", slog.Any("request", listContactReq), slog.Any("response", listContactResp))
|
||||
if err != nil {
|
||||
@@ -157,14 +156,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
||||
}
|
||||
|
||||
func createSdkClient(accessKeyId, accessKeySecret, region string) (*alicas.Client, error) {
|
||||
if region == "" {
|
||||
region = "cn-hangzhou" // CAS 服务默认区域:华东一杭州
|
||||
}
|
||||
|
||||
// 接入点一览 https://api.aliyun.com/product/cas
|
||||
var endpoint string
|
||||
switch region {
|
||||
case "cn-hangzhou":
|
||||
case "", "cn-hangzhou":
|
||||
endpoint = "cas.aliyuncs.com"
|
||||
default:
|
||||
endpoint = fmt.Sprintf("cas.%s.aliyuncs.com", region)
|
||||
@@ -183,3 +178,25 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*alicas.Clien
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func createSslUploader(accessKeyId, accessKeySecret, resourceGroupId, region string) (uploader.Uploader, error) {
|
||||
casRegion := region
|
||||
if casRegion != "" {
|
||||
// 阿里云 CAS 服务接入点是独立于其他服务的
|
||||
// 国内版固定接入点:华东一杭州
|
||||
// 国际版固定接入点:亚太东南一新加坡
|
||||
if !strings.HasPrefix(casRegion, "cn-") {
|
||||
casRegion = "ap-southeast-1"
|
||||
} else {
|
||||
casRegion = "cn-hangzhou"
|
||||
}
|
||||
}
|
||||
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: accessKeyId,
|
||||
AccessKeySecret: accessKeySecret,
|
||||
ResourceGroupId: resourceGroupId,
|
||||
Region: casRegion,
|
||||
})
|
||||
return uploader, err
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ type DeployerConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 阿里云 AccessKeySecret。
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
// 阿里云资源组 ID。
|
||||
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||
// 阿里云地域。
|
||||
Region string `json:"region"`
|
||||
}
|
||||
@@ -35,6 +37,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
AccessKeySecret: config.AccessKeySecret,
|
||||
ResourceGroupId: config.ResourceGroupId,
|
||||
Region: config.Region,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -50,7 +53,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ type DeployerConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 阿里云 AccessKeySecret。
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
// 阿里云资源组 ID。
|
||||
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||
// 加速域名(支持泛域名)。
|
||||
Domain string `json:"domain"`
|
||||
}
|
||||
@@ -50,7 +52,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ type DeployerConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 阿里云 AccessKeySecret。
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
// 阿里云资源组 ID。
|
||||
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||
// 阿里云地域。
|
||||
Region string `json:"region"`
|
||||
// 部署资源类型。
|
||||
@@ -54,7 +56,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
|
||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.Region)
|
||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.ResourceGroupId, config.Region)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
}
|
||||
@@ -69,7 +71,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
@@ -283,7 +285,7 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*alislb.Clien
|
||||
// 接入点一览 https://api.aliyun.com/product/Slb
|
||||
var endpoint string
|
||||
switch region {
|
||||
case
|
||||
case "",
|
||||
"cn-hangzhou",
|
||||
"cn-hangzhou-finance",
|
||||
"cn-shanghai-finance-1",
|
||||
@@ -307,10 +309,11 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*alislb.Clien
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Uploader, error) {
|
||||
func createSslUploader(accessKeyId, accessKeySecret, resourceGroupId, region string) (uploader.Uploader, error) {
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: accessKeyId,
|
||||
AccessKeySecret: accessKeySecret,
|
||||
ResourceGroupId: resourceGroupId,
|
||||
Region: region,
|
||||
})
|
||||
return uploader, err
|
||||
|
||||
@@ -19,6 +19,8 @@ type DeployerConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 阿里云 AccessKeySecret。
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
// 阿里云资源组 ID。
|
||||
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||
// 加速域名(支持泛域名)。
|
||||
Domain string `json:"domain"`
|
||||
}
|
||||
@@ -50,7 +52,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ type DeployerConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 阿里云 AccessKeySecret。
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
// 阿里云资源组 ID。
|
||||
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||
// 阿里云地域。
|
||||
Region string `json:"region"`
|
||||
// 网站域名(支持泛域名)。
|
||||
@@ -47,7 +49,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
|
||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.Region)
|
||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.ResourceGroupId, config.Region)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
}
|
||||
@@ -62,7 +64,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
@@ -104,7 +106,7 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliddos.Clie
|
||||
config := &aliopen.Config{
|
||||
AccessKeyId: tea.String(accessKeyId),
|
||||
AccessKeySecret: tea.String(accessKeySecret),
|
||||
Endpoint: tea.String(fmt.Sprintf("ddoscoo.%s.aliyuncs.com", region)),
|
||||
Endpoint: tea.String(strings.ReplaceAll(fmt.Sprintf("ddoscoo.%s.aliyuncs.com", region), "..", ".")),
|
||||
}
|
||||
|
||||
client, err := aliddos.NewClient(config)
|
||||
@@ -115,7 +117,7 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliddos.Clie
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Uploader, error) {
|
||||
func createSslUploader(accessKeyId, accessKeySecret, resourceGroupId, region string) (uploader.Uploader, error) {
|
||||
casRegion := region
|
||||
if casRegion != "" {
|
||||
// 阿里云 CAS 服务接入点是独立于 Anti-DDoS 服务的
|
||||
@@ -131,6 +133,7 @@ func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Up
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: accessKeyId,
|
||||
AccessKeySecret: accessKeySecret,
|
||||
ResourceGroupId: resourceGroupId,
|
||||
Region: casRegion,
|
||||
})
|
||||
return uploader, err
|
||||
|
||||
@@ -22,6 +22,8 @@ type DeployerConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 阿里云 AccessKeySecret。
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
// 阿里云资源组 ID。
|
||||
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||
// 阿里云地域。
|
||||
Region string `json:"region"`
|
||||
// 阿里云 ESA 站点 ID。
|
||||
@@ -47,7 +49,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
|
||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.Region)
|
||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.ResourceGroupId, config.Region)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
}
|
||||
@@ -62,7 +64,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
@@ -105,7 +107,7 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliesa.Clien
|
||||
config := &aliopen.Config{
|
||||
AccessKeyId: tea.String(accessKeyId),
|
||||
AccessKeySecret: tea.String(accessKeySecret),
|
||||
Endpoint: tea.String(fmt.Sprintf("esa.%s.aliyuncs.com", region)),
|
||||
Endpoint: tea.String(strings.ReplaceAll(fmt.Sprintf("esa.%s.aliyuncs.com", region), "..", ".")),
|
||||
}
|
||||
|
||||
client, err := aliesa.NewClient(config)
|
||||
@@ -116,7 +118,7 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliesa.Clien
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Uploader, error) {
|
||||
func createSslUploader(accessKeyId, accessKeySecret, resourceGroupId, region string) (uploader.Uploader, error) {
|
||||
casRegion := region
|
||||
if casRegion != "" {
|
||||
// 阿里云 CAS 服务接入点是独立于 ESA 服务的
|
||||
@@ -132,6 +134,7 @@ func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Up
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: accessKeyId,
|
||||
AccessKeySecret: accessKeySecret,
|
||||
ResourceGroupId: resourceGroupId,
|
||||
Region: casRegion,
|
||||
})
|
||||
return uploader, err
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
||||
@@ -19,6 +20,8 @@ type DeployerConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 阿里云 AccessKeySecret。
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
// 阿里云资源组 ID。
|
||||
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||
// 阿里云地域。
|
||||
Region string `json:"region"`
|
||||
// 服务版本。
|
||||
@@ -60,7 +63,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
@@ -108,6 +111,9 @@ func (d *DeployerProvider) deployToFC3(ctx context.Context, certPEM string, priv
|
||||
TlsConfig: getCustomDomainResp.Body.TlsConfig,
|
||||
},
|
||||
}
|
||||
if tea.StringValue(updateCustomDomainReq.Body.Protocol) == "HTTP" {
|
||||
updateCustomDomainReq.Body.Protocol = tea.String("HTTP,HTTPS")
|
||||
}
|
||||
updateCustomDomainResp, err := d.sdkClients.FC3.UpdateCustomDomain(tea.String(d.config.Domain), updateCustomDomainReq)
|
||||
d.logger.Debug("sdk request 'fc.UpdateCustomDomain'", slog.Any("request", updateCustomDomainReq), slog.Any("response", updateCustomDomainResp))
|
||||
if err != nil {
|
||||
@@ -137,6 +143,9 @@ func (d *DeployerProvider) deployToFC2(ctx context.Context, certPEM string, priv
|
||||
Protocol: getCustomDomainResp.Body.Protocol,
|
||||
TlsConfig: getCustomDomainResp.Body.TlsConfig,
|
||||
}
|
||||
if tea.StringValue(updateCustomDomainReq.Protocol) == "HTTP" {
|
||||
updateCustomDomainReq.Protocol = tea.String("HTTP,HTTPS")
|
||||
}
|
||||
updateCustomDomainResp, err := d.sdkClients.FC2.UpdateCustomDomain(tea.String(d.config.Domain), updateCustomDomainReq)
|
||||
d.logger.Debug("sdk request 'fc.UpdateCustomDomain'", slog.Any("request", updateCustomDomainReq), slog.Any("response", updateCustomDomainResp))
|
||||
if err != nil {
|
||||
@@ -150,6 +159,8 @@ func createSdkClients(accessKeyId, accessKeySecret, region string) (*wSdkClients
|
||||
// 接入点一览 https://api.aliyun.com/product/FC-Open
|
||||
var fc2Endpoint string
|
||||
switch region {
|
||||
case "":
|
||||
fc2Endpoint = "fc.aliyuncs.com"
|
||||
case "cn-hangzhou-finance":
|
||||
fc2Endpoint = fmt.Sprintf("%s.fc.aliyuncs.com", region)
|
||||
default:
|
||||
@@ -167,7 +178,7 @@ func createSdkClients(accessKeyId, accessKeySecret, region string) (*wSdkClients
|
||||
}
|
||||
|
||||
// 接入点一览 https://api.aliyun.com/product/FC-Open
|
||||
fc3Endpoint := fmt.Sprintf("fcv3.%s.aliyuncs.com", region)
|
||||
fc3Endpoint := strings.ReplaceAll(fmt.Sprintf("fcv3.%s.aliyuncs.com", region), "..", ".")
|
||||
fc3Config := &aliopen.Config{
|
||||
AccessKeyId: tea.String(accessKeyId),
|
||||
AccessKeySecret: tea.String(accessKeySecret),
|
||||
|
||||
@@ -22,6 +22,8 @@ type DeployerConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 阿里云 AccessKeySecret。
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
// 阿里云资源组 ID。
|
||||
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||
// 部署资源类型。
|
||||
ResourceType ResourceType `json:"resourceType"`
|
||||
// 全球加速实例 ID。
|
||||
@@ -53,7 +55,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
|
||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret)
|
||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.ResourceGroupId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
}
|
||||
@@ -68,7 +70,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
@@ -200,6 +202,7 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudA
|
||||
listListenerCertificatesReq := &aliga.ListListenerCertificatesRequest{
|
||||
RegionId: tea.String("cn-hangzhou"),
|
||||
AcceleratorId: tea.String(d.config.AcceleratorId),
|
||||
ListenerId: tea.String(d.config.ListenerId),
|
||||
NextToken: listListenerCertificatesNextToken,
|
||||
MaxResults: tea.Int32(20),
|
||||
}
|
||||
@@ -312,10 +315,11 @@ func createSdkClient(accessKeyId, accessKeySecret string) (*aliga.Client, error)
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func createSslUploader(accessKeyId, accessKeySecret string) (uploader.Uploader, error) {
|
||||
func createSslUploader(accessKeyId, accessKeySecret, resourceGroupId string) (uploader.Uploader, error) {
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: accessKeyId,
|
||||
AccessKeySecret: accessKeySecret,
|
||||
ResourceGroupId: resourceGroupId,
|
||||
Region: "cn-hangzhou",
|
||||
})
|
||||
return uploader, err
|
||||
|
||||
@@ -19,6 +19,8 @@ type DeployerConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 阿里云 AccessKeySecret。
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
// 阿里云资源组 ID。
|
||||
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||
// 阿里云地域。
|
||||
Region string `json:"region"`
|
||||
// 直播流域名(支持泛域名)。
|
||||
@@ -52,7 +54,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
@@ -86,7 +88,7 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*alilive.Clie
|
||||
// 接入点一览 https://api.aliyun.com/product/live
|
||||
var endpoint string
|
||||
switch region {
|
||||
case
|
||||
case "",
|
||||
"cn-qingdao",
|
||||
"cn-beijing",
|
||||
"cn-shanghai",
|
||||
|
||||
@@ -21,6 +21,8 @@ type DeployerConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 阿里云 AccessKeySecret。
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
// 阿里云资源组 ID。
|
||||
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||
// 阿里云地域。
|
||||
Region string `json:"region"`
|
||||
// 部署资源类型。
|
||||
@@ -52,7 +54,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
|
||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.Region)
|
||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.ResourceGroupId, config.Region)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
}
|
||||
@@ -67,7 +69,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
@@ -224,12 +226,7 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL
|
||||
|
||||
func createSdkClient(accessKeyId, accessKeySecret, region string) (*alinlb.Client, error) {
|
||||
// 接入点一览 https://api.aliyun.com/product/Nlb
|
||||
var endpoint string
|
||||
switch region {
|
||||
default:
|
||||
endpoint = fmt.Sprintf("nlb.%s.aliyuncs.com", region)
|
||||
}
|
||||
|
||||
endpoint := strings.ReplaceAll(fmt.Sprintf("nlb.%s.aliyuncs.com", region), "..", ".")
|
||||
config := &aliopen.Config{
|
||||
AccessKeyId: tea.String(accessKeyId),
|
||||
AccessKeySecret: tea.String(accessKeySecret),
|
||||
@@ -244,7 +241,7 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*alinlb.Clien
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Uploader, error) {
|
||||
func createSslUploader(accessKeyId, accessKeySecret, resourceGroupId, region string) (uploader.Uploader, error) {
|
||||
casRegion := region
|
||||
if casRegion != "" {
|
||||
// 阿里云 CAS 服务接入点是独立于 NLB 服务的
|
||||
@@ -260,6 +257,7 @@ func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Up
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: accessKeyId,
|
||||
AccessKeySecret: accessKeySecret,
|
||||
ResourceGroupId: resourceGroupId,
|
||||
Region: casRegion,
|
||||
})
|
||||
return uploader, err
|
||||
|
||||
@@ -16,6 +16,8 @@ type DeployerConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 阿里云 AccessKeySecret。
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
// 阿里云资源组 ID。
|
||||
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||
// 阿里云地域。
|
||||
Region string `json:"region"`
|
||||
// 存储桶名。
|
||||
@@ -51,7 +53,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
||||
@@ -18,6 +19,8 @@ type DeployerConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 阿里云 AccessKeySecret。
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
// 阿里云资源组 ID。
|
||||
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||
// 阿里云地域。
|
||||
Region string `json:"region"`
|
||||
// 点播加速域名(不支持泛域名)。
|
||||
@@ -51,7 +54,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
@@ -80,8 +83,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
||||
|
||||
func createSdkClient(accessKeyId, accessKeySecret, region string) (*alivod.Client, error) {
|
||||
// 接入点一览 https://api.aliyun.com/product/vod
|
||||
endpoint := fmt.Sprintf("vod.%s.aliyuncs.com", region)
|
||||
|
||||
endpoint := strings.ReplaceAll(fmt.Sprintf("vod.%s.aliyuncs.com", region), "..", ".")
|
||||
config := &aliopen.Config{
|
||||
AccessKeyId: tea.String(accessKeyId),
|
||||
AccessKeySecret: tea.String(accessKeySecret),
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aliyun-cas"
|
||||
sliceutil "github.com/usual2970/certimate/internal/pkg/utils/slice"
|
||||
typeutil "github.com/usual2970/certimate/internal/pkg/utils/type"
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
@@ -22,6 +23,8 @@ type DeployerConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 阿里云 AccessKeySecret。
|
||||
AccessKeySecret string `json:"accessKeySecret"`
|
||||
// 阿里云资源组 ID。
|
||||
ResourceGroupId string `json:"resourceGroupId,omitempty"`
|
||||
// 阿里云地域。
|
||||
Region string `json:"region"`
|
||||
// 服务版本。
|
||||
@@ -51,7 +54,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
|
||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.Region)
|
||||
uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.ResourceGroupId, config.Region)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
}
|
||||
@@ -66,7 +69,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
@@ -107,8 +110,9 @@ func (d *DeployerProvider) deployToWAF3(ctx context.Context, certPEM string, pri
|
||||
// 查询默认 SSL/TLS 设置
|
||||
// REF: https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-describedefaulthttps
|
||||
describeDefaultHttpsReq := &aliwaf.DescribeDefaultHttpsRequest{
|
||||
InstanceId: tea.String(d.config.InstanceId),
|
||||
RegionId: tea.String(d.config.Region),
|
||||
ResourceManagerResourceGroupId: typeutil.ToPtrOrZeroNil(d.config.ResourceGroupId),
|
||||
InstanceId: tea.String(d.config.InstanceId),
|
||||
RegionId: tea.String(d.config.Region),
|
||||
}
|
||||
describeDefaultHttpsResp, err := d.sdkClient.DescribeDefaultHttps(describeDefaultHttpsReq)
|
||||
d.logger.Debug("sdk request 'waf.DescribeDefaultHttps'", slog.Any("request", describeDefaultHttpsReq), slog.Any("response", describeDefaultHttpsResp))
|
||||
@@ -119,11 +123,12 @@ func (d *DeployerProvider) deployToWAF3(ctx context.Context, certPEM string, pri
|
||||
// 修改默认 SSL/TLS 设置
|
||||
// REF: https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-modifydefaulthttps
|
||||
modifyDefaultHttpsReq := &aliwaf.ModifyDefaultHttpsRequest{
|
||||
InstanceId: tea.String(d.config.InstanceId),
|
||||
RegionId: tea.String(d.config.Region),
|
||||
CertId: tea.String(upres.CertId),
|
||||
TLSVersion: tea.String("tlsv1"),
|
||||
EnableTLSv3: tea.Bool(false),
|
||||
ResourceManagerResourceGroupId: typeutil.ToPtrOrZeroNil(d.config.ResourceGroupId),
|
||||
InstanceId: tea.String(d.config.InstanceId),
|
||||
RegionId: tea.String(d.config.Region),
|
||||
CertId: tea.String(upres.CertId),
|
||||
TLSVersion: tea.String("tlsv1"),
|
||||
EnableTLSv3: tea.Bool(false),
|
||||
}
|
||||
if describeDefaultHttpsResp.Body != nil && describeDefaultHttpsResp.Body.DefaultHttps != nil {
|
||||
modifyDefaultHttpsReq.TLSVersion = describeDefaultHttpsResp.Body.DefaultHttps.TLSVersion
|
||||
@@ -172,10 +177,11 @@ func (d *DeployerProvider) deployToWAF3(ctx context.Context, certPEM string, pri
|
||||
|
||||
func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliwaf.Client, error) {
|
||||
// 接入点一览:https://api.aliyun.com/product/waf-openapi
|
||||
endpoint := strings.ReplaceAll(fmt.Sprintf("wafopenapi.%s.aliyuncs.com", region), "..", ".")
|
||||
config := &aliopen.Config{
|
||||
AccessKeyId: tea.String(accessKeyId),
|
||||
AccessKeySecret: tea.String(accessKeySecret),
|
||||
Endpoint: tea.String(fmt.Sprintf("wafopenapi.%s.aliyuncs.com", region)),
|
||||
Endpoint: tea.String(endpoint),
|
||||
}
|
||||
|
||||
client, err := aliwaf.NewClient(config)
|
||||
@@ -186,7 +192,7 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliwaf.Clien
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Uploader, error) {
|
||||
func createSslUploader(accessKeyId, accessKeySecret, resourceGroupId, region string) (uploader.Uploader, error) {
|
||||
casRegion := region
|
||||
if casRegion != "" {
|
||||
// 阿里云 CAS 服务接入点是独立于 WAF 服务的
|
||||
@@ -202,6 +208,7 @@ func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Up
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: accessKeyId,
|
||||
AccessKeySecret: accessKeySecret,
|
||||
ResourceGroupId: resourceGroupId,
|
||||
Region: casRegion,
|
||||
})
|
||||
return uploader, err
|
||||
|
||||
125
internal/pkg/core/deployer/providers/apisix/apisix.go
Normal file
125
internal/pkg/core/deployer/providers/apisix/apisix.go
Normal file
@@ -0,0 +1,125 @@
|
||||
package apisix
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/url"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
apisixsdk "github.com/usual2970/certimate/internal/pkg/sdk3rd/apisix"
|
||||
certutil "github.com/usual2970/certimate/internal/pkg/utils/cert"
|
||||
typeutil "github.com/usual2970/certimate/internal/pkg/utils/type"
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// APISIX 服务地址。
|
||||
ServerUrl string `json:"serverUrl"`
|
||||
// APISIX Admin API Key。
|
||||
ApiKey string `json:"apiKey"`
|
||||
// 是否允许不安全的连接。
|
||||
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||
// 部署资源类型。
|
||||
ResourceType ResourceType `json:"resourceType"`
|
||||
// 证书 ID。
|
||||
// 部署资源类型为 [RESOURCE_TYPE_CERTIFICATE] 时必填。
|
||||
CertificateId string `json:"certificateId,omitempty"`
|
||||
}
|
||||
|
||||
type DeployerProvider struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *apisixsdk.Client
|
||||
}
|
||||
|
||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
||||
|
||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
if config == nil {
|
||||
panic("config is nil")
|
||||
}
|
||||
|
||||
client, err := createSdkClient(config.ServerUrl, config.ApiKey, config.AllowInsecureConnections)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
|
||||
return &DeployerProvider{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkClient: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||
// 根据部署资源类型决定部署方式
|
||||
switch d.config.ResourceType {
|
||||
case RESOURCE_TYPE_CERTIFICATE:
|
||||
if err := d.deployToCertificate(ctx, certPEM, privkeyPEM); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported resource type '%s'", d.config.ResourceType)
|
||||
}
|
||||
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPEM string, privkeyPEM string) error {
|
||||
if d.config.CertificateId == "" {
|
||||
return errors.New("config `certificateId` is required")
|
||||
}
|
||||
|
||||
// 解析证书内容
|
||||
certX509, err := certutil.ParseCertificateFromPEM(certPEM)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 更新 SSL 证书
|
||||
// REF: https://apisix.apache.org/zh/docs/apisix/admin-api/#ssl
|
||||
updateSSLReq := &apisixsdk.UpdateSSLRequest{
|
||||
ID: d.config.CertificateId,
|
||||
Cert: typeutil.ToPtr(certPEM),
|
||||
Key: typeutil.ToPtr(privkeyPEM),
|
||||
SNIs: typeutil.ToPtr(certX509.DNSNames),
|
||||
Type: typeutil.ToPtr("server"),
|
||||
Status: typeutil.ToPtr(int32(1)),
|
||||
}
|
||||
updateSSLResp, err := d.sdkClient.UpdateSSL(updateSSLReq)
|
||||
d.logger.Debug("sdk request 'apisix.UpdateSSL'", slog.Any("request", updateSSLReq), slog.Any("response", updateSSLResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'apisix.UpdateSSL': %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createSdkClient(serverUrl, apiKey string, skipTlsVerify bool) (*apisixsdk.Client, error) {
|
||||
if _, err := url.Parse(serverUrl); err != nil {
|
||||
return nil, errors.New("invalid apisix server url")
|
||||
}
|
||||
|
||||
if apiKey == "" {
|
||||
return nil, errors.New("invalid apisix api key")
|
||||
}
|
||||
|
||||
client := apisixsdk.NewClient(serverUrl, apiKey)
|
||||
if skipTlsVerify {
|
||||
client.WithTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
77
internal/pkg/core/deployer/providers/apisix/apisix_test.go
Normal file
77
internal/pkg/core/deployer/providers/apisix/apisix_test.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package apisix_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/apisix"
|
||||
)
|
||||
|
||||
var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fServerUrl string
|
||||
fApiKey string
|
||||
fCertificateId string
|
||||
)
|
||||
|
||||
func init() {
|
||||
argsPrefix := "CERTIMATE_DEPLOYER_APISIX_"
|
||||
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fServerUrl, argsPrefix+"SERVERURL", "", "")
|
||||
flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "")
|
||||
flag.StringVar(&fCertificateId, argsPrefix+"CERTIFICATEID", "", "")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./apisix_test.go -args \
|
||||
--CERTIMATE_DEPLOYER_APISIX_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||
--CERTIMATE_DEPLOYER_APISIX_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--CERTIMATE_DEPLOYER_APISIX_SERVERURL="http://127.0.0.1:9080" \
|
||||
--CERTIMATE_DEPLOYER_APISIX_APIKEY="your-api-key" \
|
||||
--CERTIMATE_DEPLOYER_APISIX_CERTIFICATEID="your-cerficiate-id"
|
||||
*/
|
||||
func TestDeploy(t *testing.T) {
|
||||
flag.Parse()
|
||||
|
||||
t.Run("Deploy", func(t *testing.T) {
|
||||
t.Log(strings.Join([]string{
|
||||
"args:",
|
||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||
fmt.Sprintf("SERVERURL: %v", fServerUrl),
|
||||
fmt.Sprintf("APIKEY: %v", fApiKey),
|
||||
fmt.Sprintf("CERTIFICATEID: %v", fCertificateId),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||
ServerUrl: fServerUrl,
|
||||
ApiKey: fApiKey,
|
||||
AllowInsecureConnections: true,
|
||||
ResourceType: provider.RESOURCE_TYPE_CERTIFICATE,
|
||||
CertificateId: fCertificateId,
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fInputCertData, _ := os.ReadFile(fInputCertPath)
|
||||
fInputKeyData, _ := os.ReadFile(fInputKeyPath)
|
||||
res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
t.Logf("ok: %v", res)
|
||||
})
|
||||
}
|
||||
8
internal/pkg/core/deployer/providers/apisix/consts.go
Normal file
8
internal/pkg/core/deployer/providers/apisix/consts.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package apisix
|
||||
|
||||
type ResourceType string
|
||||
|
||||
const (
|
||||
// 资源类型:替换指定证书。
|
||||
RESOURCE_TYPE_CERTIFICATE = ResourceType("certificate")
|
||||
)
|
||||
@@ -66,7 +66,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ import (
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aws-acm"
|
||||
uploaderspacm "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aws-acm"
|
||||
uploaderspiam "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aws-iam"
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
@@ -26,6 +27,9 @@ type DeployerConfig struct {
|
||||
Region string `json:"region"`
|
||||
// AWS CloudFront 分配 ID。
|
||||
DistributionId string `json:"distributionId"`
|
||||
// AWS CloudFront 证书来源。
|
||||
// 可取值 "ACM"、"IAM"。
|
||||
CertificateSource string `json:"certificateSource"`
|
||||
}
|
||||
|
||||
type DeployerProvider struct {
|
||||
@@ -47,13 +51,28 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
SecretAccessKey: config.SecretAccessKey,
|
||||
Region: config.Region,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
var uploader uploader.Uploader
|
||||
if config.CertificateSource == "ACM" {
|
||||
uploader, err = uploaderspacm.NewUploader(&uploaderspacm.UploaderConfig{
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
SecretAccessKey: config.SecretAccessKey,
|
||||
Region: config.Region,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
}
|
||||
} else if config.CertificateSource == "IAM" {
|
||||
uploader, err = uploaderspiam.NewUploader(&uploaderspiam.UploaderConfig{
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
SecretAccessKey: config.SecretAccessKey,
|
||||
Region: config.Region,
|
||||
CertificatePath: "/cloudfront/",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("unsupported certificate source: '%s'", config.CertificateSource)
|
||||
}
|
||||
|
||||
return &DeployerProvider{
|
||||
@@ -66,7 +85,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
@@ -79,7 +98,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
||||
return nil, errors.New("config `distribuitionId` is required")
|
||||
}
|
||||
|
||||
// 上传证书到 ACM
|
||||
// 上传证书到 ACM/IAM
|
||||
upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
|
||||
@@ -109,7 +128,19 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
||||
updateDistributionReq.DistributionConfig.ViewerCertificate = &types.ViewerCertificate{}
|
||||
}
|
||||
updateDistributionReq.DistributionConfig.ViewerCertificate.CloudFrontDefaultCertificate = aws.Bool(false)
|
||||
updateDistributionReq.DistributionConfig.ViewerCertificate.ACMCertificateArn = aws.String(upres.CertId)
|
||||
if d.config.CertificateSource == "ACM" {
|
||||
updateDistributionReq.DistributionConfig.ViewerCertificate.ACMCertificateArn = aws.String(upres.CertId)
|
||||
updateDistributionReq.DistributionConfig.ViewerCertificate.IAMCertificateId = nil
|
||||
} else if d.config.CertificateSource == "IAM" {
|
||||
updateDistributionReq.DistributionConfig.ViewerCertificate.ACMCertificateArn = nil
|
||||
updateDistributionReq.DistributionConfig.ViewerCertificate.IAMCertificateId = aws.String(upres.CertId)
|
||||
if updateDistributionReq.DistributionConfig.ViewerCertificate.MinimumProtocolVersion == "" {
|
||||
updateDistributionReq.DistributionConfig.ViewerCertificate.MinimumProtocolVersion = types.MinimumProtocolVersionTLSv1
|
||||
}
|
||||
if updateDistributionReq.DistributionConfig.ViewerCertificate.SSLSupportMethod == "" {
|
||||
updateDistributionReq.DistributionConfig.ViewerCertificate.SSLSupportMethod = types.SSLSupportMethodSniOnly
|
||||
}
|
||||
}
|
||||
updateDistributionResp, err := d.sdkClient.UpdateDistribution(context.TODO(), updateDistributionReq)
|
||||
d.logger.Debug("sdk request 'cloudfront.UpdateDistribution'", slog.Any("request", updateDistributionReq), slog.Any("response", updateDistributionResp))
|
||||
if err != nil {
|
||||
|
||||
75
internal/pkg/core/deployer/providers/aws-iam/aws_iam.go
Normal file
75
internal/pkg/core/deployer/providers/aws-iam/aws_iam.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package awsiam
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aws-iam"
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// AWS AccessKeyId。
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// AWS SecretAccessKey。
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
// AWS 区域。
|
||||
Region string `json:"region"`
|
||||
// IAM 证书路径。
|
||||
// 选填。
|
||||
CertificatePath string `json:"certificatePath,omitempty"`
|
||||
}
|
||||
|
||||
type DeployerProvider struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sslUploader uploader.Uploader
|
||||
}
|
||||
|
||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
||||
|
||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
if config == nil {
|
||||
panic("config is nil")
|
||||
}
|
||||
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
SecretAccessKey: config.SecretAccessKey,
|
||||
Region: config.Region,
|
||||
CertificatePath: config.CertificatePath,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
}
|
||||
|
||||
return &DeployerProvider{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sslUploader: uploader,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
d.sslUploader.WithLogger(logger)
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||
// 上传证书到 IAM
|
||||
upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
|
||||
} else {
|
||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
||||
}
|
||||
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
@@ -76,7 +76,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
@@ -285,6 +285,7 @@ func (d *DeployerProvider) updateHttpsListenerCertificate(ctx context.Context, c
|
||||
ClientToken: generateClientToken(),
|
||||
ListenerPort: uint16(cloudHttpsListenerPort),
|
||||
Scheduler: describeAppHTTPSListenersResp.ListenerList[0].Scheduler,
|
||||
CertIds: describeAppHTTPSListenersResp.ListenerList[0].CertIds,
|
||||
AdditionalCertDomains: sliceutil.Map(describeAppHTTPSListenersResp.ListenerList[0].AdditionalCertDomains, func(domain bceappblb.AdditionalCertDomainsModel) bceappblb.AdditionalCertDomainsModel {
|
||||
if domain.Host == d.config.Domain {
|
||||
return bceappblb.AdditionalCertDomainsModel{
|
||||
|
||||
@@ -74,7 +74,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
@@ -283,6 +283,7 @@ func (d *DeployerProvider) updateHttpsListenerCertificate(ctx context.Context, c
|
||||
updateHTTPSListenerReq := &bceblb.UpdateHTTPSListenerArgs{
|
||||
ClientToken: generateClientToken(),
|
||||
ListenerPort: uint16(cloudHttpsListenerPort),
|
||||
CertIds: describeHTTPSListenersResp.ListenerList[0].CertIds,
|
||||
AdditionalCertDomains: sliceutil.Map(describeHTTPSListenersResp.ListenerList[0].AdditionalCertDomains, func(domain bceblb.AdditionalCertDomainsModel) bceblb.AdditionalCertDomainsModel {
|
||||
if domain.Host == d.config.Domain {
|
||||
return bceblb.AdditionalCertDomainsModel{
|
||||
|
||||
@@ -48,7 +48,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ type DeployerConfig struct {
|
||||
// 网站名称。
|
||||
SiteName string `json:"siteName"`
|
||||
// 网站 SSL 端口。
|
||||
// 零值时默认为 443。
|
||||
// 零值时默认值 443。
|
||||
SitePort int32 `json:"sitePort,omitempty"`
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
@@ -116,7 +116,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
||||
SiteId: siteId,
|
||||
Type: typeutil.ToPtr("openCert"),
|
||||
Server: &btsdk.SiteServerInfo{
|
||||
ListenSSLPort: typeutil.ToPtr(d.config.SitePort),
|
||||
ListenSSLPorts: typeutil.ToPtr([]int32{d.config.SitePort}),
|
||||
SSL: &btsdk.SiteServerSSLInfo{
|
||||
IsSSL: typeutil.ToPtr(int32(1)),
|
||||
FullChain: typeutil.ToPtr(certPEM),
|
||||
|
||||
@@ -39,7 +39,7 @@ Shell command to run this test:
|
||||
--CERTIMATE_DEPLOYER_BAOTAWAFSITE_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--CERTIMATE_DEPLOYER_BAOTAWAFSITE_SERVERURL="http://127.0.0.1:8888" \
|
||||
--CERTIMATE_DEPLOYER_BAOTAWAFSITE_APIKEY="your-api-key" \
|
||||
--CERTIMATE_DEPLOYER_BAOTAWAFSITE_SITENAME="your-site-name"\
|
||||
--CERTIMATE_DEPLOYER_BAOTAWAFSITE_SITENAME="your-site-name" \
|
||||
--CERTIMATE_DEPLOYER_BAOTAWAFSITE_SITEPORT=443
|
||||
*/
|
||||
func TestDeploy(t *testing.T) {
|
||||
|
||||
@@ -41,7 +41,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
package ctcccloudao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/ctcccloud-ao"
|
||||
ctyunao "github.com/usual2970/certimate/internal/pkg/sdk3rd/ctyun/ao"
|
||||
typeutil "github.com/usual2970/certimate/internal/pkg/utils/type"
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// 天翼云 AccessKeyId。
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 天翼云 SecretAccessKey。
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
// 加速域名(支持泛域名)。
|
||||
Domain string `json:"domain"`
|
||||
}
|
||||
|
||||
type DeployerProvider struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *ctyunao.Client
|
||||
sslUploader uploader.Uploader
|
||||
}
|
||||
|
||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
||||
|
||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
if config == nil {
|
||||
panic("config is nil")
|
||||
}
|
||||
|
||||
client, err := createSdkClient(config.AccessKeyId, config.SecretAccessKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
SecretAccessKey: config.SecretAccessKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
}
|
||||
|
||||
return &DeployerProvider{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkClient: client,
|
||||
sslUploader: uploader,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||
if d.config.Domain == "" {
|
||||
return nil, errors.New("config `domain` is required")
|
||||
}
|
||||
|
||||
// 上传证书到 AccessOne
|
||||
upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
|
||||
} else {
|
||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
||||
}
|
||||
|
||||
// 域名基础及加速配置查询
|
||||
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=113&api=13412&data=174&isNormal=1&vid=167
|
||||
getDomainConfigReq := &ctyunao.GetDomainConfigRequest{
|
||||
Domain: typeutil.ToPtr(d.config.Domain),
|
||||
}
|
||||
getDomainConfigResp, err := d.sdkClient.GetDomainConfig(getDomainConfigReq)
|
||||
d.logger.Debug("sdk request 'cdn.GetDomainConfig'", slog.Any("request", getDomainConfigReq), slog.Any("response", getDomainConfigResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'cdn.GetDomainConfig': %w", err)
|
||||
}
|
||||
|
||||
// 域名基础及加速配置修改
|
||||
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=113&api=13413&data=174&isNormal=1&vid=167
|
||||
modifyDomainConfigReq := &ctyunao.ModifyDomainConfigRequest{
|
||||
Domain: typeutil.ToPtr(d.config.Domain),
|
||||
ProductCode: typeutil.ToPtr(getDomainConfigResp.ReturnObj.ProductCode),
|
||||
Origin: getDomainConfigResp.ReturnObj.Origin,
|
||||
HttpsStatus: typeutil.ToPtr("on"),
|
||||
CertName: typeutil.ToPtr(upres.CertName),
|
||||
}
|
||||
modifyDomainConfigResp, err := d.sdkClient.ModifyDomainConfig(modifyDomainConfigReq)
|
||||
d.logger.Debug("sdk request 'cdn.ModifyDomainConfig'", slog.Any("request", modifyDomainConfigReq), slog.Any("response", modifyDomainConfigResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'cdn.ModifyDomainConfig': %w", err)
|
||||
}
|
||||
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
|
||||
func createSdkClient(accessKeyId, secretAccessKey string) (*ctyunao.Client, error) {
|
||||
return ctyunao.NewClient(accessKeyId, secretAccessKey)
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package ctcccloudao_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-ao"
|
||||
)
|
||||
|
||||
var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fAccessKeyId string
|
||||
fSecretAccessKey string
|
||||
fDomain string
|
||||
)
|
||||
|
||||
func init() {
|
||||
argsPrefix := "CERTIMATE_DEPLOYER_CTCCCLOUDAO_"
|
||||
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
|
||||
flag.StringVar(&fSecretAccessKey, argsPrefix+"SECRETACCESSKEY", "", "")
|
||||
flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./ctcccloud_ao_test.go -args \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDAO_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDAO_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDAO_ACCESSKEYID="your-access-key-id" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDAO_SECRETACCESSKEY="your-secret-access-key" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDAO_DOMAIN="example.com"
|
||||
*/
|
||||
func TestDeploy(t *testing.T) {
|
||||
flag.Parse()
|
||||
|
||||
t.Run("Deploy", func(t *testing.T) {
|
||||
t.Log(strings.Join([]string{
|
||||
"args:",
|
||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||
fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId),
|
||||
fmt.Sprintf("SECRETACCESSKEY: %v", fSecretAccessKey),
|
||||
fmt.Sprintf("DOMAIN: %v", fDomain),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||
AccessKeyId: fAccessKeyId,
|
||||
SecretAccessKey: fSecretAccessKey,
|
||||
Domain: fDomain,
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fInputCertData, _ := os.ReadFile(fInputCertPath)
|
||||
fInputKeyData, _ := os.ReadFile(fInputKeyPath)
|
||||
res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
t.Logf("ok: %v", res)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package ctcccloudcdn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/ctcccloud-cdn"
|
||||
ctyuncdn "github.com/usual2970/certimate/internal/pkg/sdk3rd/ctyun/cdn"
|
||||
typeutil "github.com/usual2970/certimate/internal/pkg/utils/type"
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// 天翼云 AccessKeyId。
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 天翼云 SecretAccessKey。
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
// 加速域名(支持泛域名)。
|
||||
Domain string `json:"domain"`
|
||||
}
|
||||
|
||||
type DeployerProvider struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *ctyuncdn.Client
|
||||
sslUploader uploader.Uploader
|
||||
}
|
||||
|
||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
||||
|
||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
if config == nil {
|
||||
panic("config is nil")
|
||||
}
|
||||
|
||||
client, err := createSdkClient(config.AccessKeyId, config.SecretAccessKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
SecretAccessKey: config.SecretAccessKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
}
|
||||
|
||||
return &DeployerProvider{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkClient: client,
|
||||
sslUploader: uploader,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||
if d.config.Domain == "" {
|
||||
return nil, errors.New("config `domain` is required")
|
||||
}
|
||||
|
||||
// 上传证书到 CDN
|
||||
upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
|
||||
} else {
|
||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
||||
}
|
||||
|
||||
// 查询域名配置信息
|
||||
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=108&api=11304&data=161&isNormal=1&vid=154
|
||||
queryDomainDetailReq := &ctyuncdn.QueryDomainDetailRequest{
|
||||
Domain: typeutil.ToPtr(d.config.Domain),
|
||||
}
|
||||
queryDomainDetailResp, err := d.sdkClient.QueryDomainDetail(queryDomainDetailReq)
|
||||
d.logger.Debug("sdk request 'cdn.QueryDomainDetail'", slog.Any("request", queryDomainDetailReq), slog.Any("response", queryDomainDetailResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'cdn.QueryDomainDetail': %w", err)
|
||||
}
|
||||
|
||||
// 修改域名配置
|
||||
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=108&api=11308&data=161&isNormal=1&vid=154
|
||||
updateDomainReq := &ctyuncdn.UpdateDomainRequest{
|
||||
Domain: typeutil.ToPtr(d.config.Domain),
|
||||
HttpsStatus: typeutil.ToPtr("on"),
|
||||
CertName: typeutil.ToPtr(upres.CertName),
|
||||
}
|
||||
updateDomainResp, err := d.sdkClient.UpdateDomain(updateDomainReq)
|
||||
d.logger.Debug("sdk request 'cdn.UpdateDomain'", slog.Any("request", updateDomainReq), slog.Any("response", updateDomainResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'cdn.UpdateDomain': %w", err)
|
||||
}
|
||||
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
|
||||
func createSdkClient(accessKeyId, secretAccessKey string) (*ctyuncdn.Client, error) {
|
||||
return ctyuncdn.NewClient(accessKeyId, secretAccessKey)
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package ctcccloudcdn_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-cdn"
|
||||
)
|
||||
|
||||
var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fAccessKeyId string
|
||||
fSecretAccessKey string
|
||||
fDomain string
|
||||
)
|
||||
|
||||
func init() {
|
||||
argsPrefix := "CERTIMATE_DEPLOYER_CTCCCLOUDCDN_"
|
||||
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
|
||||
flag.StringVar(&fSecretAccessKey, argsPrefix+"SECRETACCESSKEY", "", "")
|
||||
flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./ctcccloud_cdn_test.go -args \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDCDN_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDCDN_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDCDN_ACCESSKEYID="your-access-key-id" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDCDN_SECRETACCESSKEY="your-secret-access-key" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDCDN_DOMAIN="example.com"
|
||||
*/
|
||||
func TestDeploy(t *testing.T) {
|
||||
flag.Parse()
|
||||
|
||||
t.Run("Deploy", func(t *testing.T) {
|
||||
t.Log(strings.Join([]string{
|
||||
"args:",
|
||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||
fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId),
|
||||
fmt.Sprintf("SECRETACCESSKEY: %v", fSecretAccessKey),
|
||||
fmt.Sprintf("DOMAIN: %v", fDomain),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||
AccessKeyId: fAccessKeyId,
|
||||
SecretAccessKey: fSecretAccessKey,
|
||||
Domain: fDomain,
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fInputCertData, _ := os.ReadFile(fInputCertPath)
|
||||
fInputKeyData, _ := os.ReadFile(fInputKeyPath)
|
||||
res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
t.Logf("ok: %v", res)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package ctcccloudcms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/ctcccloud-cms"
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// 天翼云 AccessKeyId。
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 天翼云 SecretAccessKey。
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
}
|
||||
|
||||
type DeployerProvider struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sslUploader uploader.Uploader
|
||||
}
|
||||
|
||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
||||
|
||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
if config == nil {
|
||||
panic("config is nil")
|
||||
}
|
||||
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
SecretAccessKey: config.SecretAccessKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
}
|
||||
|
||||
return &DeployerProvider{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sslUploader: uploader,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||
// 上传证书到 CMS
|
||||
upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
|
||||
} else {
|
||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
||||
}
|
||||
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package ctcccloudcms_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-cms"
|
||||
)
|
||||
|
||||
var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fAccessKeyId string
|
||||
fSecretAccessKey string
|
||||
)
|
||||
|
||||
func init() {
|
||||
argsPrefix := "CERTIMATE_DEPLOYER_CTCCCLOUDCMS_"
|
||||
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
|
||||
flag.StringVar(&fSecretAccessKey, argsPrefix+"SECRETACCESSKEY", "", "")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./ctcccloud_cms_test.go -args \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDCMS_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDCMS_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDCMS_ACCESSKEYID="your-access-key-id" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDCMS_SECRETACCESSKEY="your-secret-access-key"
|
||||
*/
|
||||
func TestDeploy(t *testing.T) {
|
||||
flag.Parse()
|
||||
|
||||
t.Run("Deploy", func(t *testing.T) {
|
||||
t.Log(strings.Join([]string{
|
||||
"args:",
|
||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||
fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId),
|
||||
fmt.Sprintf("SECRETACCESSKEY: %v", fSecretAccessKey),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||
AccessKeyId: fAccessKeyId,
|
||||
SecretAccessKey: fSecretAccessKey,
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fInputCertData, _ := os.ReadFile(fInputCertPath)
|
||||
fInputKeyData, _ := os.ReadFile(fInputKeyPath)
|
||||
res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
t.Logf("ok: %v", res)
|
||||
})
|
||||
}
|
||||
10
internal/pkg/core/deployer/providers/ctcccloud-elb/consts.go
Normal file
10
internal/pkg/core/deployer/providers/ctcccloud-elb/consts.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package ctcccloudelb
|
||||
|
||||
type ResourceType string
|
||||
|
||||
const (
|
||||
// 资源类型:部署到指定负载均衡器。
|
||||
RESOURCE_TYPE_LOADBALANCER = ResourceType("loadbalancer")
|
||||
// 资源类型:部署到指定监听器。
|
||||
RESOURCE_TYPE_LISTENER = ResourceType("listener")
|
||||
)
|
||||
@@ -0,0 +1,199 @@
|
||||
package ctcccloudelb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/ctcccloud-elb"
|
||||
ctyunelb "github.com/usual2970/certimate/internal/pkg/sdk3rd/ctyun/elb"
|
||||
typeutil "github.com/usual2970/certimate/internal/pkg/utils/type"
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// 天翼云 AccessKeyId。
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 天翼云 SecretAccessKey。
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
// 天翼云资源池 ID。
|
||||
RegionId string `json:"regionId"`
|
||||
// 部署资源类型。
|
||||
ResourceType ResourceType `json:"resourceType"`
|
||||
// 负载均衡实例 ID。
|
||||
// 部署资源类型为 [RESOURCE_TYPE_LOADBALANCER] 时必填。
|
||||
LoadbalancerId string `json:"loadbalancerId,omitempty"`
|
||||
// 负载均衡监听器 ID。
|
||||
// 部署资源类型为 [RESOURCE_TYPE_LISTENER] 时必填。
|
||||
ListenerId string `json:"listenerId,omitempty"`
|
||||
}
|
||||
|
||||
type DeployerProvider struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *ctyunelb.Client
|
||||
sslUploader uploader.Uploader
|
||||
}
|
||||
|
||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
||||
|
||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
if config == nil {
|
||||
panic("config is nil")
|
||||
}
|
||||
|
||||
client, err := createSdkClient(config.AccessKeyId, config.SecretAccessKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
SecretAccessKey: config.SecretAccessKey,
|
||||
RegionId: config.RegionId,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
}
|
||||
|
||||
return &DeployerProvider{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkClient: client,
|
||||
sslUploader: uploader,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||
// 上传证书到 ELB
|
||||
upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
|
||||
} else {
|
||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
||||
}
|
||||
|
||||
// 根据部署资源类型决定部署方式
|
||||
switch d.config.ResourceType {
|
||||
case RESOURCE_TYPE_LOADBALANCER:
|
||||
if err := d.deployToLoadbalancer(ctx, upres.CertId); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
case RESOURCE_TYPE_LISTENER:
|
||||
if err := d.deployToListener(ctx, upres.CertId); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported resource type '%s'", d.config.ResourceType)
|
||||
}
|
||||
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId string) error {
|
||||
if d.config.LoadbalancerId == "" {
|
||||
return errors.New("config `loadbalancerId` is required")
|
||||
}
|
||||
|
||||
// 查询监听列表
|
||||
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=24&api=5654&data=88&isNormal=1&vid=82
|
||||
listenerIds := make([]string, 0)
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
listListenersReq := &ctyunelb.ListListenersRequest{
|
||||
RegionID: typeutil.ToPtr(d.config.RegionId),
|
||||
LoadBalancerID: typeutil.ToPtr(d.config.LoadbalancerId),
|
||||
}
|
||||
listListenersResp, err := d.sdkClient.ListListeners(listListenersReq)
|
||||
d.logger.Debug("sdk request 'elb.ListListeners'", slog.Any("request", listListenersReq), slog.Any("response", listListenersResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'elb.ListListeners': %w", err)
|
||||
}
|
||||
|
||||
for _, listener := range listListenersResp.ReturnObj {
|
||||
if strings.EqualFold(listener.Protocol, "HTTPS") {
|
||||
listenerIds = append(listenerIds, listener.ID)
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
// 遍历更新监听证书
|
||||
if len(listenerIds) == 0 {
|
||||
d.logger.Info("no elb listeners to deploy")
|
||||
} else {
|
||||
d.logger.Info("found https listeners to deploy", slog.Any("listenerIds", listenerIds))
|
||||
var errs []error
|
||||
|
||||
for _, listenerId := range listenerIds {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
if err := d.updateListenerCertificate(ctx, listenerId, cloudCertId); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) deployToListener(ctx context.Context, cloudCertId string) error {
|
||||
if d.config.ListenerId == "" {
|
||||
return errors.New("config `listenerId` is required")
|
||||
}
|
||||
|
||||
// 更新监听
|
||||
if err := d.updateListenerCertificate(ctx, d.config.ListenerId, cloudCertId); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudListenerId string, cloudCertId string) error {
|
||||
// 更新监听器
|
||||
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=24&api=5652&data=88&isNormal=1&vid=82
|
||||
setLoadBalancerHTTPSListenerAttributeReq := &ctyunelb.UpdateListenerRequest{
|
||||
RegionID: typeutil.ToPtr(d.config.RegionId),
|
||||
ListenerID: typeutil.ToPtr(cloudListenerId),
|
||||
CertificateID: typeutil.ToPtr(cloudCertId),
|
||||
}
|
||||
setLoadBalancerHTTPSListenerAttributeResp, err := d.sdkClient.UpdateListener(setLoadBalancerHTTPSListenerAttributeReq)
|
||||
d.logger.Debug("sdk request 'elb.UpdateListener'", slog.Any("request", setLoadBalancerHTTPSListenerAttributeReq), slog.Any("response", setLoadBalancerHTTPSListenerAttributeResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'elb.UpdateListener': %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createSdkClient(accessKeyId, secretAccessKey string) (*ctyunelb.Client, error) {
|
||||
return ctyunelb.NewClient(accessKeyId, secretAccessKey)
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package ctcccloudelb_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-elb"
|
||||
)
|
||||
|
||||
var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fAccessKeyId string
|
||||
fSecretAccessKey string
|
||||
fRegionId string
|
||||
fLoadbalancerId string
|
||||
fListenerId string
|
||||
)
|
||||
|
||||
func init() {
|
||||
argsPrefix := "CERTIMATE_DEPLOYER_CTCCCLOUDELB_"
|
||||
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
|
||||
flag.StringVar(&fSecretAccessKey, argsPrefix+"SECRETACCESSKEY", "", "")
|
||||
flag.StringVar(&fRegionId, argsPrefix+"REGIONID", "", "")
|
||||
flag.StringVar(&fLoadbalancerId, argsPrefix+"LOADBALANCERID", "", "")
|
||||
flag.StringVar(&fListenerId, argsPrefix+"LISTENERID", "", "")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./ctcccloud_elb_test.go -args \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDELB_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDELB_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDELB_ACCESSKEYID="your-access-key-id" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDELB_SECRETACCESSKEY="your-secret-access-key" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDELB_REGIONID="your-region-id" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDELB_LOADBALANCERID="your-elb-instance-id" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDELB_LISTENERID="your-elb-listener-id"
|
||||
*/
|
||||
func TestDeploy(t *testing.T) {
|
||||
flag.Parse()
|
||||
|
||||
t.Run("Deploy_ToLoadbalancer", func(t *testing.T) {
|
||||
t.Log(strings.Join([]string{
|
||||
"args:",
|
||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||
fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId),
|
||||
fmt.Sprintf("SECRETACCESSKEY: %v", fSecretAccessKey),
|
||||
fmt.Sprintf("REGIONID: %v", fRegionId),
|
||||
fmt.Sprintf("LOADBALANCERID: %v", fLoadbalancerId),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||
AccessKeyId: fAccessKeyId,
|
||||
SecretAccessKey: fSecretAccessKey,
|
||||
RegionId: fRegionId,
|
||||
ResourceType: provider.RESOURCE_TYPE_LOADBALANCER,
|
||||
LoadbalancerId: fLoadbalancerId,
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fInputCertData, _ := os.ReadFile(fInputCertPath)
|
||||
fInputKeyData, _ := os.ReadFile(fInputKeyPath)
|
||||
res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
t.Logf("ok: %v", res)
|
||||
})
|
||||
|
||||
t.Run("Deploy_ToListener", func(t *testing.T) {
|
||||
t.Log(strings.Join([]string{
|
||||
"args:",
|
||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||
fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId),
|
||||
fmt.Sprintf("SECRETACCESSKEY: %v", fSecretAccessKey),
|
||||
fmt.Sprintf("REGIONID: %v", fRegionId),
|
||||
fmt.Sprintf("LISTENERID: %v", fListenerId),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||
AccessKeyId: fAccessKeyId,
|
||||
SecretAccessKey: fSecretAccessKey,
|
||||
RegionId: fRegionId,
|
||||
ResourceType: provider.RESOURCE_TYPE_LISTENER,
|
||||
ListenerId: fListenerId,
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fInputCertData, _ := os.ReadFile(fInputCertPath)
|
||||
fInputKeyData, _ := os.ReadFile(fInputKeyPath)
|
||||
res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
t.Logf("ok: %v", res)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package ctcccloudicdn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/ctcccloud-icdn"
|
||||
ctyunicdn "github.com/usual2970/certimate/internal/pkg/sdk3rd/ctyun/icdn"
|
||||
typeutil "github.com/usual2970/certimate/internal/pkg/utils/type"
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// 天翼云 AccessKeyId。
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 天翼云 SecretAccessKey。
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
// 加速域名(支持泛域名)。
|
||||
Domain string `json:"domain"`
|
||||
}
|
||||
|
||||
type DeployerProvider struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *ctyunicdn.Client
|
||||
sslUploader uploader.Uploader
|
||||
}
|
||||
|
||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
||||
|
||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
if config == nil {
|
||||
panic("config is nil")
|
||||
}
|
||||
|
||||
client, err := createSdkClient(config.AccessKeyId, config.SecretAccessKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
SecretAccessKey: config.SecretAccessKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
}
|
||||
|
||||
return &DeployerProvider{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkClient: client,
|
||||
sslUploader: uploader,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||
if d.config.Domain == "" {
|
||||
return nil, errors.New("config `domain` is required")
|
||||
}
|
||||
|
||||
// 上传证书到 ICDN
|
||||
upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
|
||||
} else {
|
||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
||||
}
|
||||
|
||||
// 查询域名配置信息
|
||||
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=112&api=10849&data=173&isNormal=1&vid=166
|
||||
queryDomainDetailReq := &ctyunicdn.QueryDomainDetailRequest{
|
||||
Domain: typeutil.ToPtr(d.config.Domain),
|
||||
}
|
||||
queryDomainDetailResp, err := d.sdkClient.QueryDomainDetail(queryDomainDetailReq)
|
||||
d.logger.Debug("sdk request 'icdn.QueryDomainDetail'", slog.Any("request", queryDomainDetailReq), slog.Any("response", queryDomainDetailResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'icdn.QueryDomainDetail': %w", err)
|
||||
}
|
||||
|
||||
// 修改域名配置
|
||||
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=112&api=10853&data=173&isNormal=1&vid=166
|
||||
updateDomainReq := &ctyunicdn.UpdateDomainRequest{
|
||||
Domain: typeutil.ToPtr(d.config.Domain),
|
||||
HttpsStatus: typeutil.ToPtr("on"),
|
||||
CertName: typeutil.ToPtr(upres.CertName),
|
||||
}
|
||||
updateDomainResp, err := d.sdkClient.UpdateDomain(updateDomainReq)
|
||||
d.logger.Debug("sdk request 'icdn.UpdateDomain'", slog.Any("request", updateDomainReq), slog.Any("response", updateDomainResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'icdn.UpdateDomain': %w", err)
|
||||
}
|
||||
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
|
||||
func createSdkClient(accessKeyId, secretAccessKey string) (*ctyunicdn.Client, error) {
|
||||
return ctyunicdn.NewClient(accessKeyId, secretAccessKey)
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package ctcccloudicdn_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-icdn"
|
||||
)
|
||||
|
||||
var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fAccessKeyId string
|
||||
fSecretAccessKey string
|
||||
fDomain string
|
||||
)
|
||||
|
||||
func init() {
|
||||
argsPrefix := "CERTIMATE_DEPLOYER_CTCCCLOUDCDN_"
|
||||
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
|
||||
flag.StringVar(&fSecretAccessKey, argsPrefix+"SECRETACCESSKEY", "", "")
|
||||
flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./ctcccloud_cdn_test.go -args \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDCDN_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDCDN_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDCDN_ACCESSKEYID="your-access-key-id" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDCDN_SECRETACCESSKEY="your-secret-access-key" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDCDN_DOMAIN="example.com"
|
||||
*/
|
||||
func TestDeploy(t *testing.T) {
|
||||
flag.Parse()
|
||||
|
||||
t.Run("Deploy", func(t *testing.T) {
|
||||
t.Log(strings.Join([]string{
|
||||
"args:",
|
||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||
fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId),
|
||||
fmt.Sprintf("SECRETACCESSKEY: %v", fSecretAccessKey),
|
||||
fmt.Sprintf("DOMAIN: %v", fDomain),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||
AccessKeyId: fAccessKeyId,
|
||||
SecretAccessKey: fSecretAccessKey,
|
||||
Domain: fDomain,
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fInputCertData, _ := os.ReadFile(fInputCertPath)
|
||||
fInputKeyData, _ := os.ReadFile(fInputKeyPath)
|
||||
res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
t.Logf("ok: %v", res)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package ctcccloudlvdn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/usual2970/certimate/internal/pkg/core/deployer"
|
||||
"github.com/usual2970/certimate/internal/pkg/core/uploader"
|
||||
uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/ctcccloud-lvdn"
|
||||
ctyunlvdn "github.com/usual2970/certimate/internal/pkg/sdk3rd/ctyun/lvdn"
|
||||
typeutil "github.com/usual2970/certimate/internal/pkg/utils/type"
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// 天翼云 AccessKeyId。
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 天翼云 SecretAccessKey。
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
// 加速域名(不支持泛域名)。
|
||||
Domain string `json:"domain"`
|
||||
}
|
||||
|
||||
type DeployerProvider struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *ctyunlvdn.Client
|
||||
sslUploader uploader.Uploader
|
||||
}
|
||||
|
||||
var _ deployer.Deployer = (*DeployerProvider)(nil)
|
||||
|
||||
func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
if config == nil {
|
||||
panic("config is nil")
|
||||
}
|
||||
|
||||
client, err := createSdkClient(config.AccessKeyId, config.SecretAccessKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create sdk client: %w", err)
|
||||
}
|
||||
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
SecretAccessKey: config.SecretAccessKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
}
|
||||
|
||||
return &DeployerProvider{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkClient: client,
|
||||
sslUploader: uploader,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||
if d.config.Domain == "" {
|
||||
return nil, errors.New("config `domain` is required")
|
||||
}
|
||||
|
||||
// 上传证书到 CDN
|
||||
upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
|
||||
} else {
|
||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
||||
}
|
||||
|
||||
// 查询域名配置信息
|
||||
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=125&api=11473&data=183&isNormal=1&vid=261
|
||||
queryDomainDetailReq := &ctyunlvdn.QueryDomainDetailRequest{
|
||||
Domain: typeutil.ToPtr(d.config.Domain),
|
||||
ProductCode: typeutil.ToPtr("005"),
|
||||
}
|
||||
queryDomainDetailResp, err := d.sdkClient.QueryDomainDetail(queryDomainDetailReq)
|
||||
d.logger.Debug("sdk request 'lvdn.QueryDomainDetail'", slog.Any("request", queryDomainDetailReq), slog.Any("response", queryDomainDetailResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'lvdn.QueryDomainDetail': %w", err)
|
||||
}
|
||||
|
||||
// 修改域名配置
|
||||
// REF: https://eop.ctyun.cn/ebp/ctapiDocument/search?sid=108&api=11308&data=161&isNormal=1&vid=154
|
||||
updateDomainReq := &ctyunlvdn.UpdateDomainRequest{
|
||||
Domain: typeutil.ToPtr(d.config.Domain),
|
||||
ProductCode: typeutil.ToPtr("005"),
|
||||
HttpsSwitch: typeutil.ToPtr(int32(1)),
|
||||
CertName: typeutil.ToPtr(upres.CertName),
|
||||
}
|
||||
updateDomainResp, err := d.sdkClient.UpdateDomain(updateDomainReq)
|
||||
d.logger.Debug("sdk request 'lvdn.UpdateDomain'", slog.Any("request", updateDomainReq), slog.Any("response", updateDomainResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'lvdn.UpdateDomain': %w", err)
|
||||
}
|
||||
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
|
||||
func createSdkClient(accessKeyId, secretAccessKey string) (*ctyunlvdn.Client, error) {
|
||||
return ctyunlvdn.NewClient(accessKeyId, secretAccessKey)
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package ctcccloudlvdn_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ctcccloud-lvdn"
|
||||
)
|
||||
|
||||
var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fAccessKeyId string
|
||||
fSecretAccessKey string
|
||||
fDomain string
|
||||
)
|
||||
|
||||
func init() {
|
||||
argsPrefix := "CERTIMATE_DEPLOYER_CTCCCLOUDLVDN_"
|
||||
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "")
|
||||
flag.StringVar(&fSecretAccessKey, argsPrefix+"SECRETACCESSKEY", "", "")
|
||||
flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./ctcccloud_lvdn_test.go -args \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDLVDN_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDLVDN_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDLVDN_ACCESSKEYID="your-access-key-id" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDLVDN_SECRETACCESSKEY="your-secret-access-key" \
|
||||
--CERTIMATE_DEPLOYER_CTCCCLOUDLVDN_DOMAIN="example.com"
|
||||
*/
|
||||
func TestDeploy(t *testing.T) {
|
||||
flag.Parse()
|
||||
|
||||
t.Run("Deploy", func(t *testing.T) {
|
||||
t.Log(strings.Join([]string{
|
||||
"args:",
|
||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||
fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId),
|
||||
fmt.Sprintf("SECRETACCESSKEY: %v", fSecretAccessKey),
|
||||
fmt.Sprintf("DOMAIN: %v", fDomain),
|
||||
}, "\n"))
|
||||
|
||||
deployer, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||
AccessKeyId: fAccessKeyId,
|
||||
SecretAccessKey: fSecretAccessKey,
|
||||
Domain: fDomain,
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fInputCertData, _ := os.ReadFile(fInputCertPath)
|
||||
fInputKeyData, _ := os.ReadFile(fInputKeyPath)
|
||||
res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
t.Logf("ok: %v", res)
|
||||
})
|
||||
}
|
||||
@@ -55,7 +55,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ type DeployerConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 华为云 SecretAccessKey。
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
// 华为云企业项目 ID。
|
||||
EnterpriseProjectId string `json:"enterpriseProjectId,omitempty"`
|
||||
// 华为云区域。
|
||||
Region string `json:"region"`
|
||||
// 加速域名(不支持泛域名)。
|
||||
@@ -51,8 +53,9 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
}
|
||||
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
SecretAccessKey: config.SecretAccessKey,
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
SecretAccessKey: config.SecretAccessKey,
|
||||
EnterpriseProjectId: config.EnterpriseProjectId,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
@@ -68,7 +71,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
@@ -88,7 +91,8 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
||||
// 查询加速域名配置
|
||||
// REF: https://support.huaweicloud.com/api-cdn/ShowDomainFullConfig.html
|
||||
showDomainFullConfigReq := &hccdnmodel.ShowDomainFullConfigRequest{
|
||||
DomainName: d.config.Domain,
|
||||
EnterpriseProjectId: typeutil.ToPtrOrZeroNil(d.config.EnterpriseProjectId),
|
||||
DomainName: d.config.Domain,
|
||||
}
|
||||
showDomainFullConfigResp, err := d.sdkClient.ShowDomainFullConfig(showDomainFullConfigReq)
|
||||
d.logger.Debug("sdk request 'cdn.ShowDomainFullConfig'", slog.Any("request", showDomainFullConfigReq), slog.Any("response", showDomainFullConfigResp))
|
||||
@@ -107,6 +111,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPE
|
||||
updateDomainMultiCertificatesReqBodyContent.CertName = typeutil.ToPtr(upres.CertName)
|
||||
updateDomainMultiCertificatesReqBodyContent = assign(updateDomainMultiCertificatesReqBodyContent, showDomainFullConfigResp.Configs)
|
||||
updateDomainMultiCertificatesReq := &hccdnmodel.UpdateDomainMultiCertificatesRequest{
|
||||
EnterpriseProjectId: typeutil.ToPtrOrZeroNil(d.config.EnterpriseProjectId),
|
||||
Body: &hccdnmodel.UpdateDomainMultiCertificatesRequestBody{
|
||||
Https: updateDomainMultiCertificatesReqBodyContent,
|
||||
},
|
||||
|
||||
@@ -27,6 +27,8 @@ type DeployerConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 华为云 SecretAccessKey。
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
// 华为云企业项目 ID。
|
||||
EnterpriseProjectId string `json:"enterpriseProjectId,omitempty"`
|
||||
// 华为云区域。
|
||||
Region string `json:"region"`
|
||||
// 部署资源类型。
|
||||
@@ -62,9 +64,10 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
}
|
||||
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
SecretAccessKey: config.SecretAccessKey,
|
||||
Region: config.Region,
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
SecretAccessKey: config.SecretAccessKey,
|
||||
EnterpriseProjectId: config.EnterpriseProjectId,
|
||||
Region: config.Region,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
@@ -80,7 +83,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
@@ -172,6 +175,9 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, certPEM str
|
||||
Protocol: &[]string{"HTTPS", "TERMINATED_HTTPS"},
|
||||
LoadbalancerId: &[]string{showLoadBalancerResp.Loadbalancer.Id},
|
||||
}
|
||||
if d.config.EnterpriseProjectId != "" {
|
||||
listListenersReq.EnterpriseProjectId = typeutil.ToPtr([]string{d.config.EnterpriseProjectId})
|
||||
}
|
||||
listListenersResp, err := d.sdkClient.ListListeners(listListenersReq)
|
||||
d.logger.Debug("sdk request 'elb.ListListeners'", slog.Any("request", listListenersReq), slog.Any("response", listListenersResp))
|
||||
if err != nil {
|
||||
|
||||
@@ -15,6 +15,8 @@ type DeployerConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 华为云 SecretAccessKey。
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
// 华为云企业项目 ID。
|
||||
EnterpriseProjectId string `json:"enterpriseProjectId,omitempty"`
|
||||
}
|
||||
|
||||
type DeployerProvider struct {
|
||||
@@ -31,8 +33,9 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
}
|
||||
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
SecretAccessKey: config.SecretAccessKey,
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
SecretAccessKey: config.SecretAccessKey,
|
||||
EnterpriseProjectId: config.EnterpriseProjectId,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
@@ -47,7 +50,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ type DeployerConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 华为云 SecretAccessKey。
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
// 华为云企业项目 ID。
|
||||
EnterpriseProjectId string `json:"enterpriseProjectId,omitempty"`
|
||||
// 华为云区域。
|
||||
Region string `json:"region"`
|
||||
// 部署资源类型。
|
||||
@@ -59,9 +61,10 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
}
|
||||
|
||||
uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
SecretAccessKey: config.SecretAccessKey,
|
||||
Region: config.Region,
|
||||
AccessKeyId: config.AccessKeyId,
|
||||
SecretAccessKey: config.SecretAccessKey,
|
||||
EnterpriseProjectId: config.EnterpriseProjectId,
|
||||
Region: config.Region,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create ssl uploader: %w", err)
|
||||
@@ -77,7 +80,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
@@ -126,7 +129,8 @@ func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPEM stri
|
||||
// 查询证书
|
||||
// REF: https://support.huaweicloud.com/api-waf/ShowCertificate.html
|
||||
showCertificateReq := &hcwafmodel.ShowCertificateRequest{
|
||||
CertificateId: d.config.CertificateId,
|
||||
EnterpriseProjectId: typeutil.ToPtrOrZeroNil(d.config.EnterpriseProjectId),
|
||||
CertificateId: d.config.CertificateId,
|
||||
}
|
||||
showCertificateResp, err := d.sdkClient.ShowCertificate(showCertificateReq)
|
||||
d.logger.Debug("sdk request 'waf.ShowCertificate'", slog.Any("request", showCertificateReq), slog.Any("response", showCertificateResp))
|
||||
@@ -137,7 +141,8 @@ func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPEM stri
|
||||
// 更新证书
|
||||
// REF: https://support.huaweicloud.com/api-waf/UpdateCertificate.html
|
||||
updateCertificateReq := &hcwafmodel.UpdateCertificateRequest{
|
||||
CertificateId: d.config.CertificateId,
|
||||
EnterpriseProjectId: typeutil.ToPtrOrZeroNil(d.config.EnterpriseProjectId),
|
||||
CertificateId: d.config.CertificateId,
|
||||
Body: &hcwafmodel.UpdateCertificateRequestBody{
|
||||
Name: *showCertificateResp.Name,
|
||||
Content: typeutil.ToPtr(certPEM),
|
||||
@@ -179,9 +184,10 @@ func (d *DeployerProvider) deployToCloudServer(ctx context.Context, certPEM stri
|
||||
}
|
||||
|
||||
listHostReq := &hcwafmodel.ListHostRequest{
|
||||
Hostname: typeutil.ToPtr(strings.TrimPrefix(d.config.Domain, "*")),
|
||||
Page: typeutil.ToPtr(listHostPage),
|
||||
Pagesize: typeutil.ToPtr(listHostPageSize),
|
||||
EnterpriseProjectId: typeutil.ToPtrOrZeroNil(d.config.EnterpriseProjectId),
|
||||
Hostname: typeutil.ToPtr(strings.TrimPrefix(d.config.Domain, "*")),
|
||||
Page: typeutil.ToPtr(listHostPage),
|
||||
Pagesize: typeutil.ToPtr(listHostPageSize),
|
||||
}
|
||||
listHostResp, err := d.sdkClient.ListHost(listHostReq)
|
||||
d.logger.Debug("sdk request 'waf.ListHost'", slog.Any("request", listHostReq), slog.Any("response", listHostResp))
|
||||
@@ -211,7 +217,8 @@ func (d *DeployerProvider) deployToCloudServer(ctx context.Context, certPEM stri
|
||||
// 更新云模式防护域名的配置
|
||||
// REF: https://support.huaweicloud.com/api-waf/UpdateHost.html
|
||||
updateHostReq := &hcwafmodel.UpdateHostRequest{
|
||||
InstanceId: hostId,
|
||||
EnterpriseProjectId: typeutil.ToPtrOrZeroNil(d.config.EnterpriseProjectId),
|
||||
InstanceId: hostId,
|
||||
Body: &hcwafmodel.UpdateHostRequestBody{
|
||||
Certificateid: typeutil.ToPtr(upres.CertId),
|
||||
Certificatename: typeutil.ToPtr(upres.CertName),
|
||||
@@ -252,9 +259,10 @@ func (d *DeployerProvider) deployToPremiumHost(ctx context.Context, certPEM stri
|
||||
}
|
||||
|
||||
listPremiumHostReq := &hcwafmodel.ListPremiumHostRequest{
|
||||
Hostname: typeutil.ToPtr(strings.TrimPrefix(d.config.Domain, "*")),
|
||||
Page: typeutil.ToPtr(fmt.Sprintf("%d", listPremiumHostPage)),
|
||||
Pagesize: typeutil.ToPtr(fmt.Sprintf("%d", listPremiumHostPageSize)),
|
||||
EnterpriseProjectId: typeutil.ToPtrOrZeroNil(d.config.EnterpriseProjectId),
|
||||
Hostname: typeutil.ToPtr(strings.TrimPrefix(d.config.Domain, "*")),
|
||||
Page: typeutil.ToPtr(fmt.Sprintf("%d", listPremiumHostPage)),
|
||||
Pagesize: typeutil.ToPtr(fmt.Sprintf("%d", listPremiumHostPageSize)),
|
||||
}
|
||||
listPremiumHostResp, err := d.sdkClient.ListPremiumHost(listPremiumHostReq)
|
||||
d.logger.Debug("sdk request 'waf.ListPremiumHost'", slog.Any("request", listPremiumHostReq), slog.Any("response", listPremiumHostResp))
|
||||
@@ -284,7 +292,8 @@ func (d *DeployerProvider) deployToPremiumHost(ctx context.Context, certPEM stri
|
||||
// 修改独享模式域名配置
|
||||
// REF: https://support.huaweicloud.com/api-waf/UpdatePremiumHost.html
|
||||
updatePremiumHostReq := &hcwafmodel.UpdatePremiumHostRequest{
|
||||
HostId: hostId,
|
||||
EnterpriseProjectId: typeutil.ToPtrOrZeroNil(d.config.EnterpriseProjectId),
|
||||
HostId: hostId,
|
||||
Body: &hcwafmodel.UpdatePremiumHostRequestBody{
|
||||
Certificateid: typeutil.ToPtr(upres.CertId),
|
||||
Certificatename: typeutil.ToPtr(upres.CertName),
|
||||
|
||||
@@ -76,7 +76,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) {
|
||||
|
||||
func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
|
||||
if logger == nil {
|
||||
d.logger = slog.Default()
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user