diff --git a/README.md b/README.md index 6f90fb32..0899200e 100644 --- a/README.md +++ b/README.md @@ -90,17 +90,23 @@ make local.run | :----------------------------------------------------------------- | :-------------------------------------- | | [阿里云](https://www.aliyun.com/) | | | [腾讯云](https://cloud.tencent.com/) | | +| [百度智能云](https://cloud.baidu.com/) | | | [华为云](https://www.huaweicloud.com/) | | | [火山引擎](https://www.volcengine.com/) | | +| [京东云](https://www.jdcloud.com/) | | | [AWS Route53](https://aws.amazon.com/route53/) | | | [Azure](https://azure.microsoft.com/) | | | [CloudFlare](https://www.cloudflare.com/) | | -| [ClouDNS](https://www.cloudns.net//) | | +| [ClouDNS](https://www.cloudns.net/) | | +| [DNS.LA](https://www.dns.la/) | | +| [Gcore](https://gcore.com/) | | | [GNAME](https://www.gname.com/) | | | [GoDaddy](https://www.godaddy.com/) | | | [Name.com](https://www.name.com/) | | +| [Namecheap](https://www.namecheap.com/) | | | [NameSilo](https://www.namesilo.com/) | | | [IBM NS1 Connect](https://www.ibm.com/cn-zh/products/ns1-connect/) | | +| [移动云](https://ecloud.10086.cn/) | | | [雨云](https://www.rainyun.com/) | | | [西部数码](https://www.west.cn/) | | | [PowerDNS](https://www.powerdns.com/) | | @@ -116,24 +122,30 @@ make local.run [展开查看] -| 提供商 | 备注 | -| :-------------------------------------- | :----------------------------------------------------------------------- | -| 本地部署 | 可部署到本地服务器 | -| SSH 部署 | 可部署到远程服务器(通过 SSH+SFTP/SCP) | -| Webhook 回调 | 可部署到 Webhook | -| [Kubernetes](https://kubernetes.io/) | 可部署到 Kubernetes Secret | -| [阿里云](https://www.aliyun.com/) | 可部署到阿里云 OSS、CDN、DCDN、ESA、SLB(CLB/ALB/NLB)、WAF、Live 等服务 | -| [腾讯云](https://cloud.tencent.com/) | 可部署到腾讯云 COS、CDN、ECDN、EdgeOne、CLB、CSS 等服务 | -| [百度智能云](https://cloud.baidu.com/) | 可部署到百度智能云 CDN 等服务 | -| [华为云](https://www.huaweicloud.com/) | 可部署到华为云 CDN、ELB 等服务 | -| [火山引擎](https://www.volcengine.com/) | 可部署到火山引擎 TOS、CDN、DCDN、CLB、Live 等服务 | -| [七牛云](https://www.qiniu.com/) | 可部署到七牛云 CDN、直播云等服务 | -| [多吉云](https://www.dogecloud.com/) | 可部署到多吉云 CDN | -| [优刻得](https://www.ucloud.cn/) | 可部署到优刻得 US3、UCDN 等服务 | -| [宝塔面板](https://www.bt.cn/) | 可部署到宝塔面板 | -| [AWS](https://aws.amazon.com/) | 可部署到 AWS CloudFront 等服务 | -| [BytePlus](https://www.byteplus.com/) | 可部署到 BytePlus CDN 等服务 | -| [Edgio](https://edg.io/) | 可部署到 Edgio Applications 等服务 | +| 提供商 | 备注 | +| :-------------------------------------- | :---------------------------------------------------------------------------- | +| 本地部署 | 可部署到本地服务器 | +| SSH 部署 | 可部署到远程服务器(通过 SSH+SFTP/SCP) | +| Webhook 回调 | 可部署到 Webhook | +| [Kubernetes](https://kubernetes.io/) | 可部署到 Kubernetes Secret | +| [阿里云](https://www.aliyun.com/) | 可部署到阿里云 OSS、CDN、DCDN、ESA、SLB(CLB/ALB/NLB)、WAF、Live、VOD 等服务 | +| [腾讯云](https://cloud.tencent.com/) | 可部署到腾讯云 COS、CDN、ECDN、EdgeOne、CLB、WAF、CSS、VOD 等服务 | +| [百度智能云](https://cloud.baidu.com/) | 可部署到百度智能云 CDN 等服务 | +| [华为云](https://www.huaweicloud.com/) | 可部署到华为云 CDN、ELB、WAF 等服务 | +| [火山引擎](https://www.volcengine.com/) | 可部署到火山引擎 TOS、CDN、DCDN、CLB、ImageX、Live 等服务 | +| [京东云](https://www.jdcloud.com/) | 可部署到京东云 CDN、ALB、视频直播、视频点播等服务 | +| [七牛云](https://www.qiniu.com/) | 可部署到七牛云 CDN、直播云等服务 | +| [白山云](https://www.baishan.com/) | 可部署到白山云 CDN | +| [多吉云](https://www.dogecloud.com/) | 可部署到多吉云 CDN | +| [优刻得](https://www.ucloud.cn/) | 可部署到优刻得 US3、UCDN 等服务 | +| [雷池](https://waf-ce.chaitin.cn/) | 可部署到雷池 WAF | +| [宝塔面板](https://www.bt.cn/) | 可部署到宝塔面板 | +| [AWS](https://aws.amazon.com/) | 可部署到 AWS CloudFront | +| [BytePlus](https://www.byteplus.com/) | 可部署到 BytePlus CDN | +| [CacheFly](https://www.cachefly.com/) | 可部署到 CacheFly CDN | +| [Cdnfly](https://www.cdnfly.cn/) | 可部署到 Cdnfly CDN | +| [Edgio](https://edg.io/) | 可部署到 Edgio Applications | +| [Gcore](https://gcore.com/) | 可部署到 Gcore CDN | diff --git a/README_EN.md b/README_EN.md index d5300b07..b92fc82a 100644 --- a/README_EN.md +++ b/README_EN.md @@ -89,17 +89,23 @@ The following DNS providers are supported: | :----------------------------------------------------------- | :------------------------------------ | | [Alibaba Cloud](https://www.alibabacloud.com/) | | | [Tencent Cloud](https://www.tencentcloud.com/) | | +| [Baidu AI Cloud](https://intl.cloud.baidu.com/) | | | [Huawei Cloud](https://www.huaweicloud.com/) | | | [Volcengine](https://www.volcengine.com/) | | +| [JD Cloud](https://www.jdcloud.com/) | | | [AWS Route53](https://aws.amazon.com/route53/) | | | [Azure DNS](https://azure.microsoft.com/) | | | [CloudFlare](https://www.cloudflare.com/) | | -| [ClouDNS](https://www.cloudns.net//) | | +| [ClouDNS](https://www.cloudns.net/) | | +| [DNS.LA](https://www.dns.la/) | | +| [Gcore](https://gcore.com/) | | | [GNAME](https://www.gname.com/) | | | [GoDaddy](https://www.godaddy.com/) | | | [Name.com](https://www.name.com/) | | +| [Namecheap](https://www.namecheap.com/) | | | [NameSilo](https://www.namesilo.com/) | | | [IBM NS1 Connect](https://www.ibm.com/products/ns1-connect/) | | +| [CMCC Cloud](https://ecloud.10086.cn/) | | | [Rain Yun](https://www.rainyun.com/) | | | [West.cn](https://www.west.cn/) | | | [PowerDNS](https://www.powerdns.com/) | | @@ -115,24 +121,30 @@ The following hosting providers are supported: [Fold/Unfold to view ...] -| Provider | Remarks | -| :---------------------------------------------- | :------------------------------------------------------------------------------- | -| Local | Supports deployment to local servers | -| SSH | Supports deployment to remote servers (via SSH+SFTP/SCP) | -| Webhook | Supports deployment to Webhook | -| [Kubernetes](https://kubernetes.io/) | Supports deployment to Kubernetes Secret | -| [Alibaba Cloud](https://www.alibabacloud.com/) | Supports deployment to Alibaba Cloud OSS, CDN, DCDN, SLB(CLB/ALB/NLB), WAF, Live | -| [Tencent Cloud](https://www.tencentcloud.com/) | Supports deployment to Tencent Cloud COS, CDN, ECDN, EdgeOne, CLB, CSS | -| [Baidu AI Cloud](https://intl.cloud.baidu.com/) | Supports deployment to Baidu AI CLoud CDN | -| [Huawei Cloud](https://www.huaweicloud.com/) | Supports deployment to Huawei Cloud CDN, ELB | -| [Volcengine](https://www.volcengine.com/) | Supports deployment to Volcengine TOS, CDN, DCDN, CLB, Live | -| [Qiniu Cloud](https://www.qiniu.com/) | Supports deployment to Qiniu Cloud CDN, Pili | -| [Doge Cloud](https://www.dogecloud.com/) | Supports deployment to Doge Cloud CDN | -| [BaoTa Panel](https://www.bt.cn/) | Supports deployment to BaoTa Panel sites | -| [UCloud](https://www.ucloud-global.com/) | Supports deployment to UCloud US3, UCDN | -| [AWS](https://aws.amazon.com/) | Supports deployment to AWS CloudFront | -| [BytePlus](https://www.byteplus.com/) | Supports deployment to BytePlus CDN | -| [Edgio](https://edg.io/) | Supports deployment to Edgio Applications | +| Provider | Remarks | +| :---------------------------------------------- | :------------------------------------------------------------------------------------ | +| Local | Supports deployment to local servers | +| SSH | Supports deployment to remote servers (via SSH+SFTP/SCP) | +| Webhook | Supports deployment to Webhook | +| [Kubernetes](https://kubernetes.io/) | Supports deployment to Kubernetes Secret | +| [Alibaba Cloud](https://www.alibabacloud.com/) | Supports deployment to Alibaba Cloud OSS, CDN, DCDN, SLB(CLB/ALB/NLB), WAF, Live, VOD | +| [Tencent Cloud](https://www.tencentcloud.com/) | Supports deployment to Tencent Cloud COS, CDN, ECDN, EdgeOne, CLB, WAF, CSS, VOD | +| [Baidu AI Cloud](https://intl.cloud.baidu.com/) | Supports deployment to Baidu AI CLoud CDN | +| [Huawei Cloud](https://www.huaweicloud.com/) | Supports deployment to Huawei Cloud CDN, ELB, WAF | +| [Volcengine](https://www.volcengine.com/) | Supports deployment to Volcengine TOS, CDN, DCDN, CLB, ImageX, Live | +| [JD Cloud](https://www.jdcloud.com/) | Supports deployment to JD Cloud CDN, ALB, Live Video, VOD | +| [Qiniu Cloud](https://www.qiniu.com/) | Supports deployment to Qiniu Cloud CDN, Pili | +| [Baishan Cloud](https://intl.baishancloud.com/) | Supports deployment to Baishan Cloud CDN | +| [Doge Cloud](https://www.dogecloud.com/) | Supports deployment to Doge Cloud CDN | +| [UCloud](https://www.ucloud-global.com/) | Supports deployment to UCloud US3, UCDN | +| [SafeLine](https://waf.chaitin.com/) | Supports deployment to SafeLine WAF | +| [BaoTa Panel](https://www.bt.cn/) | Supports deployment to BaoTa Panel sites | +| [AWS](https://aws.amazon.com/) | Supports deployment to AWS CloudFront | +| [BytePlus](https://www.byteplus.com/) | Supports deployment to BytePlus CDN | +| [CacheFly](https://www.cachefly.com/) | Supports deployment to CacheFly CDN | +| [Cdnfly](https://www.cdnfly.cn/) | Supports deployment to Cdnfly CDN | +| [Edgio](https://edg.io/) | Supports deployment to Edgio Applications | +| [Gcore](https://gcore.com/) | Supports deployment to Gcore CDN | diff --git a/go.mod b/go.mod index d3280f69..40efa5a4 100644 --- a/go.mod +++ b/go.mod @@ -19,12 +19,12 @@ require ( github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible github.com/aws/aws-sdk-go-v2/service/acm v1.30.18 github.com/aws/aws-sdk-go-v2/service/cloudfront v1.44.10 - github.com/baidubce/bce-sdk-go v0.9.216 + github.com/baidubce/bce-sdk-go v0.9.217 github.com/byteplus-sdk/byteplus-sdk-golang v1.0.41 - github.com/go-acme/lego/v4 v4.21.0 + github.com/go-acme/lego/v4 v4.22.2 github.com/go-resty/resty/v2 v2.16.5 github.com/go-viper/mapstructure/v2 v2.2.1 - github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.135 + github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.136 github.com/nikoksr/notify v1.3.0 github.com/pavlo-v-chernykh/keystore-go/v4 v4.5.0 github.com/pkg/sftp v1.13.7 @@ -34,13 +34,13 @@ require ( github.com/qiniu/go-sdk/v7 v7.25.2 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1096 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1096 - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1096 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1102 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1096 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1096 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1096 github.com/ucloud/ucloud-sdk-go v0.22.31 github.com/volcengine/ve-tos-golang-sdk/v2 v2.7.9 - github.com/volcengine/volc-sdk-golang v1.0.194 + github.com/volcengine/volc-sdk-golang v1.0.195 github.com/volcengine/volcengine-go-sdk v1.0.180 golang.org/x/crypto v0.33.0 golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac @@ -57,11 +57,17 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.3.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2 // indirect + github.com/G-Core/gcorelabscdn-go v1.0.26 // indirect github.com/alibabacloud-go/openplatform-20191219/v2 v2.0.1 // indirect github.com/alibabacloud-go/tea-fileform v1.1.1 // indirect github.com/alibabacloud-go/tea-oss-sdk v1.1.3 // indirect github.com/alibabacloud-go/tea-oss-utils v1.1.0 // indirect + github.com/alibabacloud-go/tea-rpc v1.1.3 // indirect + github.com/alibabacloud-go/tea-rpc-utils v1.1.0 // indirect github.com/alibabacloud-go/tea-utils/v2 v2.0.7 // indirect + github.com/alibabacloud-go/vod-20170321 v1.0.1 // indirect + github.com/alibabacloud-go/vod-20170321/v4 v4.6.1 // indirect + github.com/avast/retry-go v3.0.0+incompatible // indirect github.com/aws/aws-sdk-go-v2/service/route53 v1.48.1 // indirect github.com/blinkbean/dingtalk v1.1.3 // indirect github.com/emicklei/go-restful/v3 v3.12.1 // indirect @@ -75,12 +81,14 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.16.0 // indirect github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible // indirect + github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v5 v5.2.1 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/gnostic-models v0.6.9 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect + github.com/jdcloud-api/jdcloud-sdk-go v1.62.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect @@ -94,7 +102,11 @@ require ( github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/technoweenie/multipartstreamer v1.0.1 // indirect + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1102 // indirect + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1099 // indirect github.com/x448/float16 v0.8.4 // indirect + gitlab.ecloud.com/ecloud/ecloudsdkclouddns v1.0.1 // indirect + gitlab.ecloud.com/ecloud/ecloudsdkcore v1.0.0 // indirect go.mongodb.org/mongo-driver v1.17.2 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect @@ -201,3 +213,7 @@ require ( modernc.org/memory v1.8.2 // indirect modernc.org/sqlite v1.34.5 // indirect ) + +replace gitlab.ecloud.com/ecloud/ecloudsdkcore v1.0.0 => ./internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0 + +replace gitlab.ecloud.com/ecloud/ecloudsdkclouddns v1.0.1 => ./internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1 diff --git a/go.sum b/go.sum index e9239294..d15c396f 100644 --- a/go.sum +++ b/go.sum @@ -79,6 +79,8 @@ github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0 github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/G-Core/gcorelabscdn-go v1.0.26 h1:22SqETUw64s+It/op1T7y3ukEOU62CJOsUcsfSkhvZs= +github.com/G-Core/gcorelabscdn-go v1.0.26/go.mod h1:iSGXaTvZBzDHQW+rKFS918BgFVpONcyLEijwh8WsXpE= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 h1:3c8yed4lgqTt+oTQ+JNMDo+F4xprBf+O/il4ZC0nRLw= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0/go.mod h1:obipzmGjfSjam60XLwGfqUkJsfiheAl+TUjG+4yzyPM= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0 h1:o90wcURuxekmXrtxmYWTyNla0+ZEHhud6DI1ZTxd1vI= @@ -169,6 +171,11 @@ github.com/alibabacloud-go/tea-oss-sdk v1.1.3 h1:EhAHI6edMeqgkZEqP7r4nc9iMWAUBKG github.com/alibabacloud-go/tea-oss-sdk v1.1.3/go.mod h1:yUnodpR3Bf2rudLE7V/Gft5txjJF30Pk+hH77K/Eab0= github.com/alibabacloud-go/tea-oss-utils v1.1.0 h1:y65crjjcZ2Pbb6UZtC2deuIZHDVTS3IaDWE7M9nVLRc= github.com/alibabacloud-go/tea-oss-utils v1.1.0/go.mod h1:PFCF12e9yEKyBUIn7X1IrF/pNjvxgkHy0CgxX4+xRuY= +github.com/alibabacloud-go/tea-rpc v1.1.3 h1:uuxAIT9PB6MMABQfV/EMSnREZjh629WXu+hmPNF1IAs= +github.com/alibabacloud-go/tea-rpc v1.1.3/go.mod h1:uwhvnxPK69jcAYkVyP1WCFhTh1oVLiibUseSUpC7L8g= +github.com/alibabacloud-go/tea-rpc-utils v1.1.0 h1:kIG7+9sMRaDzvCbXfowycEwFRdnLAglRFQ/dnc0/JNE= +github.com/alibabacloud-go/tea-rpc-utils v1.1.0/go.mod h1:rxGY+fLbm3Fj3oJpeU0hBTmz52Ux50nm7JL01tyPv9c= +github.com/alibabacloud-go/tea-utils v1.3.0/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= github.com/alibabacloud-go/tea-utils v1.3.6/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= github.com/alibabacloud-go/tea-utils v1.4.5 h1:h0/6Xd2f3bPE4XHTvkpjwxowIwRCJAJOqY6Eq8f3zfA= @@ -184,12 +191,17 @@ github.com/alibabacloud-go/tea-xml v1.1.1/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCE github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8= github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0= github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8= +github.com/alibabacloud-go/vod-20170321 v1.0.1 h1:ZiBggVoJegu0Q3iarHZyveTOJJE0kUym6RCSLM9epoc= +github.com/alibabacloud-go/vod-20170321 v1.0.1/go.mod h1:eKaYMCAd22pgBFMz0Ci/o2l+UJSrq24LLSF/XyaTiac= +github.com/alibabacloud-go/vod-20170321/v4 v4.6.1 h1:6JTNq23lMo3wOui5qjpUJu2VKBgSHR4ArMgbKDOej7Q= +github.com/alibabacloud-go/vod-20170321/v4 v4.6.1/go.mod h1:TkgLKMSLu0qZN8Qdcu8svfHREyI64kjFvrp/GhrD4VQ= github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.0.4 h1:Od0KgA73DyG9X2XFwuZZTkDv2pzA6B5mhYapyyca6QE= github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.0.4/go.mod h1:DohGoS8BnMxHXghHebtjPP7+GMdxPsRN19T3nn2HcCU= github.com/aliyun/alibaba-cloud-sdk-go v1.63.83 h1:YBkf7H5CSgrlb3C1aWcpDt7Vk8UEGFPeD2OOirtt6IM= github.com/aliyun/alibaba-cloud-sdk-go v1.63.83/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ= github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g= github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= +github.com/aliyun/credentials-go v1.1.0/go.mod h1:ZXrrxv386Mj6z8NpihLKpexQE550m7j3LlyCvYub9aE= github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw= github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0= github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM= @@ -205,6 +217,7 @@ github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgI github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= @@ -258,6 +271,8 @@ github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ= github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/baidubce/bce-sdk-go v0.9.216 h1:jRq4C1UGYcvHo6Gst2kuUzhWwJM6EqXCmhIsTKQvf4k= github.com/baidubce/bce-sdk-go v0.9.216/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg= +github.com/baidubce/bce-sdk-go v0.9.217 h1:dbMeVzpr9BGItTFHB1s2KSrpz0ayJC1y366VUMmaF0k= +github.com/baidubce/bce-sdk-go v0.9.217/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -361,6 +376,8 @@ github.com/ganigeorgiev/fexpr v0.4.1/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-acme/lego/v4 v4.21.0 h1:arEW+8o5p7VI8Bk1kr/PDlgD1DrxtTH1gJ4b7mehL8o= github.com/go-acme/lego/v4 v4.21.0/go.mod h1:HrSWzm3Ckj45Ie3i+p1zKVobbQoMOaGu9m4up0dUeDI= +github.com/go-acme/lego/v4 v4.22.2 h1:ck+HllWrV/rZGeYohsKQ5iKNnU/WAZxwOdiu6cxky+0= +github.com/go-acme/lego/v4 v4.22.2/go.mod h1:E2FndyI3Ekv0usNJt46mFb9LVpV/XBYT+4E3tz02Tzo= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -422,6 +439,8 @@ github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM= github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -557,6 +576,8 @@ github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKEN github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.135 h1:UbNMlPfh0GhRY3iVkvv4fXFJ+bLqXoVCwjqe6geFdPs= github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.135/go.mod h1:Y/+YLCFCJtS29i2MbYPTUlNNfwXvkzEsZKR0imY/2aY= +github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.136 h1:T785NUg5245nWpPVHLVR8lBd+zGQYR14Vi/TCX1iu3A= +github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.136/go.mod h1:Y/+YLCFCJtS29i2MbYPTUlNNfwXvkzEsZKR0imY/2aY= github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -569,6 +590,8 @@ github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/U github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jdcloud-api/jdcloud-sdk-go v1.62.0 h1:uPfyOSY16mBrhggriDNeySFB4ZkzMMXpNac2P0fbDRw= +github.com/jdcloud-api/jdcloud-sdk-go v1.62.0/go.mod h1:UrKjuULIWLjHFlG6aSPunArE5QX57LftMmStAZJBEX8= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= @@ -826,6 +849,10 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1096/go.mod h1 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1084/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1096 h1:DMokC7T0UF8wMfT1kD+mX3M+hc2C06gmFvQ9gsfRPmI= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1096/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1099 h1:4fQ53ORk6Eayw1H2kg43PoBnUuhGR6WRG6rtec/i3oI= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1099/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1102 h1:DxsNhw67OHyQME20IULmi8lgNY9MHuQ+qS1XH1/yTvM= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1102/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1084 h1:kwctN0WQYt8/iKP+iRCTCwdzEMIXsXklbRIib5rjeQ8= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1084/go.mod h1:qE67ApiBzeRvzeDsV+GxyIDbVIDemsKpHXllQATz/Vw= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1096 h1:h9FP40Ycg45egJlZcjbLyc4IUeFoq+wSpR43sHMALtM= @@ -834,6 +861,10 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1096 h1:7ZmPus github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1096/go.mod h1:aMpGcDskqqhXtfMaeo2egO61tgh/zt07L1ohSPwmjWk= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1096 h1:N62IFKL1ZRNQ7WPLNn8x9eYnwM4lOUIVY3buW6kbGtg= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1096/go.mod h1:4PZRRpZp+jvYBUbUajsoZREnk7sJXMnPAiGB4IX8IkM= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1102 h1:B0mJk0ojVOFCMLrBoxLNVgrGih11EezTekRffkACCAY= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1102/go.mod h1:0yyQ1r35jteb5DV4mcJZ5uh9NStWzjMYz9iSMnDMdJA= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1099 h1:kD+8RKF0uJCr7VaurAUA11NNAoln0HaagMCgQV6EnUw= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1099/go.mod h1:ellbjD8eHKHS4ixscLdiPJI8QoFIk0YNEgaDjxXMECM= github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho= github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE= @@ -850,6 +881,8 @@ github.com/volcengine/ve-tos-golang-sdk/v2 v2.7.9/go.mod h1:IrjK84IJJTuOZOTMv/P1 github.com/volcengine/volc-sdk-golang v1.0.23/go.mod h1:AfG/PZRUkHJ9inETvbjNifTDgut25Wbkm2QoYBTbvyU= github.com/volcengine/volc-sdk-golang v1.0.194 h1:3o0INQzdtYJWvdGrtX02booCqPL5TsWSq2W1Ur7Bzlo= github.com/volcengine/volc-sdk-golang v1.0.194/go.mod h1:u0VtPvlXWpXDTmc9IHkaW1q+5Jjwus4oAqRhNMDRInE= +github.com/volcengine/volc-sdk-golang v1.0.195 h1:hKX4pBhmKcB3652BTdcAmtgizEPBnoQUpTM+j5blMA4= +github.com/volcengine/volc-sdk-golang v1.0.195/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ= github.com/volcengine/volcengine-go-sdk v1.0.180 h1:lzcNlaxeGIUdXgDuVH7KJwZYZjIZzaCAYPDh91htU6U= github.com/volcengine/volcengine-go-sdk v1.0.180/go.mod h1:gfEDc1s7SYaGoY+WH2dRrS3qiuDJMkwqyfXWCa7+7oA= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= diff --git a/internal/applicant/providers.go b/internal/applicant/providers.go index d992e9c1..cc8a3cfd 100644 --- a/internal/applicant/providers.go +++ b/internal/applicant/providers.go @@ -6,23 +6,29 @@ import ( "github.com/go-acme/lego/v4/challenge" "github.com/usual2970/certimate/internal/domain" - providerACMEHttpReq "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/acmehttpreq" - providerAliyun "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/aliyun" - providerAWSRoute53 "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/aws-route53" - providerAzureDNS "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/azure-dns" - providerCloudflare "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/cloudflare" - providerClouDNS "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/cloudns" - providerGname "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/gname" - providerGoDaddy "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/godaddy" - providerHuaweiCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/huaweicloud" - providerNameDotCom "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namedotcom" - providerNameSilo "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namesilo" - providerNS1 "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/ns1" - providerPowerDNS "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/powerdns" - providerRainYun "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/rainyun" - providerTencentCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/tencentcloud" - providerVolcEngine "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/volcengine" - providerWestcn "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/westcn" + pACMEHttpReq "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/acmehttpreq" + pAliyun "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/aliyun" + pAWSRoute53 "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/aws-route53" + pAzureDNS "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/azure-dns" + pBaiduCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/baiducloud" + 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" + pDNSLA "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/dnsla" + pGcore "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/gcore" + pGname "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/gname" + pGoDaddy "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/godaddy" + pHuaweiCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/huaweicloud" + pJDCloud "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/jdcloud" + pNamecheap "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namecheap" + pNameDotCom "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namedotcom" + pNameSilo "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/namesilo" + pNS1 "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/ns1" + pPowerDNS "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/powerdns" + 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" + 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" "github.com/usual2970/certimate/internal/pkg/utils/maps" ) @@ -39,7 +45,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - applicant, err := providerACMEHttpReq.NewChallengeProvider(&providerACMEHttpReq.ACMEHttpReqApplicantConfig{ + applicant, err := pACMEHttpReq.NewChallengeProvider(&pACMEHttpReq.ChallengeProviderConfig{ Endpoint: access.Endpoint, Mode: access.Mode, Username: access.Username, @@ -56,7 +62,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - applicant, err := providerAliyun.NewChallengeProvider(&providerAliyun.AliyunApplicantConfig{ + applicant, err := pAliyun.NewChallengeProvider(&pAliyun.ChallengeProviderConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.AccessKeySecret, DnsPropagationTimeout: options.DnsPropagationTimeout, @@ -72,7 +78,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - applicant, err := providerAWSRoute53.NewChallengeProvider(&providerAWSRoute53.AWSRoute53ApplicantConfig{ + applicant, err := pAWSRoute53.NewChallengeProvider(&pAWSRoute53.ChallengeProviderConfig{ AccessKeyId: access.AccessKeyId, SecretAccessKey: access.SecretAccessKey, Region: maps.GetValueAsString(options.ProviderApplyConfig, "region"), @@ -83,14 +89,14 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { return applicant, err } - case domain.ApplyDNSProviderTypeAzureDNS: + case domain.ApplyDNSProviderTypeAzure, domain.ApplyDNSProviderTypeAzureDNS: { access := domain.AccessConfigForAzure{} if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - applicant, err := providerAzureDNS.NewChallengeProvider(&providerAzureDNS.AzureDNSApplicantConfig{ + applicant, err := pAzureDNS.NewChallengeProvider(&pAzureDNS.ChallengeProviderConfig{ TenantId: access.TenantId, ClientId: access.ClientId, ClientSecret: access.ClientSecret, @@ -101,6 +107,22 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { return applicant, err } + case domain.ApplyDNSProviderTypeBaiduCloud, domain.ApplyDNSProviderTypeBaiduCloudDNS: + { + access := domain.AccessConfigForBaiduCloud{} + if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + applicant, err := pBaiduCloud.NewChallengeProvider(&pBaiduCloud.ChallengeProviderConfig{ + AccessKeyId: access.AccessKeyId, + SecretAccessKey: access.SecretAccessKey, + DnsPropagationTimeout: options.DnsPropagationTimeout, + DnsTTL: options.DnsTTL, + }) + return applicant, err + } + case domain.ApplyDNSProviderTypeCloudflare: { access := domain.AccessConfigForCloudflare{} @@ -108,7 +130,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - applicant, err := providerCloudflare.NewChallengeProvider(&providerCloudflare.CloudflareApplicantConfig{ + applicant, err := pCloudflare.NewChallengeProvider(&pCloudflare.ChallengeProviderConfig{ DnsApiToken: access.DnsApiToken, DnsPropagationTimeout: options.DnsPropagationTimeout, DnsTTL: options.DnsTTL, @@ -123,7 +145,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - applicant, err := providerClouDNS.NewChallengeProvider(&providerClouDNS.ClouDNSApplicantConfig{ + applicant, err := pClouDNS.NewChallengeProvider(&pClouDNS.ChallengeProviderConfig{ AuthId: access.AuthId, AuthPassword: access.AuthPassword, DnsPropagationTimeout: options.DnsPropagationTimeout, @@ -132,6 +154,53 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { return applicant, err } + case domain.ApplyDNSProviderTypeCMCCCloud: + { + access := domain.AccessConfigForCMCCCloud{} + if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + applicant, err := pCMCCCloud.NewChallengeProvider(&pCMCCCloud.ChallengeProviderConfig{ + AccessKeyId: access.AccessKeyId, + AccessKeySecret: access.AccessKeySecret, + DnsPropagationTimeout: options.DnsPropagationTimeout, + DnsTTL: options.DnsTTL, + }) + return applicant, err + } + + case domain.ApplyDNSProviderTypeDNSLA: + { + access := domain.AccessConfigForDNSLA{} + if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + applicant, err := pDNSLA.NewChallengeProvider(&pDNSLA.ChallengeProviderConfig{ + ApiId: access.ApiId, + ApiSecret: access.ApiSecret, + DnsPropagationTimeout: options.DnsPropagationTimeout, + DnsTTL: options.DnsTTL, + }) + return applicant, err + } + + case domain.ApplyDNSProviderTypeGcore: + { + access := domain.AccessConfigForGcore{} + if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + applicant, err := pGcore.NewChallengeProvider(&pGcore.ChallengeProviderConfig{ + ApiToken: access.ApiToken, + DnsPropagationTimeout: options.DnsPropagationTimeout, + DnsTTL: options.DnsTTL, + }) + return applicant, err + } + case domain.ApplyDNSProviderTypeGname: { access := domain.AccessConfigForGname{} @@ -139,7 +208,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - applicant, err := providerGname.NewChallengeProvider(&providerGname.GnameApplicantConfig{ + applicant, err := pGname.NewChallengeProvider(&pGname.ChallengeProviderConfig{ AppId: access.AppId, AppKey: access.AppKey, DnsPropagationTimeout: options.DnsPropagationTimeout, @@ -155,7 +224,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - applicant, err := providerGoDaddy.NewChallengeProvider(&providerGoDaddy.GoDaddyApplicantConfig{ + applicant, err := pGoDaddy.NewChallengeProvider(&pGoDaddy.ChallengeProviderConfig{ ApiKey: access.ApiKey, ApiSecret: access.ApiSecret, DnsPropagationTimeout: options.DnsPropagationTimeout, @@ -171,7 +240,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - applicant, err := providerHuaweiCloud.NewChallengeProvider(&providerHuaweiCloud.HuaweiCloudApplicantConfig{ + applicant, err := pHuaweiCloud.NewChallengeProvider(&pHuaweiCloud.ChallengeProviderConfig{ AccessKeyId: access.AccessKeyId, SecretAccessKey: access.SecretAccessKey, Region: maps.GetValueAsString(options.ProviderApplyConfig, "region"), @@ -181,6 +250,39 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { return applicant, err } + case domain.ApplyDNSProviderTypeJDCloud, domain.ApplyDNSProviderTypeJDCloudDNS: + { + access := domain.AccessConfigForJDCloud{} + if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + applicant, err := pJDCloud.NewChallengeProvider(&pJDCloud.ChallengeProviderConfig{ + AccessKeyId: access.AccessKeyId, + AccessKeySecret: access.AccessKeySecret, + RegionId: maps.GetValueAsString(options.ProviderApplyConfig, "region_id"), + DnsPropagationTimeout: options.DnsPropagationTimeout, + DnsTTL: options.DnsTTL, + }) + return applicant, err + } + + case domain.ApplyDNSProviderTypeNamecheap: + { + access := domain.AccessConfigForNamecheap{} + if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + applicant, err := pNamecheap.NewChallengeProvider(&pNamecheap.ChallengeProviderConfig{ + Username: access.Username, + ApiKey: access.ApiKey, + DnsPropagationTimeout: options.DnsPropagationTimeout, + DnsTTL: options.DnsTTL, + }) + return applicant, err + } + case domain.ApplyDNSProviderTypeNameDotCom: { access := domain.AccessConfigForNameDotCom{} @@ -188,7 +290,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - applicant, err := providerNameDotCom.NewChallengeProvider(&providerNameDotCom.NameDotComApplicantConfig{ + applicant, err := pNameDotCom.NewChallengeProvider(&pNameDotCom.ChallengeProviderConfig{ Username: access.Username, ApiToken: access.ApiToken, DnsPropagationTimeout: options.DnsPropagationTimeout, @@ -204,7 +306,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - applicant, err := providerNameSilo.NewChallengeProvider(&providerNameSilo.NameSiloApplicantConfig{ + applicant, err := pNameSilo.NewChallengeProvider(&pNameSilo.ChallengeProviderConfig{ ApiKey: access.ApiKey, DnsPropagationTimeout: options.DnsPropagationTimeout, DnsTTL: options.DnsTTL, @@ -219,7 +321,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - applicant, err := providerNS1.NewChallengeProvider(&providerNS1.NS1ApplicantConfig{ + applicant, err := pNS1.NewChallengeProvider(&pNS1.ChallengeProviderConfig{ ApiKey: access.ApiKey, DnsPropagationTimeout: options.DnsPropagationTimeout, DnsTTL: options.DnsTTL, @@ -234,7 +336,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - applicant, err := providerPowerDNS.NewChallengeProvider(&providerPowerDNS.PowerDNSApplicantConfig{ + applicant, err := pPowerDNS.NewChallengeProvider(&pPowerDNS.ChallengeProviderConfig{ ApiUrl: access.ApiUrl, ApiKey: access.ApiKey, DnsPropagationTimeout: options.DnsPropagationTimeout, @@ -250,7 +352,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - applicant, err := providerRainYun.NewChallengeProvider(&providerRainYun.RainYunApplicantConfig{ + applicant, err := pRainYun.NewChallengeProvider(&pRainYun.ChallengeProviderConfig{ ApiKey: access.ApiKey, DnsPropagationTimeout: options.DnsPropagationTimeout, DnsTTL: options.DnsTTL, @@ -265,7 +367,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - applicant, err := providerTencentCloud.NewChallengeProvider(&providerTencentCloud.TencentCloudApplicantConfig{ + applicant, err := pTencentCloud.NewChallengeProvider(&pTencentCloud.ChallengeProviderConfig{ SecretId: access.SecretId, SecretKey: access.SecretKey, DnsPropagationTimeout: options.DnsPropagationTimeout, @@ -281,7 +383,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - applicant, err := providerVolcEngine.NewChallengeProvider(&providerVolcEngine.VolcEngineApplicantConfig{ + applicant, err := pVolcEngine.NewChallengeProvider(&pVolcEngine.ChallengeProviderConfig{ AccessKeyId: access.AccessKeyId, SecretAccessKey: access.SecretAccessKey, DnsPropagationTimeout: options.DnsPropagationTimeout, @@ -297,7 +399,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - applicant, err := providerWestcn.NewChallengeProvider(&providerWestcn.WestcnApplicantConfig{ + applicant, err := pWestcn.NewChallengeProvider(&pWestcn.ChallengeProviderConfig{ Username: access.Username, ApiPassword: access.ApiPassword, DnsPropagationTimeout: options.DnsPropagationTimeout, diff --git a/internal/deployer/deployer.go b/internal/deployer/deployer.go index e64c8a88..f95442a6 100644 --- a/internal/deployer/deployer.go +++ b/internal/deployer/deployer.go @@ -42,7 +42,7 @@ func NewWithDeployNode(node *domain.WorkflowNode, certdata struct { return nil, fmt.Errorf("failed to unmarshal access config: %w", err) } - deployer, logger, err := createDeployer(&deployerOptions{ + deployer, err := createDeployer(&deployerOptions{ Provider: domain.DeployProviderType(nodeConfig.Provider), ProviderAccessConfig: accessConfig, ProviderDeployConfig: nodeConfig.ProviderConfig, @@ -52,7 +52,7 @@ func NewWithDeployNode(node *domain.WorkflowNode, certdata struct { } return &proxyDeployer{ - logger: logger, + logger: logger.NewNilLogger(), deployer: deployer, deployCertificate: certdata.Certificate, deployPrivateKey: certdata.PrivateKey, diff --git a/internal/deployer/providers.go b/internal/deployer/providers.go index a9878f8a..6a8a0b6c 100644 --- a/internal/deployer/providers.go +++ b/internal/deployer/providers.go @@ -6,162 +6,183 @@ import ( "github.com/usual2970/certimate/internal/domain" "github.com/usual2970/certimate/internal/pkg/core/deployer" - providerAliyunALB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-alb" - providerAliyunCASDeploy "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-cas-deploy" - providerAliyunCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-cdn" - providerAliyunCLB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-clb" - providerAliyunDCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-dcdn" - providerAliyunESA "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-esa" - providerAliyunLive "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-live" - providerAliyunNLB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-nlb" - providerAliyunOSS "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-oss" - providerAliyunWAF "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-waf" - providerAWSCloudFront "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aws-cloudfront" - providerBaiduCloudCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baiducloud-cdn" - providerBaotaPanelSite "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotapanel-site" - providerBytePlusCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/byteplus-cdn" - providerDogeCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/dogecloud-cdn" - providerEdgioApplications "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/edgio-applications" - providerHuaweiCloudCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/huaweicloud-cdn" - providerHuaweiCloudELB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/huaweicloud-elb" - providerK8sSecret "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/k8s-secret" - providerLocal "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/local" - providerQiniuCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/qiniu-cdn" - providerQiniuPili "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/qiniu-pili" - providerSSH "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ssh" - providerTencentCloudCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-cdn" - providerTencentCloudCLB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-clb" - providerTencentCloudCOS "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-cos" - providerTencentCloudCSS "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-css" - providerTencentCloudECDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-ecdn" - providerTencentCloudEO "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-eo" - providerTencentCloudSSLDeploy "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-ssl-deploy" - providerUCloudUCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ucloud-ucdn" - providerUCloudUS3 "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ucloud-us3" - providerVolcEngineCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/volcengine-cdn" - providerVolcEngineCLB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/volcengine-clb" - providerVolcEngineDCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/volcengine-dcdn" - providerVolcEngineLive "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/volcengine-live" - providerVolcEngineTOS "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/volcengine-tos" - providerWebhook "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/webhook" - "github.com/usual2970/certimate/internal/pkg/core/logger" + pAliyunALB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-alb" + pAliyunCASDeploy "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-cas-deploy" + pAliyunCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-cdn" + pAliyunCLB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-clb" + pAliyunDCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-dcdn" + pAliyunESA "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-esa" + pAliyunLive "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-live" + pAliyunNLB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-nlb" + 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" + pAWSCloudFront "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aws-cloudfront" + pBaiduCloudCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baiducloud-cdn" + pBaishanCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baishan-cdn" + pBaotaPanelConsole "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotapanel-console" + pBaotaPanelSite "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotapanel-site" + 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" + pDogeCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/dogecloud-cdn" + pEdgioApplications "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/edgio-applications" + pGcoreCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/gcore-cdn" + pHuaweiCloudCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/huaweicloud-cdn" + pHuaweiCloudELB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/huaweicloud-elb" + pHuaweiCloudWAF "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/huaweicloud-waf" + pJDCloudALB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/jdcloud-alb" + pJDCloudCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/jdcloud-cdn" + pJDCloudLive "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/jdcloud-live" + pJDCloudVOD "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/jdcloud-vod" + pK8sSecret "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/k8s-secret" + pLocal "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/local" + pQiniuCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/qiniu-cdn" + pQiniuPili "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/qiniu-pili" + pSafeLine "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/safeline" + pSSH "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ssh" + pTencentCloudCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-cdn" + pTencentCloudCLB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-clb" + pTencentCloudCOS "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-cos" + 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" + pTencentCloudSSLDeploy "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-ssl-deploy" + pTencentCloudVOD "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-vod" + pTencentCloudWAF "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-waf" + pUCloudUCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ucloud-ucdn" + pUCloudUS3 "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/ucloud-us3" + pVolcEngineCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/volcengine-cdn" + pVolcEngineCLB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/volcengine-clb" + pVolcEngineDCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/volcengine-dcdn" + pVolcEngineImageX "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/volcengine-imagex" + pVolcEngineLive "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/volcengine-live" + pVolcEngineTOS "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/volcengine-tos" + pWebhook "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/webhook" "github.com/usual2970/certimate/internal/pkg/utils/maps" "github.com/usual2970/certimate/internal/pkg/utils/slices" ) -func createDeployer(options *deployerOptions) (deployer.Deployer, logger.Logger, error) { - logger := logger.NewDefaultLogger() - +func createDeployer(options *deployerOptions) (deployer.Deployer, error) { /* 注意:如果追加新的常量值,请保持以 ASCII 排序。 NOTICE: If you add new constant, please keep ASCII order. */ switch options.Provider { - case domain.DeployProviderTypeAliyunALB, domain.DeployProviderTypeAliyunCASDeploy, domain.DeployProviderTypeAliyunCDN, domain.DeployProviderTypeAliyunCLB, domain.DeployProviderTypeAliyunDCDN, domain.DeployProviderTypeAliyunESA, domain.DeployProviderTypeAliyunLive, domain.DeployProviderTypeAliyunNLB, domain.DeployProviderTypeAliyunOSS, domain.DeployProviderTypeAliyunWAF: + case domain.DeployProviderTypeAliyunALB, domain.DeployProviderTypeAliyunCASDeploy, domain.DeployProviderTypeAliyunCDN, domain.DeployProviderTypeAliyunCLB, domain.DeployProviderTypeAliyunDCDN, domain.DeployProviderTypeAliyunESA, domain.DeployProviderTypeAliyunLive, domain.DeployProviderTypeAliyunNLB, domain.DeployProviderTypeAliyunOSS, domain.DeployProviderTypeAliyunVOD, domain.DeployProviderTypeAliyunWAF: { access := domain.AccessConfigForAliyun{} if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { - return nil, nil, fmt.Errorf("failed to populate provider access config: %w", err) + return nil, fmt.Errorf("failed to populate provider access config: %w", err) } switch options.Provider { case domain.DeployProviderTypeAliyunALB: - deployer, err := providerAliyunALB.NewWithLogger(&providerAliyunALB.AliyunALBDeployerConfig{ + deployer, err := pAliyunALB.NewDeployer(&pAliyunALB.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.AccessKeySecret, Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), - ResourceType: providerAliyunALB.DeployResourceType(maps.GetValueAsString(options.ProviderDeployConfig, "resourceType")), + ResourceType: pAliyunALB.ResourceType(maps.GetValueAsString(options.ProviderDeployConfig, "resourceType")), LoadbalancerId: maps.GetValueAsString(options.ProviderDeployConfig, "loadbalancerId"), ListenerId: maps.GetValueAsString(options.ProviderDeployConfig, "listenerId"), Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), - }, logger) - return deployer, logger, err + }) + return deployer, err case domain.DeployProviderTypeAliyunCASDeploy: - deployer, err := providerAliyunCASDeploy.NewWithLogger(&providerAliyunCASDeploy.AliyunCASDeployDeployerConfig{ + deployer, err := pAliyunCASDeploy.NewDeployer(&pAliyunCASDeploy.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.AccessKeySecret, Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), ResourceIds: slices.Filter(strings.Split(maps.GetValueAsString(options.ProviderDeployConfig, "resourceIds"), ";"), func(s string) bool { return s != "" }), ContactIds: slices.Filter(strings.Split(maps.GetValueAsString(options.ProviderDeployConfig, "contactIds"), ";"), func(s string) bool { return s != "" }), - }, logger) - return deployer, logger, err + }) + return deployer, err case domain.DeployProviderTypeAliyunCDN: - deployer, err := providerAliyunCDN.NewWithLogger(&providerAliyunCDN.AliyunCDNDeployerConfig{ + deployer, err := pAliyunCDN.NewDeployer(&pAliyunCDN.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.AccessKeySecret, Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), - }, logger) - return deployer, logger, err + }) + return deployer, err case domain.DeployProviderTypeAliyunCLB: - deployer, err := providerAliyunCLB.NewWithLogger(&providerAliyunCLB.AliyunCLBDeployerConfig{ + deployer, err := pAliyunCLB.NewDeployer(&pAliyunCLB.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.AccessKeySecret, Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), - ResourceType: providerAliyunCLB.DeployResourceType(maps.GetValueAsString(options.ProviderDeployConfig, "resourceType")), + ResourceType: pAliyunCLB.ResourceType(maps.GetValueAsString(options.ProviderDeployConfig, "resourceType")), LoadbalancerId: maps.GetValueAsString(options.ProviderDeployConfig, "loadbalancerId"), ListenerPort: maps.GetValueOrDefaultAsInt32(options.ProviderDeployConfig, "listenerPort", 443), Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), - }, logger) - return deployer, logger, err + }) + return deployer, err case domain.DeployProviderTypeAliyunDCDN: - deployer, err := providerAliyunDCDN.NewWithLogger(&providerAliyunDCDN.AliyunDCDNDeployerConfig{ + deployer, err := pAliyunDCDN.NewDeployer(&pAliyunDCDN.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.AccessKeySecret, Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), - }, logger) - return deployer, logger, err + }) + return deployer, err case domain.DeployProviderTypeAliyunESA: - deployer, err := providerAliyunESA.NewWithLogger(&providerAliyunESA.AliyunESADeployerConfig{ + deployer, err := pAliyunESA.NewDeployer(&pAliyunESA.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.AccessKeySecret, Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), SiteId: maps.GetValueAsInt64(options.ProviderDeployConfig, "siteId"), - }, logger) - return deployer, logger, err + }) + return deployer, err case domain.DeployProviderTypeAliyunLive: - deployer, err := providerAliyunLive.NewWithLogger(&providerAliyunLive.AliyunLiveDeployerConfig{ + deployer, err := pAliyunLive.NewDeployer(&pAliyunLive.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.AccessKeySecret, Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), - }, logger) - return deployer, logger, err + }) + return deployer, err case domain.DeployProviderTypeAliyunNLB: - deployer, err := providerAliyunNLB.NewWithLogger(&providerAliyunNLB.AliyunNLBDeployerConfig{ + deployer, err := pAliyunNLB.NewDeployer(&pAliyunNLB.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.AccessKeySecret, Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), - ResourceType: providerAliyunNLB.DeployResourceType(maps.GetValueAsString(options.ProviderDeployConfig, "resourceType")), + ResourceType: pAliyunNLB.ResourceType(maps.GetValueAsString(options.ProviderDeployConfig, "resourceType")), LoadbalancerId: maps.GetValueAsString(options.ProviderDeployConfig, "loadbalancerId"), ListenerId: maps.GetValueAsString(options.ProviderDeployConfig, "listenerId"), - }, logger) - return deployer, logger, err + }) + return deployer, err case domain.DeployProviderTypeAliyunOSS: - deployer, err := providerAliyunOSS.NewWithLogger(&providerAliyunOSS.AliyunOSSDeployerConfig{ + deployer, err := pAliyunOSS.NewDeployer(&pAliyunOSS.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.AccessKeySecret, Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), Bucket: maps.GetValueAsString(options.ProviderDeployConfig, "bucket"), Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), - }, logger) - return deployer, logger, err + }) + return deployer, err + + case domain.DeployProviderTypeAliyunVOD: + deployer, err := pAliyunVOD.NewDeployer(&pAliyunVOD.DeployerConfig{ + AccessKeyId: access.AccessKeyId, + AccessKeySecret: access.AccessKeySecret, + Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), + Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + }) + return deployer, err case domain.DeployProviderTypeAliyunWAF: - deployer, err := providerAliyunWAF.NewWithLogger(&providerAliyunWAF.AliyunWAFDeployerConfig{ + deployer, err := pAliyunWAF.NewDeployer(&pAliyunWAF.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.AccessKeySecret, Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), InstanceId: maps.GetValueAsString(options.ProviderDeployConfig, "instanceId"), - }, logger) - return deployer, logger, err + }) + return deployer, err default: break @@ -172,18 +193,18 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, logger.Logger, { access := domain.AccessConfigForAWS{} if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { - return nil, nil, fmt.Errorf("failed to populate provider access config: %w", err) + return nil, fmt.Errorf("failed to populate provider access config: %w", err) } switch options.Provider { case domain.DeployProviderTypeAWSCloudFront: - deployer, err := providerAWSCloudFront.NewWithLogger(&providerAWSCloudFront.AWSCloudFrontDeployerConfig{ + deployer, err := pAWSCloudFront.NewDeployer(&pAWSCloudFront.DeployerConfig{ AccessKeyId: access.AccessKeyId, SecretAccessKey: access.SecretAccessKey, Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), DistributionId: maps.GetValueAsString(options.ProviderDeployConfig, "distributionId"), - }, logger) - return deployer, logger, err + }) + return deployer, err default: break @@ -194,117 +215,263 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, logger.Logger, { access := domain.AccessConfigForBaiduCloud{} if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { - return nil, nil, fmt.Errorf("failed to populate provider access config: %w", err) + return nil, fmt.Errorf("failed to populate provider access config: %w", err) } switch options.Provider { case domain.DeployProviderTypeBaiduCloudCDN: - deployer, err := providerBaiduCloudCDN.NewWithLogger(&providerBaiduCloudCDN.BaiduCloudCDNDeployerConfig{ + deployer, err := pBaiduCloudCDN.NewDeployer(&pBaiduCloudCDN.DeployerConfig{ AccessKeyId: access.AccessKeyId, SecretAccessKey: access.SecretAccessKey, Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), - }, logger) - return deployer, logger, err + }) + return deployer, err default: break } } - case domain.DeployProviderTypeBaotaPanelSite: + case domain.DeployProviderTypeBaishanCDN: + { + access := domain.AccessConfigForBaishan{} + if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + switch options.Provider { + case domain.DeployProviderTypeBaishanCDN: + deployer, err := pBaishanCDN.NewDeployer(&pBaishanCDN.DeployerConfig{ + ApiToken: access.ApiToken, + Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + }) + return deployer, err + + default: + break + } + } + + case domain.DeployProviderTypeBaotaPanelConsole, domain.DeployProviderTypeBaotaPanelSite: { access := domain.AccessConfigForBaotaPanel{} if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { - return nil, nil, fmt.Errorf("failed to populate provider access config: %w", err) + return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - deployer, err := providerBaotaPanelSite.NewWithLogger(&providerBaotaPanelSite.BaotaPanelSiteDeployerConfig{ - ApiUrl: access.ApiUrl, - ApiKey: access.ApiKey, - SiteName: maps.GetValueAsString(options.ProviderDeployConfig, "siteName"), - }, logger) - return deployer, logger, err + switch options.Provider { + case domain.DeployProviderTypeBaotaPanelConsole: + deployer, err := pBaotaPanelConsole.NewDeployer(&pBaotaPanelConsole.DeployerConfig{ + ApiUrl: access.ApiUrl, + ApiKey: access.ApiKey, + AutoRestart: maps.GetValueAsBool(options.ProviderDeployConfig, "autoRestart"), + }) + return deployer, err + + case domain.DeployProviderTypeBaotaPanelSite: + deployer, err := pBaotaPanelSite.NewDeployer(&pBaotaPanelSite.DeployerConfig{ + ApiUrl: access.ApiUrl, + ApiKey: access.ApiKey, + SiteType: maps.GetValueOrDefaultAsString(options.ProviderDeployConfig, "siteType", "other"), + SiteName: maps.GetValueAsString(options.ProviderDeployConfig, "siteName"), + SiteNames: slices.Filter(strings.Split(maps.GetValueAsString(options.ProviderDeployConfig, "siteNames"), ";"), func(s string) bool { return s != "" }), + }) + return deployer, err + + default: + break + } } case domain.DeployProviderTypeBytePlusCDN: { access := domain.AccessConfigForBytePlus{} if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { - return nil, nil, fmt.Errorf("failed to populate provider access config: %w", err) + return nil, fmt.Errorf("failed to populate provider access config: %w", err) } switch options.Provider { case domain.DeployProviderTypeBytePlusCDN: - deployer, err := providerBytePlusCDN.NewWithLogger(&providerBytePlusCDN.BytePlusCDNDeployerConfig{ + deployer, err := pBytePlusCDN.NewDeployer(&pBytePlusCDN.DeployerConfig{ AccessKey: access.AccessKey, SecretKey: access.SecretKey, Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), - }, logger) - return deployer, logger, err + }) + return deployer, err default: break } } + case domain.DeployProviderTypeCacheFly: + { + access := domain.AccessConfigForCacheFly{} + if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + deployer, err := pCacheFly.NewDeployer(&pCacheFly.DeployerConfig{ + ApiToken: access.ApiToken, + }) + return deployer, err + } + + case domain.DeployProviderTypeCdnfly: + { + access := domain.AccessConfigForCdnfly{} + if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + deployer, err := pCdnfly.NewDeployer(&pCdnfly.DeployerConfig{ + ApiUrl: access.ApiUrl, + ApiKey: access.ApiKey, + ApiSecret: access.ApiSecret, + ResourceType: pCdnfly.ResourceType(maps.GetValueAsString(options.ProviderDeployConfig, "resourceType")), + SiteId: maps.GetValueAsString(options.ProviderDeployConfig, "siteId"), + CertificateId: maps.GetValueAsString(options.ProviderDeployConfig, "certificateId"), + }) + return deployer, err + } + case domain.DeployProviderTypeDogeCloudCDN: { access := domain.AccessConfigForDogeCloud{} if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { - return nil, nil, fmt.Errorf("failed to populate provider access config: %w", err) + return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - deployer, err := providerDogeCDN.NewWithLogger(&providerDogeCDN.DogeCloudCDNDeployerConfig{ + deployer, err := pDogeCDN.NewDeployer(&pDogeCDN.DeployerConfig{ AccessKey: access.AccessKey, SecretKey: access.SecretKey, Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), - }, logger) - return deployer, logger, err + }) + return deployer, err } case domain.DeployProviderTypeEdgioApplications: { access := domain.AccessConfigForEdgio{} if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { - return nil, nil, fmt.Errorf("failed to populate provider access config: %w", err) + return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - deployer, err := providerEdgioApplications.NewWithLogger(&providerEdgioApplications.EdgioApplicationsDeployerConfig{ + deployer, err := pEdgioApplications.NewDeployer(&pEdgioApplications.DeployerConfig{ ClientId: access.ClientId, ClientSecret: access.ClientSecret, EnvironmentId: maps.GetValueAsString(options.ProviderDeployConfig, "environmentId"), - }, logger) - return deployer, logger, err + }) + return deployer, err } - case domain.DeployProviderTypeHuaweiCloudCDN, domain.DeployProviderTypeHuaweiCloudELB: + case domain.DeployProviderTypeGcoreCDN: + { + access := domain.AccessConfigForGcore{} + if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + switch options.Provider { + case domain.DeployProviderTypeGcoreCDN: + deployer, err := pGcoreCDN.NewDeployer(&pGcoreCDN.DeployerConfig{ + ApiToken: access.ApiToken, + ResourceId: maps.GetValueAsInt64(options.ProviderDeployConfig, "resourceId"), + }) + return deployer, err + + default: + break + } + } + + case domain.DeployProviderTypeHuaweiCloudCDN, domain.DeployProviderTypeHuaweiCloudELB, domain.DeployProviderTypeHuaweiCloudWAF: { access := domain.AccessConfigForHuaweiCloud{} if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { - return nil, nil, fmt.Errorf("failed to populate provider access config: %w", err) + return nil, fmt.Errorf("failed to populate provider access config: %w", err) } switch options.Provider { case domain.DeployProviderTypeHuaweiCloudCDN: - deployer, err := providerHuaweiCloudCDN.NewWithLogger(&providerHuaweiCloudCDN.HuaweiCloudCDNDeployerConfig{ + deployer, err := pHuaweiCloudCDN.NewDeployer(&pHuaweiCloudCDN.DeployerConfig{ AccessKeyId: access.AccessKeyId, SecretAccessKey: access.SecretAccessKey, Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), - }, logger) - return deployer, logger, err + }) + return deployer, err case domain.DeployProviderTypeHuaweiCloudELB: - deployer, err := providerHuaweiCloudELB.NewWithLogger(&providerHuaweiCloudELB.HuaweiCloudELBDeployerConfig{ + deployer, err := pHuaweiCloudELB.NewDeployer(&pHuaweiCloudELB.DeployerConfig{ AccessKeyId: access.AccessKeyId, SecretAccessKey: access.SecretAccessKey, Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), - ResourceType: providerHuaweiCloudELB.DeployResourceType(maps.GetValueAsString(options.ProviderDeployConfig, "resourceType")), + ResourceType: pHuaweiCloudELB.ResourceType(maps.GetValueAsString(options.ProviderDeployConfig, "resourceType")), CertificateId: maps.GetValueAsString(options.ProviderDeployConfig, "certificateId"), LoadbalancerId: maps.GetValueAsString(options.ProviderDeployConfig, "loadbalancerId"), ListenerId: maps.GetValueAsString(options.ProviderDeployConfig, "listenerId"), - }, logger) - return deployer, logger, err + }) + return deployer, err + + case domain.DeployProviderTypeHuaweiCloudWAF: + deployer, err := pHuaweiCloudWAF.NewDeployer(&pHuaweiCloudWAF.DeployerConfig{ + AccessKeyId: access.AccessKeyId, + SecretAccessKey: access.SecretAccessKey, + Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), + ResourceType: pHuaweiCloudWAF.ResourceType(maps.GetValueAsString(options.ProviderDeployConfig, "resourceType")), + CertificateId: maps.GetValueAsString(options.ProviderDeployConfig, "certificateId"), + Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + }) + return deployer, err + + default: + break + } + } + + case domain.DeployProviderTypeJDCloudALB, domain.DeployProviderTypeJDCloudCDN, domain.DeployProviderTypeJDCloudLive, domain.DeployProviderTypeJDCloudVOD: + { + access := domain.AccessConfigForJDCloud{} + if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + switch options.Provider { + case domain.DeployProviderTypeJDCloudALB: + deployer, err := pJDCloudALB.NewDeployer(&pJDCloudALB.DeployerConfig{ + AccessKeyId: access.AccessKeyId, + AccessKeySecret: access.AccessKeySecret, + RegionId: maps.GetValueAsString(options.ProviderDeployConfig, "regionId"), + ResourceType: pJDCloudALB.ResourceType(maps.GetValueAsString(options.ProviderDeployConfig, "resourceType")), + LoadbalancerId: maps.GetValueAsString(options.ProviderDeployConfig, "loadbalancerId"), + ListenerId: maps.GetValueAsString(options.ProviderDeployConfig, "listenerId"), + }) + return deployer, err + + case domain.DeployProviderTypeJDCloudCDN: + deployer, err := pJDCloudCDN.NewDeployer(&pJDCloudCDN.DeployerConfig{ + AccessKeyId: access.AccessKeyId, + AccessKeySecret: access.AccessKeySecret, + Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + }) + return deployer, err + + case domain.DeployProviderTypeJDCloudLive: + deployer, err := pJDCloudLive.NewDeployer(&pJDCloudLive.DeployerConfig{ + AccessKeyId: access.AccessKeyId, + AccessKeySecret: access.AccessKeySecret, + Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + }) + return deployer, err + + case domain.DeployProviderTypeJDCloudVOD: + deployer, err := pJDCloudVOD.NewDeployer(&pJDCloudVOD.DeployerConfig{ + AccessKeyId: access.AccessKeyId, + AccessKeySecret: access.AccessKeySecret, + Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + }) + return deployer, err default: break @@ -313,77 +480,93 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, logger.Logger, case domain.DeployProviderTypeLocal: { - deployer, err := providerLocal.NewWithLogger(&providerLocal.LocalDeployerConfig{ - ShellEnv: providerLocal.ShellEnvType(maps.GetValueAsString(options.ProviderDeployConfig, "shellEnv")), + deployer, err := pLocal.NewDeployer(&pLocal.DeployerConfig{ + ShellEnv: pLocal.ShellEnvType(maps.GetValueAsString(options.ProviderDeployConfig, "shellEnv")), PreCommand: maps.GetValueAsString(options.ProviderDeployConfig, "preCommand"), PostCommand: maps.GetValueAsString(options.ProviderDeployConfig, "postCommand"), - OutputFormat: providerLocal.OutputFormatType(maps.GetValueOrDefaultAsString(options.ProviderDeployConfig, "format", string(providerLocal.OUTPUT_FORMAT_PEM))), + OutputFormat: pLocal.OutputFormatType(maps.GetValueOrDefaultAsString(options.ProviderDeployConfig, "format", string(pLocal.OUTPUT_FORMAT_PEM))), OutputCertPath: maps.GetValueAsString(options.ProviderDeployConfig, "certPath"), OutputKeyPath: maps.GetValueAsString(options.ProviderDeployConfig, "keyPath"), PfxPassword: maps.GetValueAsString(options.ProviderDeployConfig, "pfxPassword"), JksAlias: maps.GetValueAsString(options.ProviderDeployConfig, "jksAlias"), JksKeypass: maps.GetValueAsString(options.ProviderDeployConfig, "jksKeypass"), JksStorepass: maps.GetValueAsString(options.ProviderDeployConfig, "jksStorepass"), - }, logger) - return deployer, logger, err + }) + return deployer, err } case domain.DeployProviderTypeKubernetesSecret: { access := domain.AccessConfigForKubernetes{} if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { - return nil, nil, fmt.Errorf("failed to populate provider access config: %w", err) + return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - deployer, err := providerK8sSecret.NewWithLogger(&providerK8sSecret.K8sSecretDeployerConfig{ + deployer, err := pK8sSecret.NewDeployer(&pK8sSecret.DeployerConfig{ KubeConfig: access.KubeConfig, Namespace: maps.GetValueOrDefaultAsString(options.ProviderDeployConfig, "namespace", "default"), SecretName: maps.GetValueAsString(options.ProviderDeployConfig, "secretName"), SecretType: maps.GetValueOrDefaultAsString(options.ProviderDeployConfig, "secretType", "kubernetes.io/tls"), SecretDataKeyForCrt: maps.GetValueOrDefaultAsString(options.ProviderDeployConfig, "secretDataKeyForCrt", "tls.crt"), SecretDataKeyForKey: maps.GetValueOrDefaultAsString(options.ProviderDeployConfig, "secretDataKeyForKey", "tls.key"), - }, logger) - return deployer, logger, err + }) + return deployer, err } case domain.DeployProviderTypeQiniuCDN, domain.DeployProviderTypeQiniuPili: { access := domain.AccessConfigForQiniu{} if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { - return nil, nil, fmt.Errorf("failed to populate provider access config: %w", err) + return nil, fmt.Errorf("failed to populate provider access config: %w", err) } switch options.Provider { case domain.DeployProviderTypeQiniuCDN: - deployer, err := providerQiniuCDN.NewWithLogger(&providerQiniuCDN.QiniuCDNDeployerConfig{ + deployer, err := pQiniuCDN.NewDeployer(&pQiniuCDN.DeployerConfig{ AccessKey: access.AccessKey, SecretKey: access.SecretKey, Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), - }, logger) - return deployer, logger, err + }) + return deployer, err case domain.DeployProviderTypeQiniuPili: - deployer, err := providerQiniuPili.NewWithLogger(&providerQiniuPili.QiniuPiliDeployerConfig{ + deployer, err := pQiniuPili.NewDeployer(&pQiniuPili.DeployerConfig{ AccessKey: access.AccessKey, SecretKey: access.SecretKey, Hub: maps.GetValueAsString(options.ProviderDeployConfig, "hub"), Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), - }, logger) - return deployer, logger, err + }) + return deployer, err default: break } } + case domain.DeployProviderTypeSafeLine: + { + access := domain.AccessConfigForSafeLine{} + if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + deployer, err := pSafeLine.NewDeployer(&pSafeLine.DeployerConfig{ + ApiUrl: access.ApiUrl, + ApiToken: access.ApiToken, + ResourceType: pSafeLine.ResourceType(maps.GetValueAsString(options.ProviderDeployConfig, "resourceType")), + CertificateId: maps.GetValueAsInt32(options.ProviderDeployConfig, "certificateId"), + }) + return deployer, err + } + case domain.DeployProviderTypeSSH: { access := domain.AccessConfigForSSH{} if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { - return nil, nil, fmt.Errorf("failed to populate provider access config: %w", err) + return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - deployer, err := providerSSH.NewWithLogger(&providerSSH.SshDeployerConfig{ + deployer, err := pSSH.NewDeployer(&pSSH.DeployerConfig{ SshHost: access.Host, SshPort: access.Port, SshUsername: access.Username, @@ -393,89 +576,108 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, logger.Logger, UseSCP: maps.GetValueAsBool(options.ProviderDeployConfig, "useSCP"), PreCommand: maps.GetValueAsString(options.ProviderDeployConfig, "preCommand"), PostCommand: maps.GetValueAsString(options.ProviderDeployConfig, "postCommand"), - OutputFormat: providerSSH.OutputFormatType(maps.GetValueOrDefaultAsString(options.ProviderDeployConfig, "format", string(providerSSH.OUTPUT_FORMAT_PEM))), + OutputFormat: pSSH.OutputFormatType(maps.GetValueOrDefaultAsString(options.ProviderDeployConfig, "format", string(pSSH.OUTPUT_FORMAT_PEM))), OutputCertPath: maps.GetValueAsString(options.ProviderDeployConfig, "certPath"), OutputKeyPath: maps.GetValueAsString(options.ProviderDeployConfig, "keyPath"), PfxPassword: maps.GetValueAsString(options.ProviderDeployConfig, "pfxPassword"), JksAlias: maps.GetValueAsString(options.ProviderDeployConfig, "jksAlias"), JksKeypass: maps.GetValueAsString(options.ProviderDeployConfig, "jksKeypass"), JksStorepass: maps.GetValueAsString(options.ProviderDeployConfig, "jksStorepass"), - }, logger) - return deployer, logger, err + }) + return deployer, err } - case domain.DeployProviderTypeTencentCloudCDN, domain.DeployProviderTypeTencentCloudCLB, domain.DeployProviderTypeTencentCloudCOS, domain.DeployProviderTypeTencentCloudCSS, domain.DeployProviderTypeTencentCloudECDN, domain.DeployProviderTypeTencentCloudEO, domain.DeployProviderTypeTencentCloudSSLDeploy: + case domain.DeployProviderTypeTencentCloudCDN, domain.DeployProviderTypeTencentCloudCLB, domain.DeployProviderTypeTencentCloudCOS, domain.DeployProviderTypeTencentCloudCSS, domain.DeployProviderTypeTencentCloudECDN, domain.DeployProviderTypeTencentCloudEO, domain.DeployProviderTypeTencentCloudSSLDeploy, domain.DeployProviderTypeTencentCloudVOD, domain.DeployProviderTypeTencentCloudWAF: { access := domain.AccessConfigForTencentCloud{} if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { - return nil, nil, fmt.Errorf("failed to populate provider access config: %w", err) + return nil, fmt.Errorf("failed to populate provider access config: %w", err) } switch options.Provider { case domain.DeployProviderTypeTencentCloudCDN: - deployer, err := providerTencentCloudCDN.NewWithLogger(&providerTencentCloudCDN.TencentCloudCDNDeployerConfig{ + deployer, err := pTencentCloudCDN.NewDeployer(&pTencentCloudCDN.DeployerConfig{ SecretId: access.SecretId, SecretKey: access.SecretKey, Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), - }, logger) - return deployer, logger, err + }) + return deployer, err case domain.DeployProviderTypeTencentCloudCLB: - deployer, err := providerTencentCloudCLB.NewWithLogger(&providerTencentCloudCLB.TencentCloudCLBDeployerConfig{ + deployer, err := pTencentCloudCLB.NewDeployer(&pTencentCloudCLB.DeployerConfig{ SecretId: access.SecretId, SecretKey: access.SecretKey, Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), - ResourceType: providerTencentCloudCLB.DeployResourceType(maps.GetValueAsString(options.ProviderDeployConfig, "resourceType")), + ResourceType: pTencentCloudCLB.ResourceType(maps.GetValueAsString(options.ProviderDeployConfig, "resourceType")), LoadbalancerId: maps.GetValueAsString(options.ProviderDeployConfig, "loadbalancerId"), ListenerId: maps.GetValueAsString(options.ProviderDeployConfig, "listenerId"), Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), - }, logger) - return deployer, logger, err + }) + return deployer, err case domain.DeployProviderTypeTencentCloudCOS: - deployer, err := providerTencentCloudCOS.NewWithLogger(&providerTencentCloudCOS.TencentCloudCOSDeployerConfig{ + deployer, err := pTencentCloudCOS.NewDeployer(&pTencentCloudCOS.DeployerConfig{ SecretId: access.SecretId, SecretKey: access.SecretKey, Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), Bucket: maps.GetValueAsString(options.ProviderDeployConfig, "bucket"), Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), - }, logger) - return deployer, logger, err + }) + return deployer, err case domain.DeployProviderTypeTencentCloudCSS: - deployer, err := providerTencentCloudCSS.NewWithLogger(&providerTencentCloudCSS.TencentCloudCSSDeployerConfig{ + deployer, err := pTencentCloudCSS.NewDeployer(&pTencentCloudCSS.DeployerConfig{ SecretId: access.SecretId, SecretKey: access.SecretKey, Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), - }, logger) - return deployer, logger, err + }) + return deployer, err case domain.DeployProviderTypeTencentCloudECDN: - deployer, err := providerTencentCloudECDN.NewWithLogger(&providerTencentCloudECDN.TencentCloudECDNDeployerConfig{ + deployer, err := pTencentCloudECDN.NewDeployer(&pTencentCloudECDN.DeployerConfig{ SecretId: access.SecretId, SecretKey: access.SecretKey, Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), - }, logger) - return deployer, logger, err + }) + return deployer, err case domain.DeployProviderTypeTencentCloudEO: - deployer, err := providerTencentCloudEO.NewWithLogger(&providerTencentCloudEO.TencentCloudEODeployerConfig{ + deployer, err := pTencentCloudEO.NewDeployer(&pTencentCloudEO.DeployerConfig{ SecretId: access.SecretId, SecretKey: access.SecretKey, ZoneId: maps.GetValueAsString(options.ProviderDeployConfig, "zoneId"), Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), - }, logger) - return deployer, logger, err + }) + return deployer, err case domain.DeployProviderTypeTencentCloudSSLDeploy: - deployer, err := providerTencentCloudSSLDeploy.NewWithLogger(&providerTencentCloudSSLDeploy.TencentCloudSSLDeployDeployerConfig{ + deployer, err := pTencentCloudSSLDeploy.NewDeployer(&pTencentCloudSSLDeploy.DeployerConfig{ SecretId: access.SecretId, SecretKey: access.SecretKey, Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), ResourceType: maps.GetValueAsString(options.ProviderDeployConfig, "resourceType"), ResourceIds: slices.Filter(strings.Split(maps.GetValueAsString(options.ProviderDeployConfig, "resourceIds"), ";"), func(s string) bool { return s != "" }), - }, logger) - return deployer, logger, err + }) + return deployer, err + + case domain.DeployProviderTypeTencentCloudVOD: + deployer, err := pTencentCloudVOD.NewDeployer(&pTencentCloudVOD.DeployerConfig{ + SecretId: access.SecretId, + SecretKey: access.SecretKey, + SubAppId: maps.GetValueAsInt64(options.ProviderDeployConfig, "subAppId"), + Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + }) + return deployer, err + + case domain.DeployProviderTypeTencentCloudWAF: + deployer, err := pTencentCloudWAF.NewDeployer(&pTencentCloudWAF.DeployerConfig{ + SecretId: access.SecretId, + SecretKey: access.SecretKey, + Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + DomainId: maps.GetValueAsString(options.ProviderDeployConfig, "domainId"), + InstanceId: maps.GetValueAsString(options.ProviderDeployConfig, "instanceId"), + }) + return deployer, err default: break @@ -486,86 +688,96 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, logger.Logger, { access := domain.AccessConfigForUCloud{} if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { - return nil, nil, fmt.Errorf("failed to populate provider access config: %w", err) + return nil, fmt.Errorf("failed to populate provider access config: %w", err) } switch options.Provider { case domain.DeployProviderTypeUCloudUCDN: - deployer, err := providerUCloudUCDN.NewWithLogger(&providerUCloudUCDN.UCloudUCDNDeployerConfig{ + deployer, err := pUCloudUCDN.NewDeployer(&pUCloudUCDN.DeployerConfig{ PrivateKey: access.PrivateKey, PublicKey: access.PublicKey, ProjectId: access.ProjectId, DomainId: maps.GetValueAsString(options.ProviderDeployConfig, "domainId"), - }, logger) - return deployer, logger, err + }) + return deployer, err case domain.DeployProviderTypeUCloudUS3: - deployer, err := providerUCloudUS3.NewWithLogger(&providerUCloudUS3.UCloudUS3DeployerConfig{ + deployer, err := pUCloudUS3.NewDeployer(&pUCloudUS3.DeployerConfig{ PrivateKey: access.PrivateKey, PublicKey: access.PublicKey, ProjectId: access.ProjectId, Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), Bucket: maps.GetValueAsString(options.ProviderDeployConfig, "bucket"), Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), - }, logger) - return deployer, logger, err + }) + return deployer, err default: break } } - case domain.DeployProviderTypeVolcEngineCDN, domain.DeployProviderTypeVolcEngineCLB, domain.DeployProviderTypeVolcEngineDCDN, domain.DeployProviderTypeVolcEngineLive, domain.DeployProviderTypeVolcEngineTOS: + case domain.DeployProviderTypeVolcEngineCDN, domain.DeployProviderTypeVolcEngineCLB, domain.DeployProviderTypeVolcEngineDCDN, domain.DeployProviderTypeVolcEngineImageX, domain.DeployProviderTypeVolcEngineLive, domain.DeployProviderTypeVolcEngineTOS: { access := domain.AccessConfigForVolcEngine{} if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { - return nil, nil, fmt.Errorf("failed to populate provider access config: %w", err) + return nil, fmt.Errorf("failed to populate provider access config: %w", err) } switch options.Provider { case domain.DeployProviderTypeVolcEngineCDN: - deployer, err := providerVolcEngineCDN.NewWithLogger(&providerVolcEngineCDN.VolcEngineCDNDeployerConfig{ + deployer, err := pVolcEngineCDN.NewDeployer(&pVolcEngineCDN.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.SecretAccessKey, Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), - }, logger) - return deployer, logger, err + }) + return deployer, err case domain.DeployProviderTypeVolcEngineCLB: - deployer, err := providerVolcEngineCLB.NewWithLogger(&providerVolcEngineCLB.VolcEngineCLBDeployerConfig{ + deployer, err := pVolcEngineCLB.NewDeployer(&pVolcEngineCLB.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.SecretAccessKey, Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), - ResourceType: providerVolcEngineCLB.DeployResourceType(maps.GetValueAsString(options.ProviderDeployConfig, "resourceType")), + ResourceType: pVolcEngineCLB.ResourceType(maps.GetValueAsString(options.ProviderDeployConfig, "resourceType")), ListenerId: maps.GetValueAsString(options.ProviderDeployConfig, "listenerId"), - }, logger) - return deployer, logger, err + }) + return deployer, err case domain.DeployProviderTypeVolcEngineDCDN: - deployer, err := providerVolcEngineDCDN.NewWithLogger(&providerVolcEngineDCDN.VolcEngineDCDNDeployerConfig{ + deployer, err := pVolcEngineDCDN.NewDeployer(&pVolcEngineDCDN.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.SecretAccessKey, Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), - }, logger) - return deployer, logger, err + }) + return deployer, err + + case domain.DeployProviderTypeVolcEngineImageX: + deployer, err := pVolcEngineImageX.NewDeployer(&pVolcEngineImageX.DeployerConfig{ + AccessKeyId: access.AccessKeyId, + AccessKeySecret: access.SecretAccessKey, + Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), + ServiceId: maps.GetValueAsString(options.ProviderDeployConfig, "serviceId"), + Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + }) + return deployer, err case domain.DeployProviderTypeVolcEngineLive: - deployer, err := providerVolcEngineLive.NewWithLogger(&providerVolcEngineLive.VolcEngineLiveDeployerConfig{ + deployer, err := pVolcEngineLive.NewDeployer(&pVolcEngineLive.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.SecretAccessKey, Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), - }, logger) - return deployer, logger, err + }) + return deployer, err case domain.DeployProviderTypeVolcEngineTOS: - deployer, err := providerVolcEngineTOS.NewWithLogger(&providerVolcEngineTOS.VolcEngineTOSDeployerConfig{ + deployer, err := pVolcEngineTOS.NewDeployer(&pVolcEngineTOS.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.SecretAccessKey, Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), Bucket: maps.GetValueAsString(options.ProviderDeployConfig, "bucket"), Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), - }, logger) - return deployer, logger, err + }) + return deployer, err default: break @@ -576,16 +788,16 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, logger.Logger, { access := domain.AccessConfigForWebhook{} if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { - return nil, nil, fmt.Errorf("failed to populate provider access config: %w", err) + return nil, fmt.Errorf("failed to populate provider access config: %w", err) } - deployer, err := providerWebhook.NewWithLogger(&providerWebhook.WebhookDeployerConfig{ + deployer, err := pWebhook.NewDeployer(&pWebhook.DeployerConfig{ WebhookUrl: access.Url, WebhookData: maps.GetValueAsString(options.ProviderDeployConfig, "webhookData"), - }, logger) - return deployer, logger, err + }) + return deployer, err } } - return nil, nil, fmt.Errorf("unsupported deployer provider: %s", string(options.Provider)) + return nil, fmt.Errorf("unsupported deployer provider: %s", string(options.Provider)) } diff --git a/internal/domain/access.go b/internal/domain/access.go index e9df61d2..25df3210 100644 --- a/internal/domain/access.go +++ b/internal/domain/access.go @@ -53,6 +53,10 @@ type AccessConfigForBaiduCloud struct { SecretAccessKey string `json:"secretAccessKey"` } +type AccessConfigForBaishan struct { + ApiToken string `json:"apiToken"` +} + type AccessConfigForBaotaPanel struct { ApiUrl string `json:"apiUrl"` ApiKey string `json:"apiKey"` @@ -63,6 +67,16 @@ type AccessConfigForBytePlus struct { SecretKey string `json:"secretKey"` } +type AccessConfigForCacheFly struct { + ApiToken string `json:"apiToken"` +} + +type AccessConfigForCdnfly struct { + ApiUrl string `json:"apiUrl"` + ApiKey string `json:"apiKey"` + ApiSecret string `json:"apiSecret"` +} + type AccessConfigForCloudflare struct { DnsApiToken string `json:"dnsApiToken"` } @@ -72,6 +86,16 @@ type AccessConfigForClouDNS struct { AuthPassword string `json:"authPassword"` } +type AccessConfigForCMCCCloud struct { + AccessKeyId string `json:"accessKeyId"` + AccessKeySecret string `json:"accessKeySecret"` +} + +type AccessConfigForDNSLA struct { + ApiId string `json:"apiId"` + ApiSecret string `json:"apiSecret"` +} + type AccessConfigForDogeCloud struct { AccessKey string `json:"accessKey"` SecretKey string `json:"secretKey"` @@ -82,6 +106,10 @@ type AccessConfigForEdgio struct { ClientSecret string `json:"clientSecret"` } +type AccessConfigForGcore struct { + ApiToken string `json:"apiToken"` +} + type AccessConfigForGname struct { AppId string `json:"appId"` AppKey string `json:"appKey"` @@ -97,12 +125,22 @@ type AccessConfigForHuaweiCloud struct { SecretAccessKey string `json:"secretAccessKey"` } -type AccessConfigForLocal struct{} +type AccessConfigForJDCloud struct { + AccessKeyId string `json:"accessKeyId"` + AccessKeySecret string `json:"accessKeySecret"` +} type AccessConfigForKubernetes struct { KubeConfig string `json:"kubeConfig,omitempty"` } +type AccessConfigForLocal struct{} + +type AccessConfigForNamecheap struct { + Username string `json:"username"` + ApiKey string `json:"apiKey"` +} + type AccessConfigForNameDotCom struct { Username string `json:"username"` ApiToken string `json:"apiToken"` @@ -130,6 +168,11 @@ type AccessConfigForRainYun struct { ApiKey string `json:"apiKey"` } +type AccessConfigForSafeLine struct { + ApiUrl string `json:"apiUrl"` + ApiToken string `json:"apiToken"` +} + type AccessConfigForSSH struct { Host string `json:"host"` Port int32 `json:"port"` diff --git a/internal/domain/provider.go b/internal/domain/provider.go index 350b3926..950abc08 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -16,33 +16,37 @@ const ( AccessProviderTypeAWS = AccessProviderType("aws") AccessProviderTypeAzure = AccessProviderType("azure") AccessProviderTypeBaiduCloud = AccessProviderType("baiducloud") - AccessProviderTypeBaishan = AccessProviderType("baishan") // 白山云(预留) + AccessProviderTypeBaishan = AccessProviderType("baishan") AccessProviderTypeBaotaPanel = AccessProviderType("baotapanel") AccessProviderTypeBytePlus = AccessProviderType("byteplus") - AccessProviderTypeCacheFly = AccessProviderType("cachefly") // CacheFly(预留) - AccessProviderTypeCdnfly = AccessProviderType("cdnfly") // Cdnly(预留) + AccessProviderTypeCacheFly = AccessProviderType("cachefly") + AccessProviderTypeCdnfly = AccessProviderType("cdnfly") AccessProviderTypeCloudflare = AccessProviderType("cloudflare") AccessProviderTypeClouDNS = AccessProviderType("cloudns") - AccessProviderTypeCMCCCloud = AccessProviderType("cmcccloud") // 移动云(预留) + AccessProviderTypeCMCCCloud = AccessProviderType("cmcccloud") AccessProviderTypeCTCCCloud = AccessProviderType("ctcccloud") // 联通云(预留) AccessProviderTypeCUCCCloud = AccessProviderType("cucccloud") // 天翼云(预留) + AccessProviderTypeDNSLA = AccessProviderType("dnsla") AccessProviderTypeDogeCloud = AccessProviderType("dogecloud") AccessProviderTypeEdgio = AccessProviderType("edgio") AccessProviderTypeFastly = AccessProviderType("fastly") // Fastly(预留) AccessProviderTypeGname = AccessProviderType("gname") - AccessProviderTypeGcore = AccessProviderType("gcore") // Gcore(预留) + AccessProviderTypeGcore = AccessProviderType("gcore") AccessProviderTypeGoDaddy = AccessProviderType("godaddy") AccessProviderTypeGoEdge = AccessProviderType("goedge") // GoEdge(预留) AccessProviderTypeHuaweiCloud = AccessProviderType("huaweicloud") + AccessProviderTypeJDCloud = AccessProviderType("jdcloud") AccessProviderTypeKubernetes = AccessProviderType("k8s") AccessProviderTypeLocal = AccessProviderType("local") + AccessProviderTypeNamecheap = AccessProviderType("namecheap") AccessProviderTypeNameDotCom = AccessProviderType("namedotcom") AccessProviderTypeNameSilo = AccessProviderType("namesilo") AccessProviderTypeNS1 = AccessProviderType("ns1") AccessProviderTypePowerDNS = AccessProviderType("powerdns") AccessProviderTypeQiniu = AccessProviderType("qiniu") + AccessProviderTypeQingCloud = AccessProviderType("qingcloud") // 青云(预留) AccessProviderTypeRainYun = AccessProviderType("rainyun") - AccessProviderTypeSafeLine = AccessProviderType("safeline") // 雷池(预留) + AccessProviderTypeSafeLine = AccessProviderType("safeline") AccessProviderTypeSSH = AccessProviderType("ssh") AccessProviderTypeTencentCloud = AccessProviderType("tencentcloud") AccessProviderTypeUCloud = AccessProviderType("ucloud") @@ -66,13 +70,22 @@ const ( ApplyDNSProviderTypeAliyunDNS = ApplyDNSProviderType("aliyun-dns") ApplyDNSProviderTypeAWS = ApplyDNSProviderType("aws") // 兼容旧值,等同于 [ApplyDNSProviderTypeAWSRoute53] ApplyDNSProviderTypeAWSRoute53 = ApplyDNSProviderType("aws-route53") + ApplyDNSProviderTypeAzure = ApplyDNSProviderType("azure") // 兼容旧值,等同于 [ApplyDNSProviderTypeAzure] ApplyDNSProviderTypeAzureDNS = ApplyDNSProviderType("azure-dns") + ApplyDNSProviderTypeBaiduCloud = ApplyDNSProviderType("baiducloud") // 兼容旧值,等同于 [ApplyDNSProviderTypeBaiduCloudDNS] + ApplyDNSProviderTypeBaiduCloudDNS = ApplyDNSProviderType("baiducloud-dns") ApplyDNSProviderTypeCloudflare = ApplyDNSProviderType("cloudflare") ApplyDNSProviderTypeClouDNS = ApplyDNSProviderType("cloudns") + ApplyDNSProviderTypeCMCCCloud = ApplyDNSProviderType("cmcccloud") + ApplyDNSProviderTypeDNSLA = ApplyDNSProviderType("dnsla") + ApplyDNSProviderTypeGcore = ApplyDNSProviderType("gcore") ApplyDNSProviderTypeGname = ApplyDNSProviderType("gname") ApplyDNSProviderTypeGoDaddy = ApplyDNSProviderType("godaddy") ApplyDNSProviderTypeHuaweiCloud = ApplyDNSProviderType("huaweicloud") // 兼容旧值,等同于 [ApplyDNSProviderTypeHuaweiCloudDNS] ApplyDNSProviderTypeHuaweiCloudDNS = ApplyDNSProviderType("huaweicloud-dns") + ApplyDNSProviderTypeJDCloud = ApplyDNSProviderType("jdcloud") // 兼容旧值,等同于 [ApplyDNSProviderTypeJDCloudDNS] + ApplyDNSProviderTypeJDCloudDNS = ApplyDNSProviderType("jdcloud-dns") + ApplyDNSProviderTypeNamecheap = ApplyDNSProviderType("namecheap") ApplyDNSProviderTypeNameDotCom = ApplyDNSProviderType("namedotcom") ApplyDNSProviderTypeNameSilo = ApplyDNSProviderType("namesilo") ApplyDNSProviderTypeNS1 = ApplyDNSProviderType("ns1") @@ -104,19 +117,31 @@ const ( DeployProviderTypeAliyunLive = DeployProviderType("aliyun-live") DeployProviderTypeAliyunNLB = DeployProviderType("aliyun-nlb") DeployProviderTypeAliyunOSS = DeployProviderType("aliyun-oss") + DeployProviderTypeAliyunVOD = DeployProviderType("aliyun-vod") DeployProviderTypeAliyunWAF = DeployProviderType("aliyun-waf") DeployProviderTypeAWSCloudFront = DeployProviderType("aws-cloudfront") DeployProviderTypeBaiduCloudCDN = DeployProviderType("baiducloud-cdn") + DeployProviderTypeBaishanCDN = DeployProviderType("baishan-cdn") + DeployProviderTypeBaotaPanelConsole = DeployProviderType("baotapanel-console") DeployProviderTypeBaotaPanelSite = DeployProviderType("baotapanel-site") DeployProviderTypeBytePlusCDN = DeployProviderType("byteplus-cdn") + DeployProviderTypeCacheFly = DeployProviderType("cachefly") + DeployProviderTypeCdnfly = DeployProviderType("cdnfly") DeployProviderTypeDogeCloudCDN = DeployProviderType("dogecloud-cdn") DeployProviderTypeEdgioApplications = DeployProviderType("edgio-applications") + DeployProviderTypeGcoreCDN = DeployProviderType("gcore-cdn") DeployProviderTypeHuaweiCloudCDN = DeployProviderType("huaweicloud-cdn") DeployProviderTypeHuaweiCloudELB = DeployProviderType("huaweicloud-elb") + DeployProviderTypeHuaweiCloudWAF = DeployProviderType("huaweicloud-waf") + DeployProviderTypeJDCloudALB = DeployProviderType("jdcloud-alb") + DeployProviderTypeJDCloudCDN = DeployProviderType("jdcloud-cdn") + DeployProviderTypeJDCloudLive = DeployProviderType("jdcloud-live") + DeployProviderTypeJDCloudVOD = DeployProviderType("jdcloud-vod") DeployProviderTypeKubernetesSecret = DeployProviderType("k8s-secret") DeployProviderTypeLocal = DeployProviderType("local") DeployProviderTypeQiniuCDN = DeployProviderType("qiniu-cdn") DeployProviderTypeQiniuPili = DeployProviderType("qiniu-pili") + DeployProviderTypeSafeLine = DeployProviderType("safeline") DeployProviderTypeSSH = DeployProviderType("ssh") DeployProviderTypeTencentCloudCDN = DeployProviderType("tencentcloud-cdn") DeployProviderTypeTencentCloudCLB = DeployProviderType("tencentcloud-clb") @@ -125,11 +150,14 @@ const ( DeployProviderTypeTencentCloudECDN = DeployProviderType("tencentcloud-ecdn") DeployProviderTypeTencentCloudEO = DeployProviderType("tencentcloud-eo") DeployProviderTypeTencentCloudSSLDeploy = DeployProviderType("tencentcloud-ssldeploy") + DeployProviderTypeTencentCloudVOD = DeployProviderType("tencentcloud-vod") + DeployProviderTypeTencentCloudWAF = DeployProviderType("tencentcloud-waf") DeployProviderTypeUCloudUCDN = DeployProviderType("ucloud-ucdn") DeployProviderTypeUCloudUS3 = DeployProviderType("ucloud-us3") DeployProviderTypeVolcEngineCDN = DeployProviderType("volcengine-cdn") DeployProviderTypeVolcEngineCLB = DeployProviderType("volcengine-clb") DeployProviderTypeVolcEngineDCDN = DeployProviderType("volcengine-dcdn") + DeployProviderTypeVolcEngineImageX = DeployProviderType("volcengine-imagex") DeployProviderTypeVolcEngineLive = DeployProviderType("volcengine-live") DeployProviderTypeVolcEngineTOS = DeployProviderType("volcengine-tos") DeployProviderTypeWebhook = DeployProviderType("webhook") diff --git a/internal/notify/providers.go b/internal/notify/providers.go index 6483a7a0..6e18a84c 100644 --- a/internal/notify/providers.go +++ b/internal/notify/providers.go @@ -5,14 +5,14 @@ import ( "github.com/usual2970/certimate/internal/domain" "github.com/usual2970/certimate/internal/pkg/core/notifier" - providerBark "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/bark" - providerDingTalk "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/dingtalk" - providerEmail "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/email" - providerLark "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/lark" - providerServerChan "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/serverchan" - providerTelegram "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/telegram" - providerWebhook "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/webhook" - providerWeCom "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/wecom" + pBark "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/bark" + pDingTalk "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/dingtalk" + pEmail "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/email" + pLark "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/lark" + pServerChan "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/serverchan" + pTelegram "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/telegram" + pWebhook "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/webhook" + pWeCom "github.com/usual2970/certimate/internal/pkg/core/notifier/providers/wecom" "github.com/usual2970/certimate/internal/pkg/utils/maps" ) @@ -23,19 +23,19 @@ func createNotifier(channel domain.NotifyChannelType, channelConfig map[string]a */ switch channel { case domain.NotifyChannelTypeBark: - return providerBark.New(&providerBark.BarkNotifierConfig{ + return pBark.NewNotifier(&pBark.NotifierConfig{ DeviceKey: maps.GetValueAsString(channelConfig, "deviceKey"), ServerUrl: maps.GetValueAsString(channelConfig, "serverUrl"), }) case domain.NotifyChannelTypeDingTalk: - return providerDingTalk.New(&providerDingTalk.DingTalkNotifierConfig{ + return pDingTalk.NewNotifier(&pDingTalk.NotifierConfig{ AccessToken: maps.GetValueAsString(channelConfig, "accessToken"), Secret: maps.GetValueAsString(channelConfig, "secret"), }) case domain.NotifyChannelTypeEmail: - return providerEmail.New(&providerEmail.EmailNotifierConfig{ + return pEmail.NewNotifier(&pEmail.NotifierConfig{ SmtpHost: maps.GetValueAsString(channelConfig, "smtpHost"), SmtpPort: maps.GetValueAsInt32(channelConfig, "smtpPort"), SmtpTLS: maps.GetValueOrDefaultAsBool(channelConfig, "smtpTLS", true), @@ -46,28 +46,28 @@ func createNotifier(channel domain.NotifyChannelType, channelConfig map[string]a }) case domain.NotifyChannelTypeLark: - return providerLark.New(&providerLark.LarkNotifierConfig{ + return pLark.NewNotifier(&pLark.NotifierConfig{ WebhookUrl: maps.GetValueAsString(channelConfig, "webhookUrl"), }) case domain.NotifyChannelTypeServerChan: - return providerServerChan.New(&providerServerChan.ServerChanNotifierConfig{ + return pServerChan.NewNotifier(&pServerChan.NotifierConfig{ Url: maps.GetValueAsString(channelConfig, "url"), }) case domain.NotifyChannelTypeTelegram: - return providerTelegram.New(&providerTelegram.TelegramNotifierConfig{ + return pTelegram.NewNotifier(&pTelegram.NotifierConfig{ ApiToken: maps.GetValueAsString(channelConfig, "apiToken"), ChatId: maps.GetValueAsInt64(channelConfig, "chatId"), }) case domain.NotifyChannelTypeWebhook: - return providerWebhook.New(&providerWebhook.WebhookNotifierConfig{ + return pWebhook.NewNotifier(&pWebhook.NotifierConfig{ Url: maps.GetValueAsString(channelConfig, "url"), }) case domain.NotifyChannelTypeWeCom: - return providerWeCom.New(&providerWeCom.WeComNotifierConfig{ + return pWeCom.NewNotifier(&pWeCom.NotifierConfig{ WebhookUrl: maps.GetValueAsString(channelConfig, "webhookUrl"), }) } diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/acmehttpreq/acmehttpreq.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/acmehttpreq/acmehttpreq.go index a25c13bb..ab2b11a6 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/acmehttpreq/acmehttpreq.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/acmehttpreq/acmehttpreq.go @@ -1,7 +1,6 @@ package acmehttpreq import ( - "errors" "net/url" "time" @@ -9,7 +8,7 @@ import ( "github.com/go-acme/lego/v4/providers/dns/httpreq" ) -type ACMEHttpReqApplicantConfig struct { +type ChallengeProviderConfig struct { Endpoint string `json:"endpoint"` Mode string `json:"mode"` Username string `json:"username"` @@ -17,9 +16,9 @@ type ACMEHttpReqApplicantConfig struct { DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` } -func NewChallengeProvider(config *ACMEHttpReqApplicantConfig) (challenge.Provider, error) { +func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } endpoint, _ := url.Parse(config.Endpoint) diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/aliyun/aliyun.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/aliyun/aliyun.go index 6f6d2d89..8f5cc56b 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/aliyun/aliyun.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/aliyun/aliyun.go @@ -1,23 +1,22 @@ package aliyun import ( - "errors" "time" "github.com/go-acme/lego/v4/challenge" "github.com/go-acme/lego/v4/providers/dns/alidns" ) -type AliyunApplicantConfig struct { +type ChallengeProviderConfig struct { AccessKeyId string `json:"accessKeyId"` AccessKeySecret string `json:"accessKeySecret"` DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` DnsTTL int32 `json:"dnsTTL,omitempty"` } -func NewChallengeProvider(config *AliyunApplicantConfig) (challenge.Provider, error) { +func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } providerConfig := alidns.NewDefaultConfig() diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/aws-route53/aws-route53.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/aws-route53/aws-route53.go index 6799885f..be1cfecf 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/aws-route53/aws-route53.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/aws-route53/aws-route53.go @@ -1,14 +1,13 @@ package awsroute53 import ( - "errors" "time" "github.com/go-acme/lego/v4/challenge" "github.com/go-acme/lego/v4/providers/dns/route53" ) -type AWSRoute53ApplicantConfig struct { +type ChallengeProviderConfig struct { AccessKeyId string `json:"accessKeyId"` SecretAccessKey string `json:"secretAccessKey"` Region string `json:"region"` @@ -17,9 +16,9 @@ type AWSRoute53ApplicantConfig struct { DnsTTL int32 `json:"dnsTTL,omitempty"` } -func NewChallengeProvider(config *AWSRoute53ApplicantConfig) (challenge.Provider, error) { +func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } providerConfig := route53.NewDefaultConfig() diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/azure-dns/azure-dns.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/azure-dns/azure-dns.go index 7cfce4a7..bf36f3fb 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/azure-dns/azure-dns.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/azure-dns/azure-dns.go @@ -1,7 +1,6 @@ package azuredns import ( - "errors" "fmt" "strings" "time" @@ -11,7 +10,7 @@ import ( "github.com/go-acme/lego/v4/providers/dns/azuredns" ) -type AzureDNSApplicantConfig struct { +type ChallengeProviderConfig struct { TenantId string `json:"tenantId"` ClientId string `json:"clientId"` ClientSecret string `json:"clientSecret"` @@ -20,9 +19,9 @@ type AzureDNSApplicantConfig struct { DnsTTL int32 `json:"dnsTTL,omitempty"` } -func NewChallengeProvider(config *AzureDNSApplicantConfig) (challenge.Provider, error) { +func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } providerConfig := azuredns.NewDefaultConfig() diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/baiducloud/baiducloud.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/baiducloud/baiducloud.go new file mode 100644 index 00000000..ac63665e --- /dev/null +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/baiducloud/baiducloud.go @@ -0,0 +1,39 @@ +package baiducloud + +import ( + "time" + + "github.com/go-acme/lego/v4/challenge" + + internal "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/baiducloud/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.DnsPropagationTimeout != 0 { + providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second + } + if config.DnsTTL != 0 { + providerConfig.TTL = config.DnsTTL + } + + provider, err := internal.NewDNSProviderConfig(providerConfig) + if err != nil { + return nil, err + } + + return provider, nil +} diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/baiducloud/internal/lego.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/baiducloud/internal/lego.go new file mode 100644 index 00000000..0d3f9c66 --- /dev/null +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/baiducloud/internal/lego.go @@ -0,0 +1,204 @@ +package lego_baiducloud + +import ( + "errors" + "fmt" + "strings" + "time" + + bceDns "github.com/baidubce/bce-sdk-go/services/dns" + "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/google/uuid" +) + +const ( + envNamespace = "BAIDUCLOUD_" + + 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 int32 + HTTPTimeout time.Duration +} + +type DNSProvider struct { + client *bceDns.Client + 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(EnvAccessKeyID, EnvSecretAccessKey) + if err != nil { + return nil, fmt.Errorf("baiducloud: %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("baiducloud: the configuration of the DNS provider is nil") + } + + client, err := bceDns.NewClient(config.AccessKeyID, config.SecretAccessKey, "") + if err != nil { + return nil, err + } else { + if client.Config != nil { + client.Config.ConnectionTimeoutInMillis = int(config.HTTPTimeout.Milliseconds()) + } + } + + 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("baiducloud: %w", err) + } + + subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone) + if err != nil { + return fmt.Errorf("baiducloud: %w", err) + } + + if err := d.addOrUpdateDNSRecord(dns01.UnFqdn(authZone), subDomain, info.Value); err != nil { + return fmt.Errorf("baiducloud: %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("baiducloud: %w", err) + } + + subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone) + if err != nil { + return fmt.Errorf("baiducloud: %w", err) + } + + if err := d.removeDNSRecord(dns01.UnFqdn(authZone), subDomain); err != nil { + return fmt.Errorf("baiducloud: %w", err) + } + + return nil +} + +func (d *DNSProvider) Timeout() (timeout, interval time.Duration) { + return d.config.PropagationTimeout, d.config.PollingInterval +} + +func (d *DNSProvider) getDNSRecord(zoneName, subDomain string) (*bceDns.Record, error) { + pageMarker := "" + pageSize := 1000 + for { + request := &bceDns.ListRecordRequest{} + request.Rr = subDomain + request.Marker = pageMarker + request.MaxKeys = pageSize + + response, err := d.client.ListRecord(zoneName, request) + if err != nil { + return nil, err + } + + for _, record := range response.Records { + if record.Type == "TXT" && record.Rr == subDomain { + return &record, nil + } + } + + if len(response.Records) < pageSize { + break + } + + pageMarker = response.NextMarker + } + + return nil, nil +} + +func (d *DNSProvider) addOrUpdateDNSRecord(zoneName, subDomain, value string) error { + record, err := d.getDNSRecord(zoneName, subDomain) + if err != nil { + return err + } + + if record == nil { + request := &bceDns.CreateRecordRequest{ + Type: "TXT", + Rr: subDomain, + Value: value, + Ttl: &d.config.TTL, + } + err := d.client.CreateRecord(zoneName, request, d.generateClientToken()) + return err + } else { + request := &bceDns.UpdateRecordRequest{ + Type: "TXT", + Rr: subDomain, + Value: value, + Ttl: &d.config.TTL, + } + err := d.client.UpdateRecord(zoneName, record.Id, request, d.generateClientToken()) + return err + } +} + +func (d *DNSProvider) removeDNSRecord(zoneName, subDomain string) error { + record, err := d.getDNSRecord(zoneName, subDomain) + if err != nil { + return err + } + + if record == nil { + return nil + } else { + err = d.client.DeleteRecord(zoneName, record.Id, d.generateClientToken()) + return err + } +} + +func (d *DNSProvider) generateClientToken() string { + return strings.ReplaceAll(uuid.New().String(), "-", "") +} diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/cloudflare/cloudflare.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/cloudflare/cloudflare.go index cea32e94..9782b39b 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/cloudflare/cloudflare.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/cloudflare/cloudflare.go @@ -1,22 +1,21 @@ package cloudflare import ( - "errors" "time" "github.com/go-acme/lego/v4/challenge" "github.com/go-acme/lego/v4/providers/dns/cloudflare" ) -type CloudflareApplicantConfig struct { +type ChallengeProviderConfig struct { DnsApiToken string `json:"dnsApiToken"` DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` DnsTTL int32 `json:"dnsTTL,omitempty"` } -func NewChallengeProvider(config *CloudflareApplicantConfig) (challenge.Provider, error) { +func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } providerConfig := cloudflare.NewDefaultConfig() diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/cloudns/cloudns.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/cloudns/cloudns.go index 09aac6df..dc351bd3 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/cloudns/cloudns.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/cloudns/cloudns.go @@ -1,23 +1,22 @@ package cloudns import ( - "errors" "time" "github.com/go-acme/lego/v4/challenge" "github.com/go-acme/lego/v4/providers/dns/cloudns" ) -type ClouDNSApplicantConfig struct { +type ChallengeProviderConfig struct { AuthId string `json:"authId"` AuthPassword string `json:"authPassword"` DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` DnsTTL int32 `json:"dnsTTL,omitempty"` } -func NewChallengeProvider(config *ClouDNSApplicantConfig) (challenge.Provider, error) { +func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } providerConfig := cloudns.NewDefaultConfig() diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/cmcccloud/cmcccloud.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/cmcccloud/cmcccloud.go new file mode 100644 index 00000000..ba0721fd --- /dev/null +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/cmcccloud/cmcccloud.go @@ -0,0 +1,40 @@ +package cmcccloud + +import ( + "errors" + "time" + + "github.com/go-acme/lego/v4/challenge" + + "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/cmcccloud/internal" +) + +type ChallengeProviderConfig struct { + AccessKeyId string `json:"accessKeyId"` + AccessKeySecret string `json:"accessKeySecret"` + 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.AccessKey = config.AccessKeyId + providerConfig.SecretKey = config.AccessKeySecret + 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 +} diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/cmcccloud/internal/lego.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/cmcccloud/internal/lego.go new file mode 100644 index 00000000..92ef6dfe --- /dev/null +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/cmcccloud/internal/lego.go @@ -0,0 +1,221 @@ +package internal + +import ( + "encoding/json" + "errors" + "fmt" + "strings" + "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" + "gitlab.ecloud.com/ecloud/ecloudsdkclouddns" + "gitlab.ecloud.com/ecloud/ecloudsdkclouddns/model" + "gitlab.ecloud.com/ecloud/ecloudsdkcore/config" +) + +const ( + envNamespace = "CMCCCLOUD_" + + EnvAccessKey = envNamespace + "ACCESS_KEY" + EnvSecretKey = envNamespace + "SECRET_KEY" + EnvTTL = envNamespace + "TTL" + EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT" + EnvPollingInterval = envNamespace + "POLLING_INTERVAL" + EnvReadTimeOut = envNamespace + "READ_TIMEOUT" + EnvConnectTimeout = envNamespace + "CONNECT_TIMEOUT" +) + +var _ challenge.ProviderTimeout = (*DNSProvider)(nil) + +type Config struct { + AccessKey string + SecretKey string + ReadTimeOut int + ConnectTimeout int + PropagationTimeout time.Duration + PollingInterval time.Duration + TTL int32 +} + +type DNSProvider struct { + client *ecloudsdkclouddns.Client + config *Config +} + +func NewDefaultConfig() *Config { + return &Config{ + ReadTimeOut: env.GetOrDefaultInt(EnvReadTimeOut, 30), + ConnectTimeout: env.GetOrDefaultInt(EnvConnectTimeout, 30), + TTL: int32(env.GetOrDefaultInt(EnvTTL, 600)), + PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 2*time.Minute), + PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval), + } +} + +func NewDNSProvider() (*DNSProvider, error) { + values, err := env.Get(EnvAccessKey, EnvSecretKey) + if err != nil { + return nil, fmt.Errorf("cmccecloud: %w", err) + } + + cfg := NewDefaultConfig() + cfg.AccessKey = values[EnvAccessKey] + cfg.SecretKey = values[EnvSecretKey] + + return NewDNSProviderConfig(cfg) +} + +func NewDNSProviderConfig(cfg *Config) (*DNSProvider, error) { + if cfg == nil { + return nil, errors.New("cmccecloud: the configuration of the DNS provider is nil") + } + + client := ecloudsdkclouddns.NewClient(&config.Config{ + AccessKey: cfg.AccessKey, + SecretKey: cfg.SecretKey, + // 资源池常量见: https://ecloud.10086.cn/op-help-center/doc/article/54462 + // 默认全局 + PoolId: "CIDC-CORE-00", + ReadTimeOut: cfg.ReadTimeOut, + ConnectTimeout: cfg.ConnectTimeout, + }) + + return &DNSProvider{ + client: client, + config: cfg, + }, nil +} + +func (d *DNSProvider) Present(domain, token, keyAuth string) error { + info := dns01.GetChallengeInfo(domain, keyAuth) + + zoneName, err := dns01.FindZoneByFqdn(info.EffectiveFQDN) + if err != nil { + return fmt.Errorf("cmccecloud: %w", err) + } + + subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zoneName) + if err != nil { + return fmt.Errorf("cmccecloud: %w", err) + } + + readDomain := strings.Trim(zoneName, ".") + record, err := d.getDomainRecord(readDomain, subDomain) + if err != nil { + return err + } + if record == nil { + // add new record + resp, err := d.client.CreateRecordOpenapi(&model.CreateRecordOpenapiRequest{ + CreateRecordOpenapiBody: &model.CreateRecordOpenapiBody{ + LineId: "0", // 默认线路 + Rr: subDomain, + DomainName: readDomain, + Description: "from certimate", + Type: model.CreateRecordOpenapiBodyTypeEnumTxt, + Value: info.Value, + Ttl: &d.config.TTL, + }, + }) + if err != nil { + return fmt.Errorf("lego: %w", err) + } + if resp.State != model.CreateRecordOpenapiResponseStateEnumOk { + return fmt.Errorf("lego: create record failed, response state: %s, message: %s, code: %s", resp.State, resp.ErrorMessage, resp.ErrorCode) + } + return nil + } else { + // update record + resp, err := d.client.ModifyRecordOpenapi(&model.ModifyRecordOpenapiRequest{ + ModifyRecordOpenapiBody: &model.ModifyRecordOpenapiBody{ + RecordId: record.RecordId, + Rr: subDomain, + DomainName: readDomain, + Description: "from certmate", + LineId: "0", + Type: model.ModifyRecordOpenapiBodyTypeEnumTxt, + Value: info.Value, + Ttl: &d.config.TTL, + }, + }) + if err != nil { + return fmt.Errorf("lego: %w", err) + } + if resp.State != model.ModifyRecordOpenapiResponseStateEnumOk { + return fmt.Errorf("lego: create record failed, response state: %s", resp.State) + } + return nil + } +} + +func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error { + challengeInfo := dns01.GetChallengeInfo(domain, keyAuth) + zoneName, err := dns01.FindZoneByFqdn(challengeInfo.FQDN) + if err != nil { + return fmt.Errorf("cmccecloud: %w", err) + } + subDomain, err := dns01.ExtractSubDomain(challengeInfo.FQDN, zoneName) + if err != nil { + return fmt.Errorf("cmccecloud: %w", err) + } + readDomain := strings.Trim(zoneName, ".") + record, err := d.getDomainRecord(readDomain, subDomain) + if err != nil { + return err + } + if record == nil { + return nil + } + resp, err := d.client.DeleteRecordOpenapi(&model.DeleteRecordOpenapiRequest{ + DeleteRecordOpenapiBody: &model.DeleteRecordOpenapiBody{ + RecordIdList: []string{record.RecordId}, + }, + }) + if err != nil { + return fmt.Errorf("lego: %w", err) + } + if resp.State != model.DeleteRecordOpenapiResponseStateEnumOk { + return fmt.Errorf("lego: delete record failed, response state: %s", resp.State) + } + return nil +} + +func (d *DNSProvider) Timeout() (timeout, interval time.Duration) { + return d.config.PropagationTimeout, d.config.PollingInterval +} + +func (d *DNSProvider) getDomainRecord(domain string, rr string) (*model.ListRecordOpenapiResponseData, error) { + pageSize := int32(50) + page := int32(1) + for { + resp, err := d.client.ListRecordOpenapi(&model.ListRecordOpenapiRequest{ + ListRecordOpenapiBody: &model.ListRecordOpenapiBody{ + DomainName: domain, + }, + ListRecordOpenapiQuery: &model.ListRecordOpenapiQuery{ + PageSize: &pageSize, + Page: &page, + }, + }) + if err != nil { + return nil, err + } + if resp.State != model.ListRecordOpenapiResponseStateEnumOk { + respStr, _ := json.Marshal(resp) + return nil, fmt.Errorf("request error. %s", string(respStr)) + } + if resp.Body.Data != nil { + for _, item := range *resp.Body.Data { + if item.Rr == rr { + return &item, nil + } + } + } + if resp.Body.TotalPages == nil || page >= *resp.Body.TotalPages { + return nil, nil + } + page++ + } +} diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/dnsla/dnsla.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/dnsla/dnsla.go new file mode 100644 index 00000000..5b0bd977 --- /dev/null +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/dnsla/dnsla.go @@ -0,0 +1,39 @@ +package dnsla + +import ( + "time" + + "github.com/go-acme/lego/v4/challenge" + + internal "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/dnsla/internal" +) + +type ChallengeProviderConfig struct { + ApiId string `json:"apiId"` + ApiSecret string `json:"apiSecret"` + 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.APIId = config.ApiId + providerConfig.APISecret = config.ApiSecret + if config.DnsPropagationTimeout != 0 { + providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second + } + if config.DnsTTL != 0 { + providerConfig.TTL = int(config.DnsTTL) + } + + provider, err := internal.NewDNSProviderConfig(providerConfig) + if err != nil { + return nil, err + } + + return provider, nil +} diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/dnsla/internal/lego.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/dnsla/internal/lego.go new file mode 100644 index 00000000..1b9603bd --- /dev/null +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/dnsla/internal/lego.go @@ -0,0 +1,240 @@ +package lego_dnsla + +import ( + "errors" + "fmt" + "strings" + "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" + + dnslasdk "github.com/usual2970/certimate/internal/pkg/vendors/dnsla-sdk" +) + +const ( + envNamespace = "DNSLA_" + + EnvAPIId = envNamespace + "API_ID" + EnvAPISecret = envNamespace + "API_KEY" + + EnvTTL = envNamespace + "TTL" + EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT" + EnvPollingInterval = envNamespace + "POLLING_INTERVAL" + EnvHTTPTimeout = envNamespace + "HTTP_TIMEOUT" +) + +var _ challenge.ProviderTimeout = (*DNSProvider)(nil) + +type Config struct { + APIId string + APISecret string + + PropagationTimeout time.Duration + PollingInterval time.Duration + TTL int + HTTPTimeout time.Duration +} + +type DNSProvider struct { + client *dnslasdk.Client + config *Config +} + +func NewDefaultConfig() *Config { + return &Config{ + TTL: 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(EnvAPIId, EnvAPISecret) + if err != nil { + return nil, fmt.Errorf("dnsla: %w", err) + } + + config := NewDefaultConfig() + config.APIId = values[EnvAPIId] + config.APISecret = values[EnvAPISecret] + + return NewDNSProviderConfig(config) +} + +func NewDNSProviderConfig(config *Config) (*DNSProvider, error) { + if config == nil { + return nil, errors.New("dnsla: the configuration of the DNS provider is nil") + } + + client := dnslasdk.NewClient(config.APIId, config.APISecret). + WithTimeout(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("dnsla: %w", err) + } + + subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone) + if err != nil { + return fmt.Errorf("dnsla: %w", err) + } + + if err := d.addOrUpdateDNSRecord(dns01.UnFqdn(authZone), subDomain, info.Value); err != nil { + return fmt.Errorf("dnsla: %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("dnsla: %w", err) + } + + subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone) + if err != nil { + return fmt.Errorf("dnsla: %w", err) + } + + if err := d.removeDNSRecord(dns01.UnFqdn(authZone), subDomain); err != nil { + return fmt.Errorf("dnsla: %w", err) + } + + return nil +} + +func (d *DNSProvider) Timeout() (timeout, interval time.Duration) { + return d.config.PropagationTimeout, d.config.PollingInterval +} + +func (d *DNSProvider) getDNSZone(zoneName string) (*dnslasdk.DomainInfo, error) { + pageIndex := 1 + pageSize := 100 + for { + request := &dnslasdk.ListDomainsRequest{ + PageIndex: int32(pageIndex), + PageSize: int32(pageSize), + } + response, err := d.client.ListDomains(request) + if err != nil { + return nil, err + } + + if response.Data != nil { + for _, item := range response.Data.Results { + if strings.TrimRight(item.Domain, ".") == zoneName || strings.TrimRight(item.DisplayDomain, ".") == zoneName { + return item, nil + } + } + } + + if response.Data == nil || len(response.Data.Results) < pageSize { + break + } + + pageIndex++ + } + + return nil, fmt.Errorf("dnsla: zone %s not found", zoneName) +} + +func (d *DNSProvider) getDNSZoneAndRecord(zoneName, subDomain string) (*dnslasdk.DomainInfo, *dnslasdk.RecordInfo, error) { + zone, err := d.getDNSZone(zoneName) + if err != nil { + return nil, nil, err + } + + pageIndex := 1 + pageSize := 100 + for { + request := &dnslasdk.ListRecordsRequest{ + DomainId: zone.Id, + Host: &subDomain, + PageIndex: int32(pageIndex), + PageSize: int32(pageSize), + } + response, err := d.client.ListRecords(request) + if err != nil { + return zone, nil, err + } + + if response.Data != nil { + for _, record := range response.Data.Results { + if record.Type == 16 && (record.Host == subDomain || record.DisplayHost == subDomain) { + return zone, record, nil + } + } + } + + if response.Data == nil || len(response.Data.Results) < pageSize { + break + } + + pageIndex++ + } + + return zone, nil, nil +} + +func (d *DNSProvider) addOrUpdateDNSRecord(zoneName, subDomain, value string) error { + zone, record, err := d.getDNSZoneAndRecord(zoneName, subDomain) + if err != nil { + return err + } + + if record == nil { + request := &dnslasdk.CreateRecordRequest{ + DomainId: zone.Id, + Type: 16, + Host: subDomain, + Data: value, + Ttl: int32(d.config.TTL), + } + _, err := d.client.CreateRecord(request) + return err + } else { + reqType := int32(16) + reqTtl := int32(d.config.TTL) + request := &dnslasdk.UpdateRecordRequest{ + Id: record.Id, + Type: &reqType, + Host: &subDomain, + Data: &value, + Ttl: &reqTtl, + } + _, err := d.client.UpdateRecord(request) + return err + } +} + +func (d *DNSProvider) removeDNSRecord(zoneName, subDomain string) error { + _, record, err := d.getDNSZoneAndRecord(zoneName, subDomain) + if err != nil { + return err + } + + if record == nil { + return nil + } else { + request := &dnslasdk.DeleteRecordRequest{ + Id: record.Id, + } + _, err = d.client.DeleteRecord(request) + return err + } +} diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/gcore/gcore.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/gcore/gcore.go new file mode 100644 index 00000000..ac9f7e61 --- /dev/null +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/gcore/gcore.go @@ -0,0 +1,36 @@ +package gcore + +import ( + "time" + + "github.com/go-acme/lego/v4/challenge" + "github.com/go-acme/lego/v4/providers/dns/gcore" +) + +type ChallengeProviderConfig struct { + ApiToken string `json:"apiToken"` + 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 := gcore.NewDefaultConfig() + providerConfig.APIToken = config.ApiToken + if config.DnsPropagationTimeout != 0 { + providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second + } + if config.DnsTTL != 0 { + providerConfig.TTL = int(config.DnsTTL) + } + + provider, err := gcore.NewDNSProviderConfig(providerConfig) + if err != nil { + return nil, err + } + + return provider, nil +} diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/gname/gname.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/gname/gname.go index 90cec017..42057149 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/gname/gname.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/gname/gname.go @@ -1,7 +1,6 @@ package gname import ( - "errors" "time" "github.com/go-acme/lego/v4/challenge" @@ -9,16 +8,16 @@ import ( internal "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/gname/internal" ) -type GnameApplicantConfig struct { +type ChallengeProviderConfig struct { AppId string `json:"appId"` AppKey string `json:"appKey"` DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` DnsTTL int32 `json:"dnsTTL,omitempty"` } -func NewChallengeProvider(config *GnameApplicantConfig) (challenge.Provider, error) { +func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } providerConfig := internal.NewDefaultConfig() diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/gname/internal/lego.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/gname/internal/lego.go index 03dc633f..3d0f2e54 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/gname/internal/lego.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/gname/internal/lego.go @@ -37,13 +37,13 @@ type Config struct { } type DNSProvider struct { - client *gnamesdk.GnameClient + client *gnamesdk.Client config *Config } func NewDefaultConfig() *Config { return &Config{ - TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL), + TTL: env.GetOrDefaultInt(EnvTTL, 300), PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 2*time.Minute), PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval), HTTPTimeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second), @@ -68,7 +68,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) { return nil, errors.New("gname: the configuration of the DNS provider is nil") } - client := gnamesdk.NewGnameClient(config.AppID, config.AppKey). + client := gnamesdk.NewClient(config.AppID, config.AppKey). WithTimeout(config.HTTPTimeout) return &DNSProvider{ @@ -80,17 +80,17 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) { func (d *DNSProvider) Present(domain, token, keyAuth string) error { info := dns01.GetChallengeInfo(domain, keyAuth) - zoneName, err := dns01.FindZoneByFqdn(info.EffectiveFQDN) + authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN) if err != nil { return fmt.Errorf("gname: %w", err) } - subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, zoneName) + subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone) if err != nil { return fmt.Errorf("gname: %w", err) } - if err := d.addOrUpdateDNSRecord(domain, subDomain, info.Value); err != nil { + if err := d.addOrUpdateDNSRecord(dns01.UnFqdn(authZone), subDomain, info.Value); err != nil { return fmt.Errorf("gname: %w", err) } @@ -98,10 +98,19 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error { } func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error { - fqdn, value := dns01.GetRecord(domain, keyAuth) - subDomain := dns01.UnFqdn(fqdn) + info := dns01.GetChallengeInfo(domain, keyAuth) - if err := d.removeDNSRecord(domain, subDomain, value); err != nil { + authZone, err := dns01.FindZoneByFqdn(info.EffectiveFQDN) + if err != nil { + return fmt.Errorf("gname: %w", err) + } + + subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone) + if err != nil { + return fmt.Errorf("gname: %w", err) + } + + if err := d.removeDNSRecord(dns01.UnFqdn(authZone), subDomain); err != nil { return fmt.Errorf("gname: %w", err) } @@ -112,12 +121,12 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) { return d.config.PropagationTimeout, d.config.PollingInterval } -func (d *DNSProvider) getDNSRecord(domain, subDomain string) (*gnamesdk.ResolutionRecord, error) { +func (d *DNSProvider) getDNSRecord(zoneName, subDomain string) (*gnamesdk.ResolutionRecord, error) { page := 1 pageSize := 20 for { request := &gnamesdk.ListDomainResolutionRequest{} - request.ZoneName = domain + request.ZoneName = zoneName request.Page = &page request.PageSize = &pageSize @@ -145,15 +154,15 @@ func (d *DNSProvider) getDNSRecord(domain, subDomain string) (*gnamesdk.Resoluti return nil, nil } -func (d *DNSProvider) addOrUpdateDNSRecord(domain, subDomain, value string) error { - record, err := d.getDNSRecord(domain, subDomain) +func (d *DNSProvider) addOrUpdateDNSRecord(zoneName, subDomain, value string) error { + record, err := d.getDNSRecord(zoneName, subDomain) if err != nil { return err } if record == nil { request := &gnamesdk.AddDomainResolutionRequest{ - ZoneName: domain, + ZoneName: zoneName, RecordType: "TXT", RecordName: subDomain, RecordValue: value, @@ -164,7 +173,7 @@ func (d *DNSProvider) addOrUpdateDNSRecord(domain, subDomain, value string) erro } else { request := &gnamesdk.ModifyDomainResolutionRequest{ ID: record.ID, - ZoneName: domain, + ZoneName: zoneName, RecordType: "TXT", RecordName: subDomain, RecordValue: value, @@ -175,8 +184,8 @@ func (d *DNSProvider) addOrUpdateDNSRecord(domain, subDomain, value string) erro } } -func (d *DNSProvider) removeDNSRecord(domain, subDomain, value string) error { - record, err := d.getDNSRecord(domain, subDomain) +func (d *DNSProvider) removeDNSRecord(zoneName, subDomain string) error { + record, err := d.getDNSRecord(zoneName, subDomain) if err != nil { return err } @@ -186,7 +195,7 @@ func (d *DNSProvider) removeDNSRecord(domain, subDomain, value string) error { } request := &gnamesdk.DeleteDomainResolutionRequest{ - ZoneName: domain, + ZoneName: zoneName, RecordID: record.ID, } _, err = d.client.DeleteDomainResolution(request) diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/godaddy/godaddy.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/godaddy/godaddy.go index 3a44616b..957c9185 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/godaddy/godaddy.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/godaddy/godaddy.go @@ -1,23 +1,22 @@ package godaddy import ( - "errors" "time" "github.com/go-acme/lego/v4/challenge" "github.com/go-acme/lego/v4/providers/dns/godaddy" ) -type GoDaddyApplicantConfig struct { +type ChallengeProviderConfig struct { ApiKey string `json:"apiKey"` ApiSecret string `json:"apiSecret"` DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` DnsTTL int32 `json:"dnsTTL,omitempty"` } -func NewChallengeProvider(config *GoDaddyApplicantConfig) (challenge.Provider, error) { +func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } providerConfig := godaddy.NewDefaultConfig() diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/huaweicloud/huaweicloud.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/huaweicloud/huaweicloud.go index cbdf2928..08a629fc 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/huaweicloud/huaweicloud.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/huaweicloud/huaweicloud.go @@ -1,14 +1,13 @@ package huaweicloud import ( - "errors" "time" "github.com/go-acme/lego/v4/challenge" hwc "github.com/go-acme/lego/v4/providers/dns/huaweicloud" ) -type HuaweiCloudApplicantConfig struct { +type ChallengeProviderConfig struct { AccessKeyId string `json:"accessKeyId"` SecretAccessKey string `json:"secretAccessKey"` Region string `json:"region"` @@ -16,9 +15,9 @@ type HuaweiCloudApplicantConfig struct { DnsTTL int32 `json:"dnsTTL,omitempty"` } -func NewChallengeProvider(config *HuaweiCloudApplicantConfig) (challenge.Provider, error) { +func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } region := config.Region diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/jdcloud/internal/lego.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/jdcloud/internal/lego.go new file mode 100644 index 00000000..68d81f7e --- /dev/null +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/jdcloud/internal/lego.go @@ -0,0 +1,238 @@ +package lego_jdcloud + +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" + jdCore "github.com/jdcloud-api/jdcloud-sdk-go/core" + jdDnsApi "github.com/jdcloud-api/jdcloud-sdk-go/services/domainservice/apis" + jdDnsClient "github.com/jdcloud-api/jdcloud-sdk-go/services/domainservice/client" + jdDnsModel "github.com/jdcloud-api/jdcloud-sdk-go/services/domainservice/models" +) + +const ( + envNamespace = "JDCLOUD_" + + EnvAccessKeyID = envNamespace + "ACCESS_KEY_ID" + EnvAccessKeySecret = envNamespace + "ACCESS_KEY_SECRET" + EnvRegionId = envNamespace + "REGION_ID" + + 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 + AccessKeySecret string + RegionId string + + PropagationTimeout time.Duration + PollingInterval time.Duration + TTL int32 + HTTPTimeout time.Duration +} + +type DNSProvider struct { + client *jdDnsClient.DomainserviceClient + 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(EnvAccessKeyID, EnvAccessKeySecret) + if err != nil { + return nil, fmt.Errorf("jdcloud: %w", err) + } + + config := NewDefaultConfig() + config.AccessKeyID = values[EnvAccessKeyID] + config.AccessKeySecret = values[EnvAccessKeySecret] + config.RegionId = values[EnvRegionId] + + return NewDNSProviderConfig(config) +} + +func NewDNSProviderConfig(config *Config) (*DNSProvider, error) { + if config == nil { + return nil, errors.New("jdcloud: the configuration of the DNS provider is nil") + } + + clientCredentials := jdCore.NewCredentials(config.AccessKeyID, config.AccessKeySecret) + client := jdDnsClient.NewDomainserviceClient(clientCredentials) + clientConfig := &client.Config + clientConfig.SetTimeout(config.HTTPTimeout) + client.SetConfig(clientConfig) + client.SetLogger(jdCore.NewDefaultLogger(jdCore.LogWarn)) + + 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("jdcloud: %w", err) + } + + subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone) + if err != nil { + return fmt.Errorf("jdcloud: %w", err) + } + + if err := d.addOrUpdateDNSRecord(dns01.UnFqdn(authZone), subDomain, info.Value); err != nil { + return fmt.Errorf("jdcloud: %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("jdcloud: %w", err) + } + + subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone) + if err != nil { + return fmt.Errorf("jdcloud: %w", err) + } + + if err := d.removeDNSRecord(dns01.UnFqdn(authZone), subDomain); err != nil { + return fmt.Errorf("jdcloud: %w", err) + } + + return nil +} + +func (d *DNSProvider) Timeout() (timeout, interval time.Duration) { + return d.config.PropagationTimeout, d.config.PollingInterval +} + +func (d *DNSProvider) getDNSZone(zoneName string) (*jdDnsModel.DomainInfo, error) { + pageNumber := 1 + pageSize := 10 + for { + request := jdDnsApi.NewDescribeDomainsRequest(d.config.RegionId, pageNumber, pageSize) + request.SetDomainName(zoneName) + + response, err := d.client.DescribeDomains(request) + if err != nil { + return nil, err + } + + for _, item := range response.Result.DataList { + if item.DomainName == zoneName { + return &item, nil + } + } + + if len(response.Result.DataList) < pageSize { + break + } + + pageNumber++ + } + + return nil, fmt.Errorf("jdcloud: zone %s not found", zoneName) +} + +func (d *DNSProvider) getDNSZoneAndRecord(zoneName, subDomain string) (*jdDnsModel.DomainInfo, *jdDnsModel.RRInfo, error) { + zone, err := d.getDNSZone(zoneName) + if err != nil { + return nil, nil, err + } + + pageNumber := 1 + pageSize := 10 + for { + request := jdDnsApi.NewDescribeResourceRecordRequest(d.config.RegionId, fmt.Sprintf("%d", zone.Id)) + request.SetSearch(subDomain) + request.SetPageNumber(pageNumber) + request.SetPageSize(pageSize) + + response, err := d.client.DescribeResourceRecord(request) + if err != nil { + return zone, nil, err + } + + for _, record := range response.Result.DataList { + if record.Type == "TXT" && record.HostRecord == subDomain { + return zone, &record, nil + } + } + + if len(response.Result.DataList) < pageSize { + break + } + + pageNumber++ + } + + return zone, nil, nil +} + +func (d *DNSProvider) addOrUpdateDNSRecord(zoneName, subDomain, value string) error { + zone, record, err := d.getDNSZoneAndRecord(zoneName, subDomain) + if err != nil { + return err + } + + if record == nil { + request := jdDnsApi.NewCreateResourceRecordRequest(d.config.RegionId, fmt.Sprintf("%d", zone.Id), &jdDnsModel.AddRR{ + Type: "TXT", + HostRecord: subDomain, + HostValue: value, + Ttl: int(d.config.TTL), + ViewValue: -1, + }) + _, err := d.client.CreateResourceRecord(request) + return err + } else { + request := jdDnsApi.NewModifyResourceRecordRequest(d.config.RegionId, fmt.Sprintf("%d", zone.Id), fmt.Sprintf("%d", record.Id), &jdDnsModel.UpdateRR{ + Type: "TXT", + HostRecord: subDomain, + HostValue: value, + Ttl: int(d.config.TTL), + ViewValue: -1, + }) + _, err := d.client.ModifyResourceRecord(request) + return err + } +} + +func (d *DNSProvider) removeDNSRecord(zoneName, subDomain string) error { + zone, record, err := d.getDNSZoneAndRecord(zoneName, subDomain) + if err != nil { + return err + } + + if record == nil { + return nil + } else { + request := jdDnsApi.NewDeleteResourceRecordRequest(d.config.RegionId, fmt.Sprintf("%d", zone.Id), fmt.Sprintf("%d", record.Id)) + _, err = d.client.DeleteResourceRecord(request) + return err + } +} diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/jdcloud/jdcloud.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/jdcloud/jdcloud.go new file mode 100644 index 00000000..5729d932 --- /dev/null +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/jdcloud/jdcloud.go @@ -0,0 +1,47 @@ +package jdcloud + +import ( + "time" + + "github.com/go-acme/lego/v4/challenge" + + internal "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/jdcloud/internal" +) + +type ChallengeProviderConfig struct { + AccessKeyId string `json:"accessKeyId"` + AccessKeySecret string `json:"accessKeySecret"` + RegionId string `json:"regionId"` + DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` + DnsTTL int32 `json:"dnsTTL,omitempty"` +} + +func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) { + if config == nil { + panic("config is nil") + } + + regionId := config.RegionId + if regionId == "" { + // 京东云的 SDK 要求必须传一个区域,实际上 DNS-01 流程里用不到,但不传会报错 + regionId = "cn-north-1" + } + + providerConfig := internal.NewDefaultConfig() + providerConfig.AccessKeyID = config.AccessKeyId + providerConfig.AccessKeySecret = config.AccessKeySecret + providerConfig.RegionId = regionId + if config.DnsPropagationTimeout != 0 { + providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second + } + if config.DnsTTL != 0 { + providerConfig.TTL = config.DnsTTL + } + + provider, err := internal.NewDNSProviderConfig(providerConfig) + if err != nil { + return nil, err + } + + return provider, nil +} diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/namecheap/namecheap.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/namecheap/namecheap.go new file mode 100644 index 00000000..9bf2f3c3 --- /dev/null +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/namecheap/namecheap.go @@ -0,0 +1,38 @@ +package namedotcom + +import ( + "time" + + "github.com/go-acme/lego/v4/challenge" + "github.com/go-acme/lego/v4/providers/dns/namecheap" +) + +type ChallengeProviderConfig struct { + Username string `json:"username"` + ApiKey string `json:"apiKey"` + 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 := namecheap.NewDefaultConfig() + providerConfig.APIUser = config.Username + providerConfig.APIKey = config.ApiKey + if config.DnsPropagationTimeout != 0 { + providerConfig.PropagationTimeout = time.Duration(config.DnsPropagationTimeout) * time.Second + } + if config.DnsTTL != 0 { + providerConfig.TTL = int(config.DnsTTL) + } + + provider, err := namecheap.NewDNSProviderConfig(providerConfig) + if err != nil { + return nil, err + } + + return provider, nil +} diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/namedotcom/namedotcom.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/namedotcom/namedotcom.go index c51b1a9b..daff3612 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/namedotcom/namedotcom.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/namedotcom/namedotcom.go @@ -1,23 +1,22 @@ package namedotcom import ( - "errors" "time" "github.com/go-acme/lego/v4/challenge" "github.com/go-acme/lego/v4/providers/dns/namedotcom" ) -type NameDotComApplicantConfig struct { +type ChallengeProviderConfig struct { Username string `json:"username"` ApiToken string `json:"apiToken"` DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` DnsTTL int32 `json:"dnsTTL,omitempty"` } -func NewChallengeProvider(config *NameDotComApplicantConfig) (challenge.Provider, error) { +func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } providerConfig := namedotcom.NewDefaultConfig() diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/namesilo/namesilo.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/namesilo/namesilo.go index 0f1bf8ea..5656136b 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/namesilo/namesilo.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/namesilo/namesilo.go @@ -1,22 +1,21 @@ package namesilo import ( - "errors" "time" "github.com/go-acme/lego/v4/challenge" "github.com/go-acme/lego/v4/providers/dns/namesilo" ) -type NameSiloApplicantConfig struct { +type ChallengeProviderConfig struct { ApiKey string `json:"apiKey"` DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` DnsTTL int32 `json:"dnsTTL,omitempty"` } -func NewChallengeProvider(config *NameSiloApplicantConfig) (challenge.Provider, error) { +func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } providerConfig := namesilo.NewDefaultConfig() diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/ns1/ns1.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/ns1/ns1.go index efa40076..1682e0c2 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/ns1/ns1.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/ns1/ns1.go @@ -1,22 +1,21 @@ package ns1 import ( - "errors" "time" "github.com/go-acme/lego/v4/challenge" "github.com/go-acme/lego/v4/providers/dns/ns1" ) -type NS1ApplicantConfig struct { +type ChallengeProviderConfig struct { ApiKey string `json:"apiKey"` DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` DnsTTL int32 `json:"dnsTTL,omitempty"` } -func NewChallengeProvider(config *NS1ApplicantConfig) (challenge.Provider, error) { +func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } providerConfig := ns1.NewDefaultConfig() diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/powerdns/powerdns.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/powerdns/powerdns.go index d5fa616c..3dc86d66 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/powerdns/powerdns.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/powerdns/powerdns.go @@ -1,7 +1,6 @@ package namesilo import ( - "errors" "net/url" "time" @@ -9,16 +8,16 @@ import ( "github.com/go-acme/lego/v4/providers/dns/pdns" ) -type PowerDNSApplicantConfig struct { +type ChallengeProviderConfig struct { ApiUrl string `json:"apiUrl"` ApiKey string `json:"apiKey"` DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` DnsTTL int32 `json:"dnsTTL,omitempty"` } -func NewChallengeProvider(config *PowerDNSApplicantConfig) (challenge.Provider, error) { +func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } host, _ := url.Parse(config.ApiUrl) diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/rainyun/rainyun.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/rainyun/rainyun.go index d250a279..2deda0f1 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/rainyun/rainyun.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/rainyun/rainyun.go @@ -1,22 +1,21 @@ package rainyun import ( - "errors" "time" "github.com/go-acme/lego/v4/challenge" "github.com/go-acme/lego/v4/providers/dns/rainyun" ) -type RainYunApplicantConfig struct { +type ChallengeProviderConfig struct { ApiKey string `json:"apiKey"` DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` DnsTTL int32 `json:"dnsTTL,omitempty"` } -func NewChallengeProvider(config *RainYunApplicantConfig) (challenge.Provider, error) { +func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } providerConfig := rainyun.NewDefaultConfig() diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/tencentcloud/tencentcloud.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/tencentcloud/tencentcloud.go index f7e6bf7b..8ef3760c 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/tencentcloud/tencentcloud.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/tencentcloud/tencentcloud.go @@ -1,23 +1,22 @@ package tencentcloud import ( - "errors" "time" "github.com/go-acme/lego/v4/challenge" "github.com/go-acme/lego/v4/providers/dns/tencentcloud" ) -type TencentCloudApplicantConfig struct { +type ChallengeProviderConfig struct { SecretId string `json:"secretId"` SecretKey string `json:"secretKey"` DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` DnsTTL int32 `json:"dnsTTL,omitempty"` } -func NewChallengeProvider(config *TencentCloudApplicantConfig) (challenge.Provider, error) { +func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } providerConfig := tencentcloud.NewDefaultConfig() diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/volcengine/volcengine.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/volcengine/volcengine.go index a8f11ff9..e0a1ae91 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/volcengine/volcengine.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/volcengine/volcengine.go @@ -1,23 +1,22 @@ package volcengine import ( - "errors" "time" "github.com/go-acme/lego/v4/challenge" "github.com/go-acme/lego/v4/providers/dns/volcengine" ) -type VolcEngineApplicantConfig struct { +type ChallengeProviderConfig struct { AccessKeyId string `json:"accessKeyId"` SecretAccessKey string `json:"secretAccessKey"` DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` DnsTTL int32 `json:"dnsTTL,omitempty"` } -func NewChallengeProvider(config *VolcEngineApplicantConfig) (challenge.Provider, error) { +func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } providerConfig := volcengine.NewDefaultConfig() diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/westcn/westcn.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/westcn/westcn.go index f20b5d21..f79c5a8c 100644 --- a/internal/pkg/core/applicant/acme-dns-01/lego-providers/westcn/westcn.go +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/westcn/westcn.go @@ -1,23 +1,22 @@ package westcn import ( - "errors" "time" "github.com/go-acme/lego/v4/challenge" "github.com/go-acme/lego/v4/providers/dns/westcn" ) -type WestcnApplicantConfig struct { +type ChallengeProviderConfig struct { Username string `json:"username"` ApiPassword string `json:"apiPassword"` DnsPropagationTimeout int32 `json:"dnsPropagationTimeout,omitempty"` DnsTTL int32 `json:"dnsTTL,omitempty"` } -func NewChallengeProvider(config *WestcnApplicantConfig) (challenge.Provider, error) { +func NewChallengeProvider(config *ChallengeProviderConfig) (challenge.Provider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } providerConfig := westcn.NewDefaultConfig() diff --git a/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb.go b/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb.go index 9878b6f4..39600c7b 100644 --- a/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb.go +++ b/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb.go @@ -18,10 +18,10 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aliyun-cas" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aliyun-cas" ) -type AliyunALBDeployerConfig struct { +type DeployerConfig struct { // 阿里云 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 阿里云 AccessKeySecret。 @@ -29,43 +29,35 @@ type AliyunALBDeployerConfig struct { // 阿里云地域。 Region string `json:"region"` // 部署资源类型。 - ResourceType DeployResourceType `json:"resourceType"` + ResourceType ResourceType `json:"resourceType"` // 负载均衡实例 ID。 - // 部署资源类型为 [DEPLOY_RESOURCE_LOADBALANCER] 时必填。 + // 部署资源类型为 [RESOURCE_TYPE_LOADBALANCER] 时必填。 LoadbalancerId string `json:"loadbalancerId,omitempty"` // 负载均衡监听 ID。 - // 部署资源类型为 [DEPLOY_RESOURCE_LISTENER] 时必填。 + // 部署资源类型为 [RESOURCE_TYPE_LISTENER] 时必填。 ListenerId string `json:"listenerId,omitempty"` // SNI 域名(支持泛域名)。 - // 部署资源类型为 [DEPLOY_RESOURCE_LOADBALANCER]、[DEPLOY_RESOURCE_LISTENER] 时选填。 + // 部署资源类型为 [RESOURCE_TYPE_LOADBALANCER]、[RESOURCE_TYPE_LISTENER] 时选填。 Domain string `json:"domain,omitempty"` } -type AliyunALBDeployer struct { - config *AliyunALBDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClients *wSdkClients sslUploader uploader.Uploader } -var _ deployer.Deployer = (*AliyunALBDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) type wSdkClients struct { alb *aliyunAlb.Client cas *aliyunCas.Client } -func New(config *AliyunALBDeployerConfig) (*AliyunALBDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *AliyunALBDeployerConfig, logger logger.Logger) (*AliyunALBDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } clients, err := createSdkClients(config.AccessKeyId, config.AccessKeySecret, config.Region) @@ -78,15 +70,20 @@ func NewWithLogger(config *AliyunALBDeployerConfig, logger logger.Logger) (*Aliy return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &AliyunALBDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClients: clients, sslUploader: uploader, }, nil } -func (d *AliyunALBDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // 上传证书到 CAS upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { @@ -97,12 +94,12 @@ func (d *AliyunALBDeployer) Deploy(ctx context.Context, certPem string, privkeyP // 根据部署资源类型决定部署方式 switch d.config.ResourceType { - case DEPLOY_RESOURCE_LOADBALANCER: + case RESOURCE_TYPE_LOADBALANCER: if err := d.deployToLoadbalancer(ctx, upres.CertId); err != nil { return nil, err } - case DEPLOY_RESOURCE_LISTENER: + case RESOURCE_TYPE_LISTENER: if err := d.deployToListener(ctx, upres.CertId); err != nil { return nil, err } @@ -114,7 +111,7 @@ func (d *AliyunALBDeployer) Deploy(ctx context.Context, certPem string, privkeyP return &deployer.DeployResult{}, nil } -func (d *AliyunALBDeployer) deployToLoadbalancer(ctx context.Context, cloudCertId string) error { +func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId string) error { if d.config.LoadbalancerId == "" { return errors.New("config `loadbalancerId` is required") } @@ -213,7 +210,7 @@ func (d *AliyunALBDeployer) deployToLoadbalancer(ctx context.Context, cloudCertI return nil } -func (d *AliyunALBDeployer) deployToListener(ctx context.Context, cloudCertId string) error { +func (d *DeployerProvider) deployToListener(ctx context.Context, cloudCertId string) error { if d.config.ListenerId == "" { return errors.New("config `listenerId` is required") } @@ -226,7 +223,7 @@ func (d *AliyunALBDeployer) deployToListener(ctx context.Context, cloudCertId st return nil } -func (d *AliyunALBDeployer) updateListenerCertificate(ctx context.Context, cloudListenerId string, cloudCertId string) error { +func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudListenerId string, cloudCertId string) error { // 查询监听的属性 // REF: https://help.aliyun.com/zh/slb/application-load-balancer/developer-reference/api-alb-2020-06-16-getlistenerattribute getListenerAttributeReq := &aliyunAlb.GetListenerAttributeRequest{ @@ -257,7 +254,7 @@ func (d *AliyunALBDeployer) updateListenerCertificate(ctx context.Context, cloud d.logger.Logt("已更新 ALB 监听配置", updateListenerAttributeResp) } else { - // 指定 SNI,需部署到扩展域名(支持泛域名) + // 指定 SNI,需部署到扩展域名 // 查询监听证书列表 // REF: https://help.aliyun.com/zh/slb/application-load-balancer/developer-reference/api-alb-2020-06-16-listlistenercertificates @@ -445,7 +442,7 @@ func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Up } } - uploader, err := uploaderp.New(&uploaderp.AliyunCASUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ AccessKeyId: accessKeyId, AccessKeySecret: accessKeySecret, Region: casRegion, diff --git a/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb_test.go b/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb_test.go index 15e6aff2..b5ae776a 100644 --- a/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb_test.go +++ b/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb_test.go @@ -63,11 +63,11 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) - deployer, err := provider.New(&provider.AliyunALBDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKeyId: fAccessKeyId, AccessKeySecret: fAccessKeySecret, Region: fRegion, - ResourceType: provider.DEPLOY_RESOURCE_LOADBALANCER, + ResourceType: provider.RESOURCE_TYPE_LOADBALANCER, LoadbalancerId: fLoadbalancerId, Domain: fDomain, }) @@ -98,11 +98,11 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("LISTENERID: %v", fListenerId), }, "\n")) - deployer, err := provider.New(&provider.AliyunALBDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKeyId: fAccessKeyId, AccessKeySecret: fAccessKeySecret, Region: fRegion, - ResourceType: provider.DEPLOY_RESOURCE_LISTENER, + ResourceType: provider.RESOURCE_TYPE_LISTENER, ListenerId: fListenerId, Domain: fDomain, }) diff --git a/internal/pkg/core/deployer/providers/aliyun-alb/consts.go b/internal/pkg/core/deployer/providers/aliyun-alb/consts.go new file mode 100644 index 00000000..a2d1aacc --- /dev/null +++ b/internal/pkg/core/deployer/providers/aliyun-alb/consts.go @@ -0,0 +1,10 @@ +package aliyunalb + +type ResourceType string + +const ( + // 资源类型:部署到指定负载均衡器。 + RESOURCE_TYPE_LOADBALANCER = ResourceType("loadbalancer") + // 资源类型:部署到指定监听器。 + RESOURCE_TYPE_LISTENER = ResourceType("listener") +) diff --git a/internal/pkg/core/deployer/providers/aliyun-alb/defines.go b/internal/pkg/core/deployer/providers/aliyun-alb/defines.go deleted file mode 100644 index 927e990a..00000000 --- a/internal/pkg/core/deployer/providers/aliyun-alb/defines.go +++ /dev/null @@ -1,10 +0,0 @@ -package aliyunalb - -type DeployResourceType string - -const ( - // 资源类型:部署到指定负载均衡器。 - DEPLOY_RESOURCE_LOADBALANCER = DeployResourceType("loadbalancer") - // 资源类型:部署到指定监听器。 - DEPLOY_RESOURCE_LISTENER = DeployResourceType("listener") -) diff --git a/internal/pkg/core/deployer/providers/aliyun-cas-deploy/aliyun_cas_deploy.go b/internal/pkg/core/deployer/providers/aliyun-cas-deploy/aliyun_cas_deploy.go index 31dc66b8..1cc36c6f 100644 --- a/internal/pkg/core/deployer/providers/aliyun-cas-deploy/aliyun_cas_deploy.go +++ b/internal/pkg/core/deployer/providers/aliyun-cas-deploy/aliyun_cas_deploy.go @@ -15,10 +15,10 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aliyun-cas" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aliyun-cas" ) -type AliyunCASDeployDeployerConfig struct { +type DeployerConfig struct { // 阿里云 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 阿里云 AccessKeySecret。 @@ -32,26 +32,18 @@ type AliyunCASDeployDeployerConfig struct { ContactIds []string `json:"contactIds"` } -type AliyunCASDeployDeployer struct { - config *AliyunCASDeployDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *aliyunCas.Client sslUploader uploader.Uploader } -var _ deployer.Deployer = (*AliyunCASDeployDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *AliyunCASDeployDeployerConfig) (*AliyunCASDeployDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *AliyunCASDeployDeployerConfig, logger logger.Logger) (*AliyunCASDeployDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region) @@ -64,15 +56,20 @@ func NewWithLogger(config *AliyunCASDeployDeployerConfig, logger logger.Logger) return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &AliyunCASDeployDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *AliyunCASDeployDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { if len(d.config.ResourceIds) == 0 { return nil, errors.New("config `resourceIds` is required") } @@ -178,7 +175,7 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunCas.Cl } func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Uploader, error) { - uploader, err := uploaderp.New(&uploaderp.AliyunCASUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ AccessKeyId: accessKeyId, AccessKeySecret: accessKeySecret, Region: region, diff --git a/internal/pkg/core/deployer/providers/aliyun-cdn/aliyun_cdn.go b/internal/pkg/core/deployer/providers/aliyun-cdn/aliyun_cdn.go index d2de5684..b0edd415 100644 --- a/internal/pkg/core/deployer/providers/aliyun-cdn/aliyun_cdn.go +++ b/internal/pkg/core/deployer/providers/aliyun-cdn/aliyun_cdn.go @@ -2,7 +2,6 @@ import ( "context" - "errors" "fmt" "strings" "time" @@ -16,7 +15,7 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/logger" ) -type AliyunCDNDeployerConfig struct { +type DeployerConfig struct { // 阿里云 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 阿里云 AccessKeySecret。 @@ -25,25 +24,17 @@ type AliyunCDNDeployerConfig struct { Domain string `json:"domain"` } -type AliyunCDNDeployer struct { - config *AliyunCDNDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *aliyunCdn.Client } -var _ deployer.Deployer = (*AliyunCDNDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *AliyunCDNDeployerConfig) (*AliyunCDNDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *AliyunCDNDeployerConfig, logger logger.Logger) (*AliyunCDNDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret) @@ -51,14 +42,19 @@ func NewWithLogger(config *AliyunCDNDeployerConfig, logger logger.Logger) (*Aliy return nil, xerrors.Wrap(err, "failed to create sdk client") } - return &AliyunCDNDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, }, nil } -func (d *AliyunCDNDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // "*.example.com" → ".example.com",适配阿里云 CDN 要求的泛域名格式 domain := strings.TrimPrefix(d.config.Domain, "*") diff --git a/internal/pkg/core/deployer/providers/aliyun-cdn/aliyun_cdn_test.go b/internal/pkg/core/deployer/providers/aliyun-cdn/aliyun_cdn_test.go index da4d1d74..1f92947f 100644 --- a/internal/pkg/core/deployer/providers/aliyun-cdn/aliyun_cdn_test.go +++ b/internal/pkg/core/deployer/providers/aliyun-cdn/aliyun_cdn_test.go @@ -52,7 +52,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) - deployer, err := provider.New(&provider.AliyunCDNDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKeyId: fAccessKeyId, AccessKeySecret: fAccessKeySecret, Domain: fDomain, diff --git a/internal/pkg/core/deployer/providers/aliyun-clb/aliyun_clb.go b/internal/pkg/core/deployer/providers/aliyun-clb/aliyun_clb.go index 4bd91611..21a1e471 100644 --- a/internal/pkg/core/deployer/providers/aliyun-clb/aliyun_clb.go +++ b/internal/pkg/core/deployer/providers/aliyun-clb/aliyun_clb.go @@ -13,10 +13,10 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aliyun-slb" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aliyun-slb" ) -type AliyunCLBDeployerConfig struct { +type DeployerConfig struct { // 阿里云 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 阿里云 AccessKeySecret。 @@ -24,38 +24,30 @@ type AliyunCLBDeployerConfig struct { // 阿里云地域。 Region string `json:"region"` // 部署资源类型。 - ResourceType DeployResourceType `json:"resourceType"` + ResourceType ResourceType `json:"resourceType"` // 负载均衡实例 ID。 - // 部署资源类型为 [DEPLOY_RESOURCE_LOADBALANCER]、[DEPLOY_RESOURCE_LISTENER] 时必填。 + // 部署资源类型为 [RESOURCE_TYPE_LOADBALANCER]、[RESOURCE_TYPE_LISTENER] 时必填。 LoadbalancerId string `json:"loadbalancerId,omitempty"` // 负载均衡监听端口。 - // 部署资源类型为 [DEPLOY_RESOURCE_LISTENER] 时必填。 + // 部署资源类型为 [RESOURCE_TYPE_LISTENER] 时必填。 ListenerPort int32 `json:"listenerPort,omitempty"` // SNI 域名(支持泛域名)。 - // 部署资源类型为 [DEPLOY_RESOURCE_LOADBALANCER]、[DEPLOY_RESOURCE_LISTENER] 时选填。 + // 部署资源类型为 [RESOURCE_TYPE_LOADBALANCER]、[RESOURCE_TYPE_LISTENER] 时选填。 Domain string `json:"domain,omitempty"` } -type AliyunCLBDeployer struct { - config *AliyunCLBDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *aliyunSlb.Client sslUploader uploader.Uploader } -var _ deployer.Deployer = (*AliyunCLBDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *AliyunCLBDeployerConfig) (*AliyunCLBDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *AliyunCLBDeployerConfig, logger logger.Logger) (*AliyunCLBDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region) @@ -63,7 +55,7 @@ func NewWithLogger(config *AliyunCLBDeployerConfig, logger logger.Logger) (*Aliy return nil, xerrors.Wrap(err, "failed to create sdk client") } - uploader, err := uploaderp.New(&uploaderp.AliyunSLBUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ AccessKeyId: config.AccessKeyId, AccessKeySecret: config.AccessKeySecret, Region: config.Region, @@ -72,15 +64,20 @@ func NewWithLogger(config *AliyunCLBDeployerConfig, logger logger.Logger) (*Aliy return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &AliyunCLBDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *AliyunCLBDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // 上传证书到 SLB upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { @@ -91,12 +88,12 @@ func (d *AliyunCLBDeployer) Deploy(ctx context.Context, certPem string, privkeyP // 根据部署资源类型决定部署方式 switch d.config.ResourceType { - case DEPLOY_RESOURCE_LOADBALANCER: + case RESOURCE_TYPE_LOADBALANCER: if err := d.deployToLoadbalancer(ctx, upres.CertId); err != nil { return nil, err } - case DEPLOY_RESOURCE_LISTENER: + case RESOURCE_TYPE_LISTENER: if err := d.deployToListener(ctx, upres.CertId); err != nil { return nil, err } @@ -108,7 +105,7 @@ func (d *AliyunCLBDeployer) Deploy(ctx context.Context, certPem string, privkeyP return &deployer.DeployResult{}, nil } -func (d *AliyunCLBDeployer) deployToLoadbalancer(ctx context.Context, cloudCertId string) error { +func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId string) error { if d.config.LoadbalancerId == "" { return errors.New("config `loadbalancerId` is required") } @@ -179,7 +176,7 @@ func (d *AliyunCLBDeployer) deployToLoadbalancer(ctx context.Context, cloudCertI return nil } -func (d *AliyunCLBDeployer) deployToListener(ctx context.Context, cloudCertId string) error { +func (d *DeployerProvider) deployToListener(ctx context.Context, cloudCertId string) error { if d.config.LoadbalancerId == "" { return errors.New("config `loadbalancerId` is required") } @@ -195,7 +192,7 @@ func (d *AliyunCLBDeployer) deployToListener(ctx context.Context, cloudCertId st return nil } -func (d *AliyunCLBDeployer) updateListenerCertificate(ctx context.Context, cloudLoadbalancerId string, cloudListenerPort int32, cloudCertId string) error { +func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudLoadbalancerId string, cloudListenerPort int32, cloudCertId string) error { // 查询监听配置 // REF: https://help.aliyun.com/zh/slb/classic-load-balancer/developer-reference/api-slb-2014-05-15-describeloadbalancerhttpslistenerattribute describeLoadBalancerHTTPSListenerAttributeReq := &aliyunSlb.DescribeLoadBalancerHTTPSListenerAttributeRequest{ @@ -214,8 +211,6 @@ func (d *AliyunCLBDeployer) updateListenerCertificate(ctx context.Context, cloud // 修改监听配置 // REF: https://help.aliyun.com/zh/slb/classic-load-balancer/developer-reference/api-slb-2014-05-15-setloadbalancerhttpslistenerattribute - // - // 注意修改监听配置要放在修改扩展域名之后 setLoadBalancerHTTPSListenerAttributeReq := &aliyunSlb.SetLoadBalancerHTTPSListenerAttributeRequest{ RegionId: tea.String(d.config.Region), LoadBalancerId: tea.String(cloudLoadbalancerId), @@ -229,7 +224,7 @@ func (d *AliyunCLBDeployer) updateListenerCertificate(ctx context.Context, cloud d.logger.Logt("已更新 CLB HTTPS 监听配置", setLoadBalancerHTTPSListenerAttributeResp) } else { - // 指定 SNI,需部署到扩展域名(支持泛域名) + // 指定 SNI,需部署到扩展域名 // 查询扩展域名 // REF: https://help.aliyun.com/zh/slb/classic-load-balancer/developer-reference/api-slb-2014-05-15-describedomainextensions diff --git a/internal/pkg/core/deployer/providers/aliyun-clb/aliyun_clb_test.go b/internal/pkg/core/deployer/providers/aliyun-clb/aliyun_clb_test.go index 0b27c5f8..a845bf86 100644 --- a/internal/pkg/core/deployer/providers/aliyun-clb/aliyun_clb_test.go +++ b/internal/pkg/core/deployer/providers/aliyun-clb/aliyun_clb_test.go @@ -63,11 +63,11 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) - deployer, err := provider.New(&provider.AliyunCLBDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKeyId: fAccessKeyId, AccessKeySecret: fAccessKeySecret, Region: fRegion, - ResourceType: provider.DEPLOY_RESOURCE_LOADBALANCER, + ResourceType: provider.RESOURCE_TYPE_LOADBALANCER, LoadbalancerId: fLoadbalancerId, Domain: fDomain, }) @@ -99,11 +99,11 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("LISTENERPORT: %v", fListenerPort), }, "\n")) - deployer, err := provider.New(&provider.AliyunCLBDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKeyId: fAccessKeyId, AccessKeySecret: fAccessKeySecret, Region: fRegion, - ResourceType: provider.DEPLOY_RESOURCE_LISTENER, + ResourceType: provider.RESOURCE_TYPE_LISTENER, LoadbalancerId: fLoadbalancerId, ListenerPort: int32(fListenerPort), Domain: fDomain, diff --git a/internal/pkg/core/deployer/providers/aliyun-clb/consts.go b/internal/pkg/core/deployer/providers/aliyun-clb/consts.go new file mode 100644 index 00000000..ad4fb070 --- /dev/null +++ b/internal/pkg/core/deployer/providers/aliyun-clb/consts.go @@ -0,0 +1,10 @@ +package aliyunclb + +type ResourceType string + +const ( + // 资源类型:部署到指定负载均衡器。 + RESOURCE_TYPE_LOADBALANCER = ResourceType("loadbalancer") + // 资源类型:部署到指定监听器。 + RESOURCE_TYPE_LISTENER = ResourceType("listener") +) diff --git a/internal/pkg/core/deployer/providers/aliyun-clb/defines.go b/internal/pkg/core/deployer/providers/aliyun-clb/defines.go deleted file mode 100644 index 4a02ab20..00000000 --- a/internal/pkg/core/deployer/providers/aliyun-clb/defines.go +++ /dev/null @@ -1,10 +0,0 @@ -package aliyunclb - -type DeployResourceType string - -const ( - // 资源类型:部署到指定负载均衡器。 - DEPLOY_RESOURCE_LOADBALANCER = DeployResourceType("loadbalancer") - // 资源类型:部署到指定监听器。 - DEPLOY_RESOURCE_LISTENER = DeployResourceType("listener") -) diff --git a/internal/pkg/core/deployer/providers/aliyun-dcdn/aliyun_dcdn.go b/internal/pkg/core/deployer/providers/aliyun-dcdn/aliyun_dcdn.go index 65c9a375..bfa28e7b 100644 --- a/internal/pkg/core/deployer/providers/aliyun-dcdn/aliyun_dcdn.go +++ b/internal/pkg/core/deployer/providers/aliyun-dcdn/aliyun_dcdn.go @@ -2,7 +2,6 @@ import ( "context" - "errors" "fmt" "strings" "time" @@ -16,7 +15,7 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/logger" ) -type AliyunDCDNDeployerConfig struct { +type DeployerConfig struct { // 阿里云 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 阿里云 AccessKeySecret。 @@ -25,25 +24,17 @@ type AliyunDCDNDeployerConfig struct { Domain string `json:"domain"` } -type AliyunDCDNDeployer struct { - config *AliyunDCDNDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *aliyunDcdn.Client } -var _ deployer.Deployer = (*AliyunDCDNDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *AliyunDCDNDeployerConfig) (*AliyunDCDNDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *AliyunDCDNDeployerConfig, logger logger.Logger) (*AliyunDCDNDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret) @@ -51,14 +42,19 @@ func NewWithLogger(config *AliyunDCDNDeployerConfig, logger logger.Logger) (*Ali return nil, xerrors.Wrap(err, "failed to create sdk client") } - return &AliyunDCDNDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, }, nil } -func (d *AliyunDCDNDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // "*.example.com" → ".example.com",适配阿里云 DCDN 要求的泛域名格式 domain := strings.TrimPrefix(d.config.Domain, "*") diff --git a/internal/pkg/core/deployer/providers/aliyun-dcdn/aliyun_dcdn_test.go b/internal/pkg/core/deployer/providers/aliyun-dcdn/aliyun_dcdn_test.go index ffbfcd1f..04ca4c48 100644 --- a/internal/pkg/core/deployer/providers/aliyun-dcdn/aliyun_dcdn_test.go +++ b/internal/pkg/core/deployer/providers/aliyun-dcdn/aliyun_dcdn_test.go @@ -52,7 +52,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) - deployer, err := provider.New(&provider.AliyunDCDNDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKeyId: fAccessKeyId, AccessKeySecret: fAccessKeySecret, Domain: fDomain, diff --git a/internal/pkg/core/deployer/providers/aliyun-esa/aliyun_esa.go b/internal/pkg/core/deployer/providers/aliyun-esa/aliyun_esa.go index a09f8bbf..1ccbdae5 100644 --- a/internal/pkg/core/deployer/providers/aliyun-esa/aliyun_esa.go +++ b/internal/pkg/core/deployer/providers/aliyun-esa/aliyun_esa.go @@ -15,10 +15,10 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aliyun-cas" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aliyun-cas" ) -type AliyunESADeployerConfig struct { +type DeployerConfig struct { // 阿里云 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 阿里云 AccessKeySecret。 @@ -29,26 +29,18 @@ type AliyunESADeployerConfig struct { SiteId int64 `json:"siteId"` } -type AliyunESADeployer struct { - config *AliyunESADeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *aliyunEsa.Client sslUploader uploader.Uploader } -var _ deployer.Deployer = (*AliyunESADeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *AliyunESADeployerConfig) (*AliyunESADeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *AliyunESADeployerConfig, logger logger.Logger) (*AliyunESADeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region) @@ -61,15 +53,20 @@ func NewWithLogger(config *AliyunESADeployerConfig, logger logger.Logger) (*Aliy return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &AliyunESADeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *AliyunESADeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { if d.config.SiteId == 0 { return nil, errors.New("config `siteId` is required") } @@ -129,7 +126,7 @@ func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Up } } - uploader, err := uploaderp.New(&uploaderp.AliyunCASUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ AccessKeyId: accessKeyId, AccessKeySecret: accessKeySecret, Region: casRegion, diff --git a/internal/pkg/core/deployer/providers/aliyun-esa/aliyun_esa_test.go b/internal/pkg/core/deployer/providers/aliyun-esa/aliyun_esa_test.go index 980dc9a0..c2d81aa3 100644 --- a/internal/pkg/core/deployer/providers/aliyun-esa/aliyun_esa_test.go +++ b/internal/pkg/core/deployer/providers/aliyun-esa/aliyun_esa_test.go @@ -56,7 +56,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("SITEID: %v", fSiteId), }, "\n")) - deployer, err := provider.New(&provider.AliyunESADeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKeyId: fAccessKeyId, AccessKeySecret: fAccessKeySecret, Region: fRegion, diff --git a/internal/pkg/core/deployer/providers/aliyun-live/aliyun_live.go b/internal/pkg/core/deployer/providers/aliyun-live/aliyun_live.go index 2e0c46af..5735da79 100644 --- a/internal/pkg/core/deployer/providers/aliyun-live/aliyun_live.go +++ b/internal/pkg/core/deployer/providers/aliyun-live/aliyun_live.go @@ -2,7 +2,6 @@ import ( "context" - "errors" "fmt" "strings" "time" @@ -16,7 +15,7 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/logger" ) -type AliyunLiveDeployerConfig struct { +type DeployerConfig struct { // 阿里云 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 阿里云 AccessKeySecret。 @@ -27,25 +26,17 @@ type AliyunLiveDeployerConfig struct { Domain string `json:"domain"` } -type AliyunLiveDeployer struct { - config *AliyunLiveDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *aliyunLive.Client } -var _ deployer.Deployer = (*AliyunLiveDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *AliyunLiveDeployerConfig) (*AliyunLiveDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *AliyunLiveDeployerConfig, logger logger.Logger) (*AliyunLiveDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region) @@ -53,14 +44,19 @@ func NewWithLogger(config *AliyunLiveDeployerConfig, logger logger.Logger) (*Ali return nil, xerrors.Wrap(err, "failed to create sdk client") } - return &AliyunLiveDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, }, nil } -func (d *AliyunLiveDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // "*.example.com" → ".example.com",适配阿里云 Live 要求的泛域名格式 domain := strings.TrimPrefix(d.config.Domain, "*") diff --git a/internal/pkg/core/deployer/providers/aliyun-live/aliyun_live_test.go b/internal/pkg/core/deployer/providers/aliyun-live/aliyun_live_test.go index d66f647a..fcf01147 100644 --- a/internal/pkg/core/deployer/providers/aliyun-live/aliyun_live_test.go +++ b/internal/pkg/core/deployer/providers/aliyun-live/aliyun_live_test.go @@ -16,6 +16,7 @@ var ( fInputKeyPath string fAccessKeyId string fAccessKeySecret string + fRegion string fDomain string ) @@ -26,6 +27,7 @@ func init() { flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "") flag.StringVar(&fAccessKeySecret, argsPrefix+"ACCESSKEYSECRET", "", "") + flag.StringVar(&fRegion, argsPrefix+"REGION", "", "") flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "") } @@ -37,6 +39,7 @@ Shell command to run this test: --CERTIMATE_DEPLOYER_ALIYUNLIVE_INPUTKEYPATH="/path/to/your-input-key.pem" \ --CERTIMATE_DEPLOYER_ALIYUNLIVE_ACCESSKEYID="your-access-key-id" \ --CERTIMATE_DEPLOYER_ALIYUNLIVE_ACCESSKEYSECRET="your-access-key-secret" \ + --CERTIMATE_DEPLOYER_ALIYUNLIVE_REGION="cn-hangzhou" \ --CERTIMATE_DEPLOYER_ALIYUNLIVE_DOMAIN="example.com" */ func TestDeploy(t *testing.T) { @@ -49,12 +52,14 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath), fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId), fmt.Sprintf("ACCESSKEYSECRET: %v", fAccessKeySecret), + fmt.Sprintf("REGION: %v", fRegion), fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) - deployer, err := provider.New(&provider.AliyunLiveDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKeyId: fAccessKeyId, AccessKeySecret: fAccessKeySecret, + Region: fRegion, Domain: fDomain, }) if err != nil { diff --git a/internal/pkg/core/deployer/providers/aliyun-nlb/aliyun_nlb.go b/internal/pkg/core/deployer/providers/aliyun-nlb/aliyun_nlb.go index 6deee907..0f1f1bca 100644 --- a/internal/pkg/core/deployer/providers/aliyun-nlb/aliyun_nlb.go +++ b/internal/pkg/core/deployer/providers/aliyun-nlb/aliyun_nlb.go @@ -14,10 +14,10 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aliyun-cas" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aliyun-cas" ) -type AliyunNLBDeployerConfig struct { +type DeployerConfig struct { // 阿里云 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 阿里云 AccessKeySecret。 @@ -25,35 +25,27 @@ type AliyunNLBDeployerConfig struct { // 阿里云地域。 Region string `json:"region"` // 部署资源类型。 - ResourceType DeployResourceType `json:"resourceType"` + ResourceType ResourceType `json:"resourceType"` // 负载均衡实例 ID。 - // 部署资源类型为 [DEPLOY_RESOURCE_LOADBALANCER] 时必填。 + // 部署资源类型为 [RESOURCE_TYPE_LOADBALANCER] 时必填。 LoadbalancerId string `json:"loadbalancerId,omitempty"` // 负载均衡监听 ID。 - // 部署资源类型为 [DEPLOY_RESOURCE_LISTENER] 时必填。 + // 部署资源类型为 [RESOURCE_TYPE_LISTENER] 时必填。 ListenerId string `json:"listenerId,omitempty"` } -type AliyunNLBDeployer struct { - config *AliyunNLBDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *aliyunNlb.Client sslUploader uploader.Uploader } -var _ deployer.Deployer = (*AliyunNLBDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *AliyunNLBDeployerConfig) (*AliyunNLBDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *AliyunNLBDeployerConfig, logger logger.Logger) (*AliyunNLBDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region) @@ -66,15 +58,20 @@ func NewWithLogger(config *AliyunNLBDeployerConfig, logger logger.Logger) (*Aliy return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &AliyunNLBDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *AliyunNLBDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // 上传证书到 CAS upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { @@ -85,12 +82,12 @@ func (d *AliyunNLBDeployer) Deploy(ctx context.Context, certPem string, privkeyP // 根据部署资源类型决定部署方式 switch d.config.ResourceType { - case DEPLOY_RESOURCE_LOADBALANCER: + case RESOURCE_TYPE_LOADBALANCER: if err := d.deployToLoadbalancer(ctx, upres.CertId); err != nil { return nil, err } - case DEPLOY_RESOURCE_LISTENER: + case RESOURCE_TYPE_LISTENER: if err := d.deployToListener(ctx, upres.CertId); err != nil { return nil, err } @@ -102,7 +99,7 @@ func (d *AliyunNLBDeployer) Deploy(ctx context.Context, certPem string, privkeyP return &deployer.DeployResult{}, nil } -func (d *AliyunNLBDeployer) deployToLoadbalancer(ctx context.Context, cloudCertId string) error { +func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId string) error { if d.config.LoadbalancerId == "" { return errors.New("config `loadbalancerId` is required") } @@ -171,7 +168,7 @@ func (d *AliyunNLBDeployer) deployToLoadbalancer(ctx context.Context, cloudCertI return nil } -func (d *AliyunNLBDeployer) deployToListener(ctx context.Context, cloudCertId string) error { +func (d *DeployerProvider) deployToListener(ctx context.Context, cloudCertId string) error { if d.config.ListenerId == "" { return errors.New("config `listenerId` is required") } @@ -184,7 +181,7 @@ func (d *AliyunNLBDeployer) deployToListener(ctx context.Context, cloudCertId st return nil } -func (d *AliyunNLBDeployer) updateListenerCertificate(ctx context.Context, cloudListenerId string, cloudCertId string) error { +func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudListenerId string, cloudCertId string) error { // 查询监听的属性 // REF: https://help.aliyun.com/zh/slb/network-load-balancer/developer-reference/api-nlb-2022-04-30-getlistenerattribute getListenerAttributeReq := &aliyunNlb.GetListenerAttributeRequest{ @@ -248,7 +245,7 @@ func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Up } } - uploader, err := uploaderp.New(&uploaderp.AliyunCASUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ AccessKeyId: accessKeyId, AccessKeySecret: accessKeySecret, Region: casRegion, diff --git a/internal/pkg/core/deployer/providers/aliyun-nlb/aliyun_nlb_test.go b/internal/pkg/core/deployer/providers/aliyun-nlb/aliyun_nlb_test.go index 45abd932..dfaf0916 100644 --- a/internal/pkg/core/deployer/providers/aliyun-nlb/aliyun_nlb_test.go +++ b/internal/pkg/core/deployer/providers/aliyun-nlb/aliyun_nlb_test.go @@ -59,11 +59,11 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("LOADBALANCERID: %v", fLoadbalancerId), }, "\n")) - deployer, err := provider.New(&provider.AliyunNLBDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKeyId: fAccessKeyId, AccessKeySecret: fAccessKeySecret, Region: fRegion, - ResourceType: provider.DEPLOY_RESOURCE_LOADBALANCER, + ResourceType: provider.RESOURCE_TYPE_LOADBALANCER, LoadbalancerId: fLoadbalancerId, }) if err != nil { @@ -94,11 +94,11 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("LISTENERID: %v", fListenerId), }, "\n")) - deployer, err := provider.New(&provider.AliyunNLBDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKeyId: fAccessKeyId, AccessKeySecret: fAccessKeySecret, Region: fRegion, - ResourceType: provider.DEPLOY_RESOURCE_LISTENER, + ResourceType: provider.RESOURCE_TYPE_LISTENER, ListenerId: fListenerId, }) if err != nil { diff --git a/internal/pkg/core/deployer/providers/aliyun-nlb/consts.go b/internal/pkg/core/deployer/providers/aliyun-nlb/consts.go new file mode 100644 index 00000000..1fa071df --- /dev/null +++ b/internal/pkg/core/deployer/providers/aliyun-nlb/consts.go @@ -0,0 +1,10 @@ +package aliyunnlb + +type ResourceType string + +const ( + // 资源类型:部署到指定负载均衡器。 + RESOURCE_TYPE_LOADBALANCER = ResourceType("loadbalancer") + // 资源类型:部署到指定监听器。 + RESOURCE_TYPE_LISTENER = ResourceType("listener") +) diff --git a/internal/pkg/core/deployer/providers/aliyun-nlb/defines.go b/internal/pkg/core/deployer/providers/aliyun-nlb/defines.go deleted file mode 100644 index 14e3c2b2..00000000 --- a/internal/pkg/core/deployer/providers/aliyun-nlb/defines.go +++ /dev/null @@ -1,10 +0,0 @@ -package aliyunnlb - -type DeployResourceType string - -const ( - // 资源类型:部署到指定负载均衡器。 - DEPLOY_RESOURCE_LOADBALANCER = DeployResourceType("loadbalancer") - // 资源类型:部署到指定监听器。 - DEPLOY_RESOURCE_LISTENER = DeployResourceType("listener") -) diff --git a/internal/pkg/core/deployer/providers/aliyun-oss/aliyun_oss.go b/internal/pkg/core/deployer/providers/aliyun-oss/aliyun_oss.go index 9caf0a3b..88adbf0b 100644 --- a/internal/pkg/core/deployer/providers/aliyun-oss/aliyun_oss.go +++ b/internal/pkg/core/deployer/providers/aliyun-oss/aliyun_oss.go @@ -12,7 +12,7 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/logger" ) -type AliyunOSSDeployerConfig struct { +type DeployerConfig struct { // 阿里云 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 阿里云 AccessKeySecret。 @@ -25,25 +25,17 @@ type AliyunOSSDeployerConfig struct { Domain string `json:"domain"` } -type AliyunOSSDeployer struct { - config *AliyunOSSDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *oss.Client } -var _ deployer.Deployer = (*AliyunOSSDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *AliyunOSSDeployerConfig) (*AliyunOSSDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *AliyunOSSDeployerConfig, logger logger.Logger) (*AliyunOSSDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region) @@ -51,14 +43,19 @@ func NewWithLogger(config *AliyunOSSDeployerConfig, logger logger.Logger) (*Aliy return nil, xerrors.Wrap(err, "failed to create sdk client") } - return &AliyunOSSDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, }, nil } -func (d *AliyunOSSDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { if d.config.Bucket == "" { return nil, errors.New("config `bucket` is required") } diff --git a/internal/pkg/core/deployer/providers/aliyun-oss/aliyun_oss_test.go b/internal/pkg/core/deployer/providers/aliyun-oss/aliyun_oss_test.go index e25f8156..7613a003 100644 --- a/internal/pkg/core/deployer/providers/aliyun-oss/aliyun_oss_test.go +++ b/internal/pkg/core/deployer/providers/aliyun-oss/aliyun_oss_test.go @@ -60,7 +60,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) - deployer, err := provider.New(&provider.AliyunOSSDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKeyId: fAccessKeyId, AccessKeySecret: fAccessKeySecret, Region: fRegion, diff --git a/internal/pkg/core/deployer/providers/aliyun-vod/aliyun_vod.go b/internal/pkg/core/deployer/providers/aliyun-vod/aliyun_vod.go new file mode 100644 index 00000000..740fbb56 --- /dev/null +++ b/internal/pkg/core/deployer/providers/aliyun-vod/aliyun_vod.go @@ -0,0 +1,95 @@ +package aliyunvod + +import ( + "context" + "fmt" + "time" + + aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client" + "github.com/alibabacloud-go/tea/tea" + aliyunVod "github.com/alibabacloud-go/vod-20170321/v4/client" + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/logger" +) + +type DeployerConfig struct { + // 阿里云 AccessKeyId。 + AccessKeyId string `json:"accessKeyId"` + // 阿里云 AccessKeySecret。 + AccessKeySecret string `json:"accessKeySecret"` + // 阿里云地域。 + Region string `json:"region"` + // 点播加速域名(不支持泛域名)。 + Domain string `json:"domain"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger logger.Logger + sdkClient *aliyunVod.Client +} + +var _ deployer.Deployer = (*DeployerProvider)(nil) + +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { + if config == nil { + panic("config is nil") + } + + client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + return &DeployerProvider{ + config: config, + logger: logger.NewNilLogger(), + sdkClient: client, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { + // 设置域名证书 + // REF: https://help.aliyun.com/zh/vod/developer-reference/api-vod-2017-03-21-setvoddomainsslcertificate + setVodDomainSSLCertificateReq := &aliyunVod.SetVodDomainSSLCertificateRequest{ + DomainName: tea.String(d.config.Domain), + CertName: tea.String(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())), + CertType: tea.String("upload"), + SSLProtocol: tea.String("on"), + SSLPub: tea.String(certPem), + SSLPri: tea.String(privkeyPem), + } + setVodDomainSSLCertificateResp, err := d.sdkClient.SetVodDomainSSLCertificate(setVodDomainSSLCertificateReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'live.SetVodDomainSSLCertificate'") + } else { + d.logger.Logt("已设置域名证书", setVodDomainSSLCertificateResp) + } + + return &deployer.DeployResult{}, nil +} + +func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunVod.Client, error) { + // 接入点一览 https://help.aliyun.com/zh/vod/developer-reference/api-vod-2017-03-21-endpoint + endpoint := fmt.Sprintf("vod.%s.aliyuncs.com", region) + + config := &aliyunOpen.Config{ + AccessKeyId: tea.String(accessKeyId), + AccessKeySecret: tea.String(accessKeySecret), + Endpoint: tea.String(endpoint), + } + + client, err := aliyunVod.NewClient(config) + if err != nil { + return nil, err + } + + return client, nil +} diff --git a/internal/pkg/core/deployer/providers/aliyun-vod/aliyun_vod_test.go b/internal/pkg/core/deployer/providers/aliyun-vod/aliyun_vod_test.go new file mode 100644 index 00000000..552ddc0f --- /dev/null +++ b/internal/pkg/core/deployer/providers/aliyun-vod/aliyun_vod_test.go @@ -0,0 +1,80 @@ +package aliyunvod_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-vod" +) + +var ( + fInputCertPath string + fInputKeyPath string + fAccessKeyId string + fAccessKeySecret string + fRegion string + fDomain string +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_ALIYUNVOD_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "") + flag.StringVar(&fAccessKeySecret, argsPrefix+"ACCESSKEYSECRET", "", "") + flag.StringVar(&fRegion, argsPrefix+"REGION", "", "") + flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "") +} + +/* +Shell command to run this test: + + go test -v ./aliyun_vod_test.go -args \ + --CERTIMATE_DEPLOYER_ALIYUNVOD_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_ALIYUNVOD_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_ALIYUNVOD_ACCESSKEYID="your-access-key-id" \ + --CERTIMATE_DEPLOYER_ALIYUNVOD_ACCESSKEYSECRET="your-access-key-secret" \ + --CERTIMATE_DEPLOYER_ALIYUNVOD_REGION="cn-hangzhou" \ + --CERTIMATE_DEPLOYER_ALIYUNVOD_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("ACCESSKEYSECRET: %v", fAccessKeySecret), + fmt.Sprintf("REGION: %v", fRegion), + fmt.Sprintf("DOMAIN: %v", fDomain), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + AccessKeyId: fAccessKeyId, + AccessKeySecret: fAccessKeySecret, + Region: fRegion, + 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) + }) +} diff --git a/internal/pkg/core/deployer/providers/aliyun-waf/aliyun_waf.go b/internal/pkg/core/deployer/providers/aliyun-waf/aliyun_waf.go index 1cc7aecd..5747d23e 100644 --- a/internal/pkg/core/deployer/providers/aliyun-waf/aliyun_waf.go +++ b/internal/pkg/core/deployer/providers/aliyun-waf/aliyun_waf.go @@ -14,10 +14,10 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aliyun-cas" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aliyun-cas" ) -type AliyunWAFDeployerConfig struct { +type DeployerConfig struct { // 阿里云 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 阿里云 AccessKeySecret。 @@ -28,26 +28,18 @@ type AliyunWAFDeployerConfig struct { InstanceId string `json:"instanceId"` } -type AliyunWAFDeployer struct { - config *AliyunWAFDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *aliyunWaf.Client sslUploader uploader.Uploader } -var _ deployer.Deployer = (*AliyunWAFDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *AliyunWAFDeployerConfig) (*AliyunWAFDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *AliyunWAFDeployerConfig, logger logger.Logger) (*AliyunWAFDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region) @@ -60,15 +52,20 @@ func NewWithLogger(config *AliyunWAFDeployerConfig, logger logger.Logger) (*Aliy return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &AliyunWAFDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *AliyunWAFDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { if d.config.InstanceId == "" { return nil, errors.New("config `instanceId` is required") } @@ -142,7 +139,7 @@ func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Up } } - uploader, err := uploaderp.New(&uploaderp.AliyunCASUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ AccessKeyId: accessKeyId, AccessKeySecret: accessKeySecret, Region: casRegion, diff --git a/internal/pkg/core/deployer/providers/aliyun-waf/aliyun_waf_test.go b/internal/pkg/core/deployer/providers/aliyun-waf/aliyun_waf_test.go index 2498beca..06a76c63 100644 --- a/internal/pkg/core/deployer/providers/aliyun-waf/aliyun_waf_test.go +++ b/internal/pkg/core/deployer/providers/aliyun-waf/aliyun_waf_test.go @@ -56,7 +56,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("INSTANCEID: %v", fInstanceId), }, "\n")) - deployer, err := provider.New(&provider.AliyunWAFDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKeyId: fAccessKeyId, AccessKeySecret: fAccessKeySecret, Region: fRegion, diff --git a/internal/pkg/core/deployer/providers/aws-cloudfront/aws_cloudfront.go b/internal/pkg/core/deployer/providers/aws-cloudfront/aws_cloudfront.go index 086dd415..2e8e09ee 100644 --- a/internal/pkg/core/deployer/providers/aws-cloudfront/aws_cloudfront.go +++ b/internal/pkg/core/deployer/providers/aws-cloudfront/aws_cloudfront.go @@ -14,10 +14,10 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aws-acm" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aws-acm" ) -type AWSCloudFrontDeployerConfig struct { +type DeployerConfig struct { // AWS AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // AWS SecretAccessKey。 @@ -28,26 +28,18 @@ type AWSCloudFrontDeployerConfig struct { DistributionId string `json:"distributionId"` } -type AWSCloudFrontDeployer struct { - config *AWSCloudFrontDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *awsCf.Client sslUploader uploader.Uploader } -var _ deployer.Deployer = (*AWSCloudFrontDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *AWSCloudFrontDeployerConfig) (*AWSCloudFrontDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *AWSCloudFrontDeployerConfig, logger logger.Logger) (*AWSCloudFrontDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client, err := createSdkClient(config.AccessKeyId, config.SecretAccessKey, config.Region) @@ -55,7 +47,7 @@ func NewWithLogger(config *AWSCloudFrontDeployerConfig, logger logger.Logger) (* return nil, xerrors.Wrap(err, "failed to create sdk client") } - uploader, err := uploaderp.New(&uploaderp.AWSCertificateManagerUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ AccessKeyId: config.AccessKeyId, SecretAccessKey: config.SecretAccessKey, Region: config.Region, @@ -64,15 +56,20 @@ func NewWithLogger(config *AWSCloudFrontDeployerConfig, logger logger.Logger) (* return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &AWSCloudFrontDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *AWSCloudFrontDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { if d.config.DistributionId == "" { return nil, errors.New("config `distribuitionId` is required") } diff --git a/internal/pkg/core/deployer/providers/aws-cloudfront/aws_cloudfront_test.go b/internal/pkg/core/deployer/providers/aws-cloudfront/aws_cloudfront_test.go index 89997b37..5b4c75db 100644 --- a/internal/pkg/core/deployer/providers/aws-cloudfront/aws_cloudfront_test.go +++ b/internal/pkg/core/deployer/providers/aws-cloudfront/aws_cloudfront_test.go @@ -56,11 +56,11 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DISTRIBUTIONID: %v", fDistribuitionId), }, "\n")) - deployer, err := provider.New(&provider.AWSCloudFrontDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKeyId: fAccessKeyId, SecretAccessKey: fSecretAccessKey, Region: fRegion, - DistribuitionId: fDistribuitionId, + DistributionId: fDistribuitionId, }) if err != nil { t.Errorf("err: %+v", err) diff --git a/internal/pkg/core/deployer/providers/baiducloud-cdn/baiducloud_cdn.go b/internal/pkg/core/deployer/providers/baiducloud-cdn/baiducloud_cdn.go index ab932b42..df57ea1d 100644 --- a/internal/pkg/core/deployer/providers/baiducloud-cdn/baiducloud_cdn.go +++ b/internal/pkg/core/deployer/providers/baiducloud-cdn/baiducloud_cdn.go @@ -2,7 +2,6 @@ import ( "context" - "errors" "fmt" "time" @@ -14,7 +13,7 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/logger" ) -type BaiduCloudCDNDeployerConfig struct { +type DeployerConfig struct { // 百度智能云 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 百度智能云 SecretAccessKey。 @@ -23,25 +22,17 @@ type BaiduCloudCDNDeployerConfig struct { Domain string `json:"domain"` } -type BaiduCloudCDNDeployer struct { - config *BaiduCloudCDNDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *bceCdn.Client } -var _ deployer.Deployer = (*BaiduCloudCDNDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *BaiduCloudCDNDeployerConfig) (*BaiduCloudCDNDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *BaiduCloudCDNDeployerConfig, logger logger.Logger) (*BaiduCloudCDNDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client, err := createSdkClient(config.AccessKeyId, config.SecretAccessKey) @@ -49,14 +40,19 @@ func NewWithLogger(config *BaiduCloudCDNDeployerConfig, logger logger.Logger) (* return nil, xerrors.Wrap(err, "failed to create sdk client") } - return &BaiduCloudCDNDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, }, nil } -func (d *BaiduCloudCDNDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // 修改域名证书 // REF: https://cloud.baidu.com/doc/CDN/s/qjzuz2hp8 putCertResp, err := d.sdkClient.PutCert( diff --git a/internal/pkg/core/deployer/providers/baiducloud-cdn/baiducloud_cdn_test.go b/internal/pkg/core/deployer/providers/baiducloud-cdn/baiducloud_cdn_test.go index 817600b6..ecb9a9d4 100644 --- a/internal/pkg/core/deployer/providers/baiducloud-cdn/baiducloud_cdn_test.go +++ b/internal/pkg/core/deployer/providers/baiducloud-cdn/baiducloud_cdn_test.go @@ -52,7 +52,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) - deployer, err := provider.New(&provider.BaiduCloudCDNDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKeyId: fAccessKeyId, SecretAccessKey: fSecretAccessKey, Domain: fDomain, diff --git a/internal/pkg/core/deployer/providers/baishan-cdn/baishan_cdn.go b/internal/pkg/core/deployer/providers/baishan-cdn/baishan_cdn.go new file mode 100644 index 00000000..efb3353e --- /dev/null +++ b/internal/pkg/core/deployer/providers/baishan-cdn/baishan_cdn.go @@ -0,0 +1,117 @@ +package baishancdn + +import ( + "context" + "errors" + "fmt" + "time" + + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/logger" + bssdk "github.com/usual2970/certimate/internal/pkg/vendors/baishan-sdk" +) + +type DeployerConfig struct { + // 白山云 API Token。 + ApiToken string `json:"apiToken"` + // 加速域名(支持泛域名)。 + Domain string `json:"domain"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger logger.Logger + sdkClient *bssdk.Client +} + +var _ deployer.Deployer = (*DeployerProvider)(nil) + +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { + if config == nil { + panic("config is nil") + } + + client, err := createSdkClient(config.ApiToken) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + return &DeployerProvider{ + config: config, + logger: logger.NewNilLogger(), + sdkClient: client, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + 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") + } + + // 查询域名配置 + // REF: https://portal.baishancloud.com/track/document/api/1/1065 + getDomainConfigReq := &bssdk.GetDomainConfigRequest{ + Domains: d.config.Domain, + Config: "https", + } + getDomainConfigResp, err := d.sdkClient.GetDomainConfig(getDomainConfigReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'baishan.GetDomainConfig'") + } else if len(getDomainConfigResp.Data) == 0 { + return nil, errors.New("domain config not found") + } else { + d.logger.Logt("已查询到域名配置", getDomainConfigResp) + } + + // 新增证书 + // REF: https://portal.baishancloud.com/track/document/downloadPdf/1441 + createCertificateReq := &bssdk.CreateCertificateRequest{ + Certificate: certPem, + Key: privkeyPem, + Name: fmt.Sprintf("certimate_%d", time.Now().UnixMilli()), + } + createCertificateResp, err := d.sdkClient.CreateCertificate(createCertificateReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'baishan.CreateCertificate'") + } else { + d.logger.Logt("已新增证书", createCertificateResp) + } + + // 设置域名配置 + // REF: https://portal.baishancloud.com/track/document/api/1/1045 + setDomainConfigReq := &bssdk.SetDomainConfigRequest{ + Domains: d.config.Domain, + Config: &bssdk.DomainConfig{ + Https: &bssdk.DomainConfigHttps{ + CertId: createCertificateResp.Data.CertId, + ForceHttps: getDomainConfigResp.Data[0].Config.Https.ForceHttps, + EnableHttp2: getDomainConfigResp.Data[0].Config.Https.EnableHttp2, + EnableOcsp: getDomainConfigResp.Data[0].Config.Https.EnableOcsp, + }, + }, + } + setDomainConfigResp, err := d.sdkClient.SetDomainConfig(setDomainConfigReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'baishan.SetDomainConfig'") + } else { + d.logger.Logt("已设置域名配置", setDomainConfigResp) + } + + return &deployer.DeployResult{}, nil +} + +func createSdkClient(apiToken string) (*bssdk.Client, error) { + if apiToken == "" { + return nil, errors.New("invalid baishan api token") + } + + client := bssdk.NewClient(apiToken) + return client, nil +} diff --git a/internal/pkg/core/deployer/providers/baishan-cdn/baishan_cdn_test.go b/internal/pkg/core/deployer/providers/baishan-cdn/baishan_cdn_test.go new file mode 100644 index 00000000..5534a232 --- /dev/null +++ b/internal/pkg/core/deployer/providers/baishan-cdn/baishan_cdn_test.go @@ -0,0 +1,70 @@ +package baishancdn_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baishan-cdn" +) + +var ( + fInputCertPath string + fInputKeyPath string + fApiToken string + fDomain string +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_BAISHANCDN_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fApiToken, argsPrefix+"APITOKEN", "", "") + flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "") +} + +/* +Shell command to run this test: + + go test -v ./baishan_cdn_test.go -args \ + --CERTIMATE_DEPLOYER_BAISHANCDN_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_BAISHANCDN_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_BAISHANCDN_APITOKEN="your-api-token" \ + --CERTIMATE_DEPLOYER_BAISHANCDN_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("APITOKEN: %v", fApiToken), + fmt.Sprintf("DOMAIN: %v", fDomain), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + ApiToken: fApiToken, + 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) + }) +} diff --git a/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console.go b/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console.go new file mode 100644 index 00000000..6343acf7 --- /dev/null +++ b/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console.go @@ -0,0 +1,93 @@ +package baotapanelconsole + +import ( + "context" + "errors" + "net/url" + + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/logger" + btsdk "github.com/usual2970/certimate/internal/pkg/vendors/btpanel-sdk" +) + +type DeployerConfig struct { + // 宝塔面板地址。 + ApiUrl string `json:"apiUrl"` + // 宝塔面板接口密钥。 + ApiKey string `json:"apiKey"` + // 是否自动重启。 + AutoRestart bool `json:"autoRestart"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger logger.Logger + sdkClient *btsdk.Client +} + +var _ deployer.Deployer = (*DeployerProvider)(nil) + +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { + if config == nil { + panic("config is nil") + } + + client, err := createSdkClient(config.ApiUrl, config.ApiKey) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + return &DeployerProvider{ + config: config, + logger: logger.NewNilLogger(), + sdkClient: client, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { + // 设置面板 SSL 证书 + configSavePanelSSLReq := &btsdk.ConfigSavePanelSSLRequest{ + PrivateKey: privkeyPem, + Certificate: certPem, + } + configSavePanelSSLResp, err := d.sdkClient.ConfigSavePanelSSL(configSavePanelSSLReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'bt.ConfigSavePanelSSL'") + } else { + d.logger.Logt("已设置面板 SSL 证书", configSavePanelSSLResp) + } + + if d.config.AutoRestart { + // 重启面板 + systemServiceAdminReq := &btsdk.SystemServiceAdminRequest{ + Name: "nginx", + Type: "restart", + } + _, err := d.sdkClient.SystemServiceAdmin(systemServiceAdminReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'bt.SystemServiceAdmin'") + } + } + + return &deployer.DeployResult{}, nil +} + +func createSdkClient(apiUrl, apiKey string) (*btsdk.Client, error) { + if _, err := url.Parse(apiUrl); err != nil { + return nil, errors.New("invalid baota api url") + } + + if apiKey == "" { + return nil, errors.New("invalid baota api key") + } + + client := btsdk.NewClient(apiUrl, apiKey) + return client, nil +} diff --git a/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console_test.go b/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console_test.go new file mode 100644 index 00000000..06a2f096 --- /dev/null +++ b/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console_test.go @@ -0,0 +1,70 @@ +package baotapanelconsole_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/baotapanel-console" +) + +var ( + fInputCertPath string + fInputKeyPath string + fApiUrl string + fApiKey string +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_BAOTAPANELCONSOLE_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "") + flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "") +} + +/* +Shell command to run this test: + + go test -v ./baotapanel_console_test.go -args \ + --CERTIMATE_DEPLOYER_BAOTAPANELCONSOLE_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_BAOTAPANELCONSOLE_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_BAOTAPANELCONSOLE_APIURL="http://127.0.0.1:8888" \ + --CERTIMATE_DEPLOYER_BAOTAPANELCONSOLE_APIKEY="your-api-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("APIURL: %v", fApiUrl), + fmt.Sprintf("APIKEY: %v", fApiKey), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + ApiUrl: fApiUrl, + ApiKey: fApiKey, + }) + 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) + }) +} diff --git a/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site.go b/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site.go index 336e2a5d..62cef9de 100644 --- a/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site.go +++ b/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site.go @@ -3,42 +3,41 @@ import ( "context" "errors" + "fmt" + "net/url" xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" + "github.com/usual2970/certimate/internal/pkg/utils/slices" btsdk "github.com/usual2970/certimate/internal/pkg/vendors/btpanel-sdk" ) -type BaotaPanelSiteDeployerConfig struct { +type DeployerConfig struct { // 宝塔面板地址。 ApiUrl string `json:"apiUrl"` // 宝塔面板接口密钥。 ApiKey string `json:"apiKey"` - // 站点名称 - SiteName string `json:"siteName"` + // 站点类型。 + SiteType string `json:"siteType"` + // 站点名称(单个)。 + SiteName string `json:"siteName,omitempty"` + // 站点名称(多个)。 + SiteNames []string `json:"siteNames,omitempty"` } -type BaotaPanelSiteDeployer struct { - config *BaotaPanelSiteDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger - sdkClient *btsdk.BaoTaPanelClient + sdkClient *btsdk.Client } -var _ deployer.Deployer = (*BaotaPanelSiteDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *BaotaPanelSiteDeployerConfig) (*BaotaPanelSiteDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *BaotaPanelSiteDeployerConfig, logger logger.Logger) (*BaotaPanelSiteDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client, err := createSdkClient(config.ApiUrl, config.ApiKey) @@ -46,36 +45,92 @@ func NewWithLogger(config *BaotaPanelSiteDeployerConfig, logger logger.Logger) ( return nil, xerrors.Wrap(err, "failed to create sdk client") } - return &BaotaPanelSiteDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, }, nil } -func (d *BaotaPanelSiteDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { - if d.config.SiteName == "" { - return nil, errors.New("config `siteName` is required") - } +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} - // 设置站点 SSL 证书 - setSiteSSLReq := &btsdk.SetSiteSSLRequest{ - SiteName: d.config.SiteName, - Type: "1", - Key: privkeyPem, - Csr: certPem, - } - setSiteSSLResp, err := d.sdkClient.SetSiteSSL(setSiteSSLReq) - if err != nil { - return nil, xerrors.Wrap(err, "failed to execute sdk request 'bt.SetSiteSSL'") - } +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { + switch d.config.SiteType { + case "php": + { + if d.config.SiteName == "" { + return nil, errors.New("config `siteName` is required") + } - d.logger.Logt("已设置站点 SSL 证书", setSiteSSLResp) + // 设置站点 SSL 证书 + siteSetSSLReq := &btsdk.SiteSetSSLRequest{ + SiteName: d.config.SiteName, + Type: "0", + Certificate: certPem, + PrivateKey: privkeyPem, + } + siteSetSSLResp, err := d.sdkClient.SiteSetSSL(siteSetSSLReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'bt.SiteSetSSL'") + } else { + d.logger.Logt("已设置站点证书", siteSetSSLResp) + } + } + + case "other": + { + if len(d.config.SiteNames) == 0 { + return nil, errors.New("config `siteNames` is required") + } + + // 上传证书 + sslCertSaveCertReq := &btsdk.SSLCertSaveCertRequest{ + Certificate: certPem, + PrivateKey: privkeyPem, + } + sslCertSaveCertResp, err := d.sdkClient.SSLCertSaveCert(sslCertSaveCertReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'bt.SSLCertSaveCert'") + } else { + d.logger.Logt("已上传证书", sslCertSaveCertResp) + } + + // 设置站点证书 + sslSetBatchCertToSiteReq := &btsdk.SSLSetBatchCertToSiteRequest{ + BatchInfo: slices.Map(d.config.SiteNames, func(siteName string) *btsdk.SSLSetBatchCertToSiteRequestBatchInfo { + return &btsdk.SSLSetBatchCertToSiteRequestBatchInfo{ + SiteName: siteName, + SSLHash: sslCertSaveCertResp.SSLHash, + } + }), + } + sslSetBatchCertToSiteResp, err := d.sdkClient.SSLSetBatchCertToSite(sslSetBatchCertToSiteReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'bt.SSLSetBatchCertToSite'") + } else { + d.logger.Logt("已设置站点证书", sslSetBatchCertToSiteResp) + } + } + + default: + return nil, fmt.Errorf("unsupported site type: %s", d.config.SiteType) + } return &deployer.DeployResult{}, nil } -func createSdkClient(apiUrl, apiKey string) (*btsdk.BaoTaPanelClient, error) { - client := btsdk.NewBaoTaPanelClient(apiUrl, apiKey) +func createSdkClient(apiUrl, apiKey string) (*btsdk.Client, error) { + if _, err := url.Parse(apiUrl); err != nil { + return nil, errors.New("invalid baota api url") + } + + if apiKey == "" { + return nil, errors.New("invalid baota api key") + } + + client := btsdk.NewClient(apiUrl, apiKey) return client, nil } diff --git a/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site_test.go b/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site_test.go index 486e8428..4c31b021 100644 --- a/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site_test.go +++ b/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site_test.go @@ -16,6 +16,7 @@ var ( fInputKeyPath string fApiUrl string fApiKey string + fSiteType string fSiteName string ) @@ -26,6 +27,7 @@ func init() { flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "") flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "") + flag.StringVar(&fSiteType, argsPrefix+"SITETYPE", "", "") flag.StringVar(&fSiteName, argsPrefix+"SITENAME", "", "") } @@ -35,9 +37,10 @@ Shell command to run this test: go test -v ./baotapanel_site_test.go -args \ --CERTIMATE_DEPLOYER_BAOTAPANELSITE_INPUTCERTPATH="/path/to/your-input-cert.pem" \ --CERTIMATE_DEPLOYER_BAOTAPANELSITE_INPUTKEYPATH="/path/to/your-input-key.pem" \ - --CERTIMATE_DEPLOYER_BAOTAPANELSITE_APIURL="your-baota-panel-url" \ - --CERTIMATE_DEPLOYER_BAOTAPANELSITE_APIKEY="your-baota-panel-key" \ - --CERTIMATE_DEPLOYER_BAOTAPANELSITE_SITENAME="your-baota-site-name" + --CERTIMATE_DEPLOYER_BAOTAPANELSITE_APIURL="http://127.0.0.1:8888" \ + --CERTIMATE_DEPLOYER_BAOTAPANELSITE_APIKEY="your-api-key" \ + --CERTIMATE_DEPLOYER_BAOTAPANELSITE_SITETYPE="php" \ + --CERTIMATE_DEPLOYER_BAOTAPANELSITE_SITENAME="your-site-name" */ func TestDeploy(t *testing.T) { flag.Parse() @@ -49,13 +52,16 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath), fmt.Sprintf("APIURL: %v", fApiUrl), fmt.Sprintf("APIKEY: %v", fApiKey), + fmt.Sprintf("SITETYPE: %v", fSiteType), fmt.Sprintf("SITENAME: %v", fSiteName), }, "\n")) - deployer, err := provider.New(&provider.BaotaPanelSiteDeployerConfig{ - ApiUrl: fApiUrl, - ApiKey: fApiKey, - SiteName: fSiteName, + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + ApiUrl: fApiUrl, + ApiKey: fApiKey, + SiteType: fSiteType, + SiteName: fSiteName, + SiteNames: []string{fSiteName}, }) if err != nil { t.Errorf("err: %+v", err) diff --git a/internal/pkg/core/deployer/providers/byteplus-cdn/byteplus_cdn.go b/internal/pkg/core/deployer/providers/byteplus-cdn/byteplus_cdn.go index 2a695513..909a2e7d 100644 --- a/internal/pkg/core/deployer/providers/byteplus-cdn/byteplus_cdn.go +++ b/internal/pkg/core/deployer/providers/byteplus-cdn/byteplus_cdn.go @@ -12,10 +12,10 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/byteplus-cdn" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/byteplus-cdn" ) -type BytePlusCDNDeployerConfig struct { +type DeployerConfig struct { // BytePlus AccessKey。 AccessKey string `json:"accessKey"` // BytePlus SecretKey。 @@ -24,33 +24,25 @@ type BytePlusCDNDeployerConfig struct { Domain string `json:"domain"` } -type BytePlusCDNDeployer struct { - config *BytePlusCDNDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *bpCdn.CDN sslUploader uploader.Uploader } -var _ deployer.Deployer = (*BytePlusCDNDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *BytePlusCDNDeployerConfig) (*BytePlusCDNDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *BytePlusCDNDeployerConfig, logger logger.Logger) (*BytePlusCDNDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client := bpCdn.NewInstance() client.Client.SetAccessKey(config.AccessKey) client.Client.SetSecretKey(config.SecretKey) - uploader, err := uploaderp.New(&uploaderp.ByteplusCDNUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ AccessKey: config.AccessKey, SecretKey: config.SecretKey, }) @@ -58,15 +50,20 @@ func NewWithLogger(config *BytePlusCDNDeployerConfig, logger logger.Logger) (*By return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &BytePlusCDNDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *BytePlusCDNDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // 上传证书到 CDN upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { diff --git a/internal/pkg/core/deployer/providers/byteplus-cdn/byteplus_cdn_test.go b/internal/pkg/core/deployer/providers/byteplus-cdn/byteplus_cdn_test.go index 9de97be6..ee09e8ee 100644 --- a/internal/pkg/core/deployer/providers/byteplus-cdn/byteplus_cdn_test.go +++ b/internal/pkg/core/deployer/providers/byteplus-cdn/byteplus_cdn_test.go @@ -52,7 +52,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) - deployer, err := provider.New(&provider.BytePlusCDNDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKey: fAccessKey, SecretKey: fSecretKey, Domain: fDomain, diff --git a/internal/pkg/core/deployer/providers/cachefly/cachefly.go b/internal/pkg/core/deployer/providers/cachefly/cachefly.go new file mode 100644 index 00000000..8c6f129d --- /dev/null +++ b/internal/pkg/core/deployer/providers/cachefly/cachefly.go @@ -0,0 +1,72 @@ +package cachefly + +import ( + "context" + "errors" + + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/logger" + cfsdk "github.com/usual2970/certimate/internal/pkg/vendors/cachefly-sdk" +) + +type DeployerConfig struct { + // CacheFly API Token。 + ApiToken string `json:"apiToken"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger logger.Logger + sdkClient *cfsdk.Client +} + +var _ deployer.Deployer = (*DeployerProvider)(nil) + +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { + if config == nil { + panic("config is nil") + } + + client, err := createSdkClient(config.ApiToken) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + return &DeployerProvider{ + config: config, + logger: logger.NewNilLogger(), + sdkClient: client, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { + // 上传证书 + createCertificateReq := &cfsdk.CreateCertificateRequest{ + Certificate: certPem, + CertificateKey: privkeyPem, + } + createCertificateResp, err := d.sdkClient.CreateCertificate(createCertificateReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'cachefly.CreateCertificate'") + } else { + d.logger.Logt("已上传证书", createCertificateResp) + } + + return &deployer.DeployResult{}, nil +} + +func createSdkClient(apiToken string) (*cfsdk.Client, error) { + if apiToken == "" { + return nil, errors.New("invalid cachefly api token") + } + + client := cfsdk.NewClient(apiToken) + return client, nil +} diff --git a/internal/pkg/core/deployer/providers/cachefly/cachefly_test.go b/internal/pkg/core/deployer/providers/cachefly/cachefly_test.go new file mode 100644 index 00000000..1de6047e --- /dev/null +++ b/internal/pkg/core/deployer/providers/cachefly/cachefly_test.go @@ -0,0 +1,65 @@ +package cachefly_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/cachefly" +) + +var ( + fInputCertPath string + fInputKeyPath string + fApiToken string +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_CACHEFLY_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fApiToken, argsPrefix+"APITOKEN", "", "") +} + +/* +Shell command to run this test: + + go test -v ./cachefly_test.go -args \ + --CERTIMATE_DEPLOYER_CACHEFLY_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_CACHEFLY_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_CACHEFLY_APITOKEN="your-api-token" +*/ +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("APITOKEN: %v", fApiToken), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + ApiToken: fApiToken, + }) + 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) + }) +} diff --git a/internal/pkg/core/deployer/providers/cdnfly/cdnfly.go b/internal/pkg/core/deployer/providers/cdnfly/cdnfly.go new file mode 100644 index 00000000..c98d9ae4 --- /dev/null +++ b/internal/pkg/core/deployer/providers/cdnfly/cdnfly.go @@ -0,0 +1,177 @@ +package cdnfly + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "net/url" + "time" + + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/logger" + cfsdk "github.com/usual2970/certimate/internal/pkg/vendors/cdnfly-sdk" +) + +type DeployerConfig struct { + // Cdnfly 地址。 + ApiUrl string `json:"apiUrl"` + // Cdnfly 用户端 API Key。 + ApiKey string `json:"apiKey"` + // Cdnfly 用户端 API Secret。 + ApiSecret string `json:"apiSecret"` + // 部署资源类型。 + ResourceType ResourceType `json:"resourceType"` + // 网站 ID。 + // 部署资源类型为 [RESOURCE_TYPE_SITE] 时必填。 + SiteId string `json:"siteId,omitempty"` + // 证书 ID。 + // 部署资源类型为 [RESOURCE_TYPE_CERTIFICATE] 时必填。 + CertificateId string `json:"certificateId,omitempty"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger logger.Logger + sdkClient *cfsdk.Client +} + +var _ deployer.Deployer = (*DeployerProvider)(nil) + +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { + if config == nil { + panic("config is nil") + } + + client, err := createSdkClient(config.ApiUrl, config.ApiKey, config.ApiSecret) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + return &DeployerProvider{ + config: config, + logger: logger.NewNilLogger(), + sdkClient: client, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + 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_SITE: + if err := d.deployToSite(ctx, certPem, privkeyPem); err != nil { + return nil, err + } + + 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) deployToSite(ctx context.Context, certPem string, privkeyPem string) error { + if d.config.SiteId == "" { + return errors.New("config `siteId` is required") + } + + // 获取单个网站详情 + // REF: https://doc.cdnfly.cn/wangzhanguanli-v1-sites.html#%E8%8E%B7%E5%8F%96%E5%8D%95%E4%B8%AA%E7%BD%91%E7%AB%99%E8%AF%A6%E6%83%85 + getSiteReq := &cfsdk.GetSiteRequest{ + Id: d.config.SiteId, + } + getSiteResp, err := d.sdkClient.GetSite(getSiteReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'cdnfly.GetSite'") + } else { + d.logger.Logt("已获取网站详情", getSiteResp) + } + + // 添加单个证书 + // REF: https://doc.cdnfly.cn/wangzhanzhengshu-v1-certs.html#%E6%B7%BB%E5%8A%A0%E5%8D%95%E4%B8%AA%E6%88%96%E5%A4%9A%E4%B8%AA%E8%AF%81%E4%B9%A6-%E5%A4%9A%E4%B8%AA%E8%AF%81%E4%B9%A6%E6%97%B6%E6%95%B0%E6%8D%AE%E6%A0%BC%E5%BC%8F%E4%B8%BA%E6%95%B0%E7%BB%84 + createCertificateReq := &cfsdk.CreateCertificateRequest{ + Name: fmt.Sprintf("certimate-%d", time.Now().UnixMilli()), + Type: "custom", + Cert: certPem, + Key: privkeyPem, + } + createCertificateResp, err := d.sdkClient.CreateCertificate(createCertificateReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'cdnfly.CreateCertificate'") + } else { + d.logger.Logt("已添加证书", createCertificateResp) + } + + // 修改单个网站 + // REF: https://doc.cdnfly.cn/wangzhanguanli-v1-sites.html#%E4%BF%AE%E6%94%B9%E5%8D%95%E4%B8%AA%E7%BD%91%E7%AB%99 + updateSiteHttpsListenMap := make(map[string]any) + _ = json.Unmarshal([]byte(getSiteResp.Data.HttpsListen), &updateSiteHttpsListenMap) + updateSiteHttpsListenMap["cert"] = createCertificateResp.Data + updateSiteHttpsListenData, _ := json.Marshal(updateSiteHttpsListenMap) + updateSiteHttpsListen := string(updateSiteHttpsListenData) + updateSiteReq := &cfsdk.UpdateSiteRequest{ + Id: d.config.SiteId, + HttpsListen: &updateSiteHttpsListen, + } + updateSiteResp, err := d.sdkClient.UpdateSite(updateSiteReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'cdnfly.UpdateSite'") + } else { + d.logger.Logt("已修改网站", updateSiteResp) + } + + return nil +} + +func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPem string, privkeyPem string) error { + if d.config.CertificateId == "" { + return errors.New("config `certificateId` is required") + } + + // 修改单个证书 + // REF: https://doc.cdnfly.cn/wangzhanzhengshu-v1-certs.html#%E4%BF%AE%E6%94%B9%E5%8D%95%E4%B8%AA%E8%AF%81%E4%B9%A6 + updateCertificateType := "custom" + updateCertificateReq := &cfsdk.UpdateCertificateRequest{ + Id: d.config.CertificateId, + Type: &updateCertificateType, + Cert: &certPem, + Key: &privkeyPem, + } + updateCertificateResp, err := d.sdkClient.UpdateCertificate(updateCertificateReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'cdnfly.UpdateCertificate'") + } else { + d.logger.Logt("已修改证书", updateCertificateResp) + } + + return nil +} + +func createSdkClient(apiUrl, apiKey, apiSecret string) (*cfsdk.Client, error) { + if _, err := url.Parse(apiUrl); err != nil { + return nil, errors.New("invalid cachefly api url") + } + + if apiKey == "" { + return nil, errors.New("invalid cachefly api key") + } + + if apiSecret == "" { + return nil, errors.New("invalid cachefly api secret") + } + + client := cfsdk.NewClient(apiUrl, apiKey, apiSecret) + return client, nil +} diff --git a/internal/pkg/core/deployer/providers/cdnfly/cdnfly_test.go b/internal/pkg/core/deployer/providers/cdnfly/cdnfly_test.go new file mode 100644 index 00000000..fd17df9c --- /dev/null +++ b/internal/pkg/core/deployer/providers/cdnfly/cdnfly_test.go @@ -0,0 +1,81 @@ +package cdnfly_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/cdnfly" +) + +var ( + fInputCertPath string + fInputKeyPath string + fApiUrl string + fApiKey string + fApiSecret string + fCertificateId string +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_CDNFLY_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "") + flag.StringVar(&fApiKey, argsPrefix+"APIKEY", "", "") + flag.StringVar(&fApiSecret, argsPrefix+"APISECRET", "", "") + flag.StringVar(&fCertificateId, argsPrefix+"CERTIFICATEID", "", "") +} + +/* +Shell command to run this test: + + go test -v ./cdnfly_test.go -args \ + --CERTIMATE_DEPLOYER_CDNFLY_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_CDNFLY_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_CDNFLY_APIURL="http://127.0.0.1:88" \ + --CERTIMATE_DEPLOYER_CDNFLY_APIKEY="your-api-key" \ + --CERTIMATE_DEPLOYER_CDNFLY_APISECRET="your-api-secret" \ + --CERTIMATE_DEPLOYER_CDNFLY_CERTIFICATEID="your-cert-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("APIURL: %v", fApiUrl), + fmt.Sprintf("APIKEY: %v", fApiKey), + fmt.Sprintf("APISECRET: %v", fApiSecret), + fmt.Sprintf("CERTIFICATEID: %v", fCertificateId), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + ApiUrl: fApiUrl, + ApiKey: fApiKey, + ApiSecret: fApiSecret, + 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) + }) +} diff --git a/internal/pkg/core/deployer/providers/cdnfly/consts.go b/internal/pkg/core/deployer/providers/cdnfly/consts.go new file mode 100644 index 00000000..3f6c6db0 --- /dev/null +++ b/internal/pkg/core/deployer/providers/cdnfly/consts.go @@ -0,0 +1,10 @@ +package cdnfly + +type ResourceType string + +const ( + // 资源类型:替换指定网站的证书。 + RESOURCE_TYPE_SITE = ResourceType("site") + // 资源类型:替换指定证书。 + RESOURCE_TYPE_CERTIFICATE = ResourceType("certificate") +) diff --git a/internal/pkg/core/deployer/providers/dogecloud-cdn/dogecloud_cdn.go b/internal/pkg/core/deployer/providers/dogecloud-cdn/dogecloud_cdn.go index 283d9907..325a5319 100644 --- a/internal/pkg/core/deployer/providers/dogecloud-cdn/dogecloud_cdn.go +++ b/internal/pkg/core/deployer/providers/dogecloud-cdn/dogecloud_cdn.go @@ -2,7 +2,6 @@ import ( "context" - "errors" "strconv" xerrors "github.com/pkg/errors" @@ -10,11 +9,11 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/dogecloud" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/dogecloud" dogesdk "github.com/usual2970/certimate/internal/pkg/vendors/dogecloud-sdk" ) -type DogeCloudCDNDeployerConfig struct { +type DeployerConfig struct { // 多吉云 AccessKey。 AccessKey string `json:"accessKey"` // 多吉云 SecretKey。 @@ -23,31 +22,23 @@ type DogeCloudCDNDeployerConfig struct { Domain string `json:"domain"` } -type DogeCloudCDNDeployer struct { - config *DogeCloudCDNDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *dogesdk.Client sslUploader uploader.Uploader } -var _ deployer.Deployer = (*DogeCloudCDNDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *DogeCloudCDNDeployerConfig) (*DogeCloudCDNDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *DogeCloudCDNDeployerConfig, logger logger.Logger) (*DogeCloudCDNDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client := dogesdk.NewClient(config.AccessKey, config.SecretKey) - uploader, err := uploaderp.New(&uploaderp.DogeCloudUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ AccessKey: config.AccessKey, SecretKey: config.SecretKey, }) @@ -55,15 +46,19 @@ func NewWithLogger(config *DogeCloudCDNDeployerConfig, logger logger.Logger) (*D return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &DogeCloudCDNDeployer{ - logger: logger, - config: config, + return &DeployerProvider{ + logger: logger.NewNilLogger(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DogeCloudCDNDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // 上传证书到 CDN upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { diff --git a/internal/pkg/core/deployer/providers/dogecloud-cdn/dogecloud_cdn_test.go b/internal/pkg/core/deployer/providers/dogecloud-cdn/dogecloud_cdn_test.go index 8d066484..f9c1e7c9 100644 --- a/internal/pkg/core/deployer/providers/dogecloud-cdn/dogecloud_cdn_test.go +++ b/internal/pkg/core/deployer/providers/dogecloud-cdn/dogecloud_cdn_test.go @@ -52,7 +52,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) - deployer, err := provider.New(&provider.DogeCloudCDNDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKey: fAccessKey, SecretKey: fSecretKey, Domain: fDomain, diff --git a/internal/pkg/core/deployer/providers/edgio-applications/edgio_applications.go b/internal/pkg/core/deployer/providers/edgio-applications/edgio_applications.go index 5a6d4bf2..890cfdf3 100644 --- a/internal/pkg/core/deployer/providers/edgio-applications/edgio_applications.go +++ b/internal/pkg/core/deployer/providers/edgio-applications/edgio_applications.go @@ -2,7 +2,6 @@ import ( "context" - "errors" xerrors "github.com/pkg/errors" @@ -13,7 +12,7 @@ import ( edgsdkDtos "github.com/usual2970/certimate/internal/pkg/vendors/edgio-sdk/applications/v7/dtos" ) -type EdgioApplicationsDeployerConfig struct { +type DeployerConfig struct { // Edgio ClientId。 ClientId string `json:"clientId"` // Edgio ClientSecret。 @@ -22,25 +21,17 @@ type EdgioApplicationsDeployerConfig struct { EnvironmentId string `json:"environmentId"` } -type EdgioApplicationsDeployer struct { - config *EdgioApplicationsDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *edgsdk.EdgioClient } -var _ deployer.Deployer = (*EdgioApplicationsDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *EdgioApplicationsDeployerConfig) (*EdgioApplicationsDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *EdgioApplicationsDeployerConfig, logger logger.Logger) (*EdgioApplicationsDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client, err := createSdkClient(config.ClientId, config.ClientSecret) @@ -48,14 +39,19 @@ func NewWithLogger(config *EdgioApplicationsDeployerConfig, logger logger.Logger return nil, xerrors.Wrap(err, "failed to create sdk client") } - return &EdgioApplicationsDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, }, nil } -func (d *EdgioApplicationsDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // 提取 Edgio 所需的服务端证书和中间证书内容 privateCertPem, intermediateCertPem, err := certs.ExtractCertificatesFromPEM(certPem) if err != nil { diff --git a/internal/pkg/core/deployer/providers/edgio-applications/edgio_applications_test.go b/internal/pkg/core/deployer/providers/edgio-applications/edgio_applications_test.go index 04f7a4cb..bd05b16c 100644 --- a/internal/pkg/core/deployer/providers/edgio-applications/edgio_applications_test.go +++ b/internal/pkg/core/deployer/providers/edgio-applications/edgio_applications_test.go @@ -52,7 +52,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("ENVIRONMENTID: %v", fEnvironmentId), }, "\n")) - deployer, err := provider.New(&provider.EdgioApplicationsDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ ClientId: fClientId, ClientSecret: fClientSecret, EnvironmentId: fEnvironmentId, diff --git a/internal/pkg/core/deployer/providers/gcore-cdn/gcore_cdn.go b/internal/pkg/core/deployer/providers/gcore-cdn/gcore_cdn.go new file mode 100644 index 00000000..e1598a5d --- /dev/null +++ b/internal/pkg/core/deployer/providers/gcore-cdn/gcore_cdn.go @@ -0,0 +1,124 @@ +package gcorecdn + +import ( + "context" + "errors" + "strconv" + + gprovider "github.com/G-Core/gcorelabscdn-go/gcore/provider" + gresources "github.com/G-Core/gcorelabscdn-go/resources" + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/logger" + "github.com/usual2970/certimate/internal/pkg/core/uploader" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/gcore-cdn" + gcoresdk "github.com/usual2970/certimate/internal/pkg/vendors/gcore-sdk/common" +) + +type DeployerConfig struct { + // Gcore API Token。 + ApiToken string `json:"apiToken"` + // CDN 资源 ID。 + ResourceId int64 `json:"resourceId"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger logger.Logger + sdkClient *gresources.Service + 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.ApiToken) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ + ApiToken: config.ApiToken, + }) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create ssl uploader") + } + + return &DeployerProvider{ + config: config, + logger: logger.NewNilLogger(), + sdkClient: client, + sslUploader: uploader, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { + if d.config.ResourceId == 0 { + return nil, errors.New("config `resourceId` is required") + } + + // 上传证书到 CDN + upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) + if err != nil { + return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Logt("certificate file uploaded", upres) + } + + // 获取 CDN 资源详情 + // REF: https://api.gcore.com/docs/cdn#tag/CDN-resources/paths/~1cdn~1resources~1%7Bresource_id%7D/get + getResourceResp, err := d.sdkClient.Get(context.TODO(), d.config.ResourceId) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'resources.Get'") + } else { + d.logger.Logt("已获取 CDN 资源详情", getResourceResp) + } + + // 更新 CDN 资源详情 + // REF: https://api.gcore.com/docs/cdn#tag/CDN-resources/operation/change_cdn_resource + updateResourceCertId, _ := strconv.ParseInt(upres.CertId, 10, 64) + updateResourceReq := &gresources.UpdateRequest{ + Description: getResourceResp.Description, + Active: getResourceResp.Active, + OriginGroup: int(getResourceResp.OriginGroup), + OriginProtocol: getResourceResp.OriginProtocol, + SecondaryHostnames: getResourceResp.SecondaryHostnames, + SSlEnabled: true, + SSLData: int(updateResourceCertId), + ProxySSLEnabled: getResourceResp.ProxySSLEnabled, + ProxySSLCA: &getResourceResp.ProxySSLCA, + ProxySSLData: &getResourceResp.ProxySSLData, + Options: getResourceResp.Options, + } + updateResourceResp, err := d.sdkClient.Update(context.TODO(), d.config.ResourceId, updateResourceReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'resources.Update'") + } else { + d.logger.Logt("已更新 CDN 资源详情", updateResourceResp) + } + + return &deployer.DeployResult{}, nil +} + +func createSdkClient(apiToken string) (*gresources.Service, error) { + if apiToken == "" { + return nil, errors.New("invalid gcore api token") + } + + requester := gprovider.NewClient( + gcoresdk.BASE_URL, + gprovider.WithSigner(gcoresdk.NewAuthRequestSigner(apiToken)), + ) + service := gresources.NewService(requester) + return service, nil +} diff --git a/internal/pkg/core/deployer/providers/gcore-cdn/gcore_cdn_test.go b/internal/pkg/core/deployer/providers/gcore-cdn/gcore_cdn_test.go new file mode 100644 index 00000000..34d4a9d6 --- /dev/null +++ b/internal/pkg/core/deployer/providers/gcore-cdn/gcore_cdn_test.go @@ -0,0 +1,70 @@ +package gcorecdn_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/gcore-cdn" +) + +var ( + fInputCertPath string + fInputKeyPath string + fApiToken string + fResourceId int64 +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_GCORECDN_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fApiToken, argsPrefix+"APITOKEN", "", "") + flag.Int64Var(&fResourceId, argsPrefix+"RESOURCEID", 0, "") +} + +/* +Shell command to run this test: + + go test -v ./gcore_cdn_test.go -args \ + --CERTIMATE_DEPLOYER_GCORECDN_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_GCORECDN_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_GCORECDN_APITOKEN="your-api-token" \ + --CERTIMATE_DEPLOYER_GCORECDN_RESOURCEID="your-cdn-resource-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("APITOKEN: %v", fApiToken), + fmt.Sprintf("RESOURCEID: %v", fResourceId), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + ApiToken: fApiToken, + ResourceId: fResourceId, + }) + 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) + }) +} diff --git a/internal/pkg/core/deployer/providers/huaweicloud-cdn/huaweicloud_cdn.go b/internal/pkg/core/deployer/providers/huaweicloud-cdn/huaweicloud_cdn.go index 31782af3..4a40fbc1 100644 --- a/internal/pkg/core/deployer/providers/huaweicloud-cdn/huaweicloud_cdn.go +++ b/internal/pkg/core/deployer/providers/huaweicloud-cdn/huaweicloud_cdn.go @@ -2,7 +2,6 @@ import ( "context" - "errors" "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/global" hcCdn "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/cdn/v2" @@ -13,11 +12,11 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/huaweicloud-scm" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/huaweicloud-scm" hwsdk "github.com/usual2970/certimate/internal/pkg/vendors/huaweicloud-sdk" ) -type HuaweiCloudCDNDeployerConfig struct { +type DeployerConfig struct { // 华为云 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 华为云 SecretAccessKey。 @@ -28,26 +27,18 @@ type HuaweiCloudCDNDeployerConfig struct { Domain string `json:"domain"` } -type HuaweiCloudCDNDeployer struct { - config *HuaweiCloudCDNDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *hcCdn.CdnClient sslUploader uploader.Uploader } -var _ deployer.Deployer = (*HuaweiCloudCDNDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *HuaweiCloudCDNDeployerConfig) (*HuaweiCloudCDNDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *HuaweiCloudCDNDeployerConfig, logger logger.Logger) (*HuaweiCloudCDNDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client, err := createSdkClient( @@ -59,7 +50,7 @@ func NewWithLogger(config *HuaweiCloudCDNDeployerConfig, logger logger.Logger) ( return nil, xerrors.Wrap(err, "failed to create sdk client") } - uploader, err := uploaderp.New(&uploaderp.HuaweiCloudSCMUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ AccessKeyId: config.AccessKeyId, SecretAccessKey: config.SecretAccessKey, }) @@ -67,15 +58,20 @@ func NewWithLogger(config *HuaweiCloudCDNDeployerConfig, logger logger.Logger) ( return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &HuaweiCloudCDNDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *HuaweiCloudCDNDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // 上传证书到 SCM upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { diff --git a/internal/pkg/core/deployer/providers/huaweicloud-cdn/huaweicloud_cdn_test.go b/internal/pkg/core/deployer/providers/huaweicloud-cdn/huaweicloud_cdn_test.go index d31b2a68..aaf8d6c7 100644 --- a/internal/pkg/core/deployer/providers/huaweicloud-cdn/huaweicloud_cdn_test.go +++ b/internal/pkg/core/deployer/providers/huaweicloud-cdn/huaweicloud_cdn_test.go @@ -56,7 +56,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) - deployer, err := provider.New(&provider.HuaweiCloudCDNDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKeyId: fAccessKeyId, SecretAccessKey: fSecretAccessKey, Region: fRegion, diff --git a/internal/pkg/core/deployer/providers/huaweicloud-elb/consts.go b/internal/pkg/core/deployer/providers/huaweicloud-elb/consts.go new file mode 100644 index 00000000..b097a958 --- /dev/null +++ b/internal/pkg/core/deployer/providers/huaweicloud-elb/consts.go @@ -0,0 +1,12 @@ +package huaweicloudelb + +type ResourceType string + +const ( + // 资源类型:替换指定证书。 + RESOURCE_TYPE_CERTIFICATE = ResourceType("certificate") + // 资源类型:部署到指定负载均衡器。 + RESOURCE_TYPE_LOADBALANCER = ResourceType("loadbalancer") + // 资源类型:部署到指定监听器。 + RESOURCE_TYPE_LISTENER = ResourceType("listener") +) diff --git a/internal/pkg/core/deployer/providers/huaweicloud-elb/defines.go b/internal/pkg/core/deployer/providers/huaweicloud-elb/defines.go deleted file mode 100644 index 093ab829..00000000 --- a/internal/pkg/core/deployer/providers/huaweicloud-elb/defines.go +++ /dev/null @@ -1,12 +0,0 @@ -package huaweicloudelb - -type DeployResourceType string - -const ( - // 资源类型:替换指定证书。 - DEPLOY_RESOURCE_CERTIFICATE = DeployResourceType("certificate") - // 资源类型:部署到指定负载均衡器。 - DEPLOY_RESOURCE_LOADBALANCER = DeployResourceType("loadbalancer") - // 资源类型:部署到指定监听器。 - DEPLOY_RESOURCE_LISTENER = DeployResourceType("listener") -) diff --git a/internal/pkg/core/deployer/providers/huaweicloud-elb/huaweicloud_elb.go b/internal/pkg/core/deployer/providers/huaweicloud-elb/huaweicloud_elb.go index 3fa17a70..17bc178b 100644 --- a/internal/pkg/core/deployer/providers/huaweicloud-elb/huaweicloud_elb.go +++ b/internal/pkg/core/deployer/providers/huaweicloud-elb/huaweicloud_elb.go @@ -19,11 +19,11 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/huaweicloud-elb" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/huaweicloud-elb" hwsdk "github.com/usual2970/certimate/internal/pkg/vendors/huaweicloud-sdk" ) -type HuaweiCloudELBDeployerConfig struct { +type DeployerConfig struct { // 华为云 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 华为云 SecretAccessKey。 @@ -31,38 +31,30 @@ type HuaweiCloudELBDeployerConfig struct { // 华为云区域。 Region string `json:"region"` // 部署资源类型。 - ResourceType DeployResourceType `json:"resourceType"` + ResourceType ResourceType `json:"resourceType"` // 证书 ID。 - // 部署资源类型为 [DEPLOY_RESOURCE_CERTIFICATE] 时必填。 + // 部署资源类型为 [RESOURCE_TYPE_CERTIFICATE] 时必填。 CertificateId string `json:"certificateId,omitempty"` // 负载均衡器 ID。 - // 部署资源类型为 [DEPLOY_RESOURCE_LOADBALANCER] 时必填。 + // 部署资源类型为 [RESOURCE_TYPE_LOADBALANCER] 时必填。 LoadbalancerId string `json:"loadbalancerId,omitempty"` // 负载均衡监听 ID。 - // 部署资源类型为 [DEPLOY_RESOURCE_LISTENER] 时必填。 + // 部署资源类型为 [RESOURCE_TYPE_LISTENER] 时必填。 ListenerId string `json:"listenerId,omitempty"` } -type HuaweiCloudELBDeployer struct { - config *HuaweiCloudELBDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *hcElb.ElbClient sslUploader uploader.Uploader } -var _ deployer.Deployer = (*HuaweiCloudELBDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *HuaweiCloudELBDeployerConfig) (*HuaweiCloudELBDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *HuaweiCloudELBDeployerConfig, logger logger.Logger) (*HuaweiCloudELBDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client, err := createSdkClient(config.AccessKeyId, config.SecretAccessKey, config.Region) @@ -70,7 +62,7 @@ func NewWithLogger(config *HuaweiCloudELBDeployerConfig, logger logger.Logger) ( return nil, xerrors.Wrap(err, "failed to create sdk client") } - uploader, err := uploaderp.New(&uploaderp.HuaweiCloudELBUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ AccessKeyId: config.AccessKeyId, SecretAccessKey: config.SecretAccessKey, Region: config.Region, @@ -79,15 +71,20 @@ func NewWithLogger(config *HuaweiCloudELBDeployerConfig, logger logger.Logger) ( return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &HuaweiCloudELBDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *HuaweiCloudELBDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // 上传证书到 SCM upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { @@ -98,17 +95,17 @@ func (d *HuaweiCloudELBDeployer) Deploy(ctx context.Context, certPem string, pri // 根据部署资源类型决定部署方式 switch d.config.ResourceType { - case DEPLOY_RESOURCE_CERTIFICATE: + case RESOURCE_TYPE_CERTIFICATE: if err := d.deployToCertificate(ctx, certPem, privkeyPem); err != nil { return nil, err } - case DEPLOY_RESOURCE_LOADBALANCER: + case RESOURCE_TYPE_LOADBALANCER: if err := d.deployToLoadbalancer(ctx, certPem, privkeyPem); err != nil { return nil, err } - case DEPLOY_RESOURCE_LISTENER: + case RESOURCE_TYPE_LISTENER: if err := d.deployToListener(ctx, certPem, privkeyPem); err != nil { return nil, err } @@ -120,7 +117,7 @@ func (d *HuaweiCloudELBDeployer) Deploy(ctx context.Context, certPem string, pri return &deployer.DeployResult{}, nil } -func (d *HuaweiCloudELBDeployer) deployToCertificate(ctx context.Context, certPem string, privkeyPem string) error { +func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPem string, privkeyPem string) error { if d.config.CertificateId == "" { return errors.New("config `certificateId` is required") } @@ -146,7 +143,7 @@ func (d *HuaweiCloudELBDeployer) deployToCertificate(ctx context.Context, certPe return nil } -func (d *HuaweiCloudELBDeployer) deployToLoadbalancer(ctx context.Context, certPem string, privkeyPem string) error { +func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, certPem string, privkeyPem string) error { if d.config.LoadbalancerId == "" { return errors.New("config `loadbalancerId` is required") } @@ -223,7 +220,7 @@ func (d *HuaweiCloudELBDeployer) deployToLoadbalancer(ctx context.Context, certP return nil } -func (d *HuaweiCloudELBDeployer) deployToListener(ctx context.Context, certPem string, privkeyPem string) error { +func (d *DeployerProvider) deployToListener(ctx context.Context, certPem string, privkeyPem string) error { if d.config.ListenerId == "" { return errors.New("config `listenerId` is required") } @@ -244,7 +241,7 @@ func (d *HuaweiCloudELBDeployer) deployToListener(ctx context.Context, certPem s return nil } -func (d *HuaweiCloudELBDeployer) modifyListenerCertificate(ctx context.Context, cloudListenerId string, cloudCertId string) error { +func (d *DeployerProvider) modifyListenerCertificate(ctx context.Context, cloudListenerId string, cloudCertId string) error { // 查询监听器详情 // REF: https://support.huaweicloud.com/api-elb/ShowListener.html showListenerReq := &hcElbModel.ShowListenerRequest{ diff --git a/internal/pkg/core/deployer/providers/huaweicloud-elb/huaweicloud_elb_test.go b/internal/pkg/core/deployer/providers/huaweicloud-elb/huaweicloud_elb_test.go index 32582800..4325ba40 100644 --- a/internal/pkg/core/deployer/providers/huaweicloud-elb/huaweicloud_elb_test.go +++ b/internal/pkg/core/deployer/providers/huaweicloud-elb/huaweicloud_elb_test.go @@ -62,11 +62,11 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("CERTIFICATEID: %v", fCertificateId), }, "\n")) - deployer, err := provider.New(&provider.HuaweiCloudELBDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKeyId: fAccessKeyId, SecretAccessKey: fSecretAccessKey, Region: fRegion, - ResourceType: provider.DEPLOY_RESOURCE_CERTIFICATE, + ResourceType: provider.RESOURCE_TYPE_CERTIFICATE, CertificateId: fCertificateId, }) if err != nil { @@ -96,11 +96,11 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("LOADBALANCERID: %v", fLoadbalancerId), }, "\n")) - deployer, err := provider.New(&provider.HuaweiCloudELBDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKeyId: fAccessKeyId, SecretAccessKey: fSecretAccessKey, Region: fRegion, - ResourceType: provider.DEPLOY_RESOURCE_LOADBALANCER, + ResourceType: provider.RESOURCE_TYPE_LOADBALANCER, LoadbalancerId: fLoadbalancerId, }) if err != nil { @@ -130,11 +130,11 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("LISTENERID: %v", fListenerId), }, "\n")) - deployer, err := provider.New(&provider.HuaweiCloudELBDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKeyId: fAccessKeyId, SecretAccessKey: fSecretAccessKey, Region: fRegion, - ResourceType: provider.DEPLOY_RESOURCE_LISTENER, + ResourceType: provider.RESOURCE_TYPE_LISTENER, ListenerId: fListenerId, }) if err != nil { diff --git a/internal/pkg/core/deployer/providers/huaweicloud-waf/consts.go b/internal/pkg/core/deployer/providers/huaweicloud-waf/consts.go new file mode 100644 index 00000000..fc574c32 --- /dev/null +++ b/internal/pkg/core/deployer/providers/huaweicloud-waf/consts.go @@ -0,0 +1,12 @@ +package huaweicloudwaf + +type ResourceType string + +const ( + // 资源类型:替换指定证书。 + RESOURCE_TYPE_CERTIFICATE = ResourceType("certificate") + // 资源类型:部署到云模式防护网站。 + RESOURCE_TYPE_CLOUDSERVER = ResourceType("cloudserver") + // 资源类型:部署到独享模式防护网站。 + RESOURCE_TYPE_PREMIUMHOST = ResourceType("premiumhost") +) diff --git a/internal/pkg/core/deployer/providers/huaweicloud-waf/huaweicloud_waf.go b/internal/pkg/core/deployer/providers/huaweicloud-waf/huaweicloud_waf.go new file mode 100644 index 00000000..2342edfa --- /dev/null +++ b/internal/pkg/core/deployer/providers/huaweicloud-waf/huaweicloud_waf.go @@ -0,0 +1,355 @@ +package huaweicloudwaf + +import ( + "context" + "errors" + "fmt" + "strings" + + "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic" + "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/global" + hcIam "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/iam/v3" + hcIamModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/iam/v3/model" + hcIamRegion "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/iam/v3/region" + hcWaf "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/waf/v1" + hcWafModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/waf/v1/model" + hcWafRegion "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/waf/v1/region" + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/logger" + "github.com/usual2970/certimate/internal/pkg/core/uploader" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/huaweicloud-waf" + hwsdk "github.com/usual2970/certimate/internal/pkg/vendors/huaweicloud-sdk" +) + +type DeployerConfig struct { + // 华为云 AccessKeyId。 + AccessKeyId string `json:"accessKeyId"` + // 华为云 SecretAccessKey。 + SecretAccessKey string `json:"secretAccessKey"` + // 华为云区域。 + Region string `json:"region"` + // 部署资源类型。 + ResourceType ResourceType `json:"resourceType"` + // 证书 ID。 + // 部署资源类型为 [RESOURCE_TYPE_CERTIFICATE] 时必填。 + CertificateId string `json:"certificateId,omitempty"` + // 防护域名(支持泛域名)。 + // 部署资源类型为 [RESOURCE_TYPE_CLOUDSERVER]、[RESOURCE_TYPE_PREMIUMHOST] 时必填。 + Domain string `json:"domain,omitempty"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger logger.Logger + sdkClient *hcWaf.WafClient + 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, config.Region) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ + AccessKeyId: config.AccessKeyId, + SecretAccessKey: config.SecretAccessKey, + Region: config.Region, + }) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create ssl uploader") + } + + return &DeployerProvider{ + config: config, + logger: logger.NewNilLogger(), + sdkClient: client, + sslUploader: uploader, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { + // 上传证书到 WAF + upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) + if err != nil { + return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Logt("certificate file uploaded", upres) + } + + // 根据部署资源类型决定部署方式 + switch d.config.ResourceType { + case RESOURCE_TYPE_CERTIFICATE: + if err := d.deployToCertificate(ctx, certPem, privkeyPem); err != nil { + return nil, err + } + + case RESOURCE_TYPE_CLOUDSERVER: + if err := d.deployToCloudServer(ctx, certPem, privkeyPem); err != nil { + return nil, err + } + + case RESOURCE_TYPE_PREMIUMHOST: + if err := d.deployToPremiumHost(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") + } + + // 查询证书 + // REF: https://support.huaweicloud.com/api-waf/ShowCertificate.html + showCertificateReq := &hcWafModel.ShowCertificateRequest{ + CertificateId: d.config.CertificateId, + } + showCertificateResp, err := d.sdkClient.ShowCertificate(showCertificateReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'waf.ShowCertificate'") + } else { + d.logger.Logt("已获取 WAF 证书", showCertificateResp) + } + + // 更新证书 + // REF: https://support.huaweicloud.com/api-waf/UpdateCertificate.html + updateCertificateReq := &hcWafModel.UpdateCertificateRequest{ + CertificateId: d.config.CertificateId, + Body: &hcWafModel.UpdateCertificateRequestBody{ + Name: *showCertificateResp.Name, + Content: hwsdk.StringPtr(certPem), + Key: hwsdk.StringPtr(privkeyPem), + }, + } + updateCertificateResp, err := d.sdkClient.UpdateCertificate(updateCertificateReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'waf.UpdateCertificate'") + } else { + d.logger.Logt("已更新 WAF 证书", updateCertificateResp) + } + + return nil +} + +func (d *DeployerProvider) deployToCloudServer(ctx context.Context, certPem string, privkeyPem string) error { + if d.config.Domain == "" { + return errors.New("config `domain` is required") + } + + // 上传证书到 WAF + upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) + if err != nil { + return xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Logt("certificate file uploaded", upres) + } + + // 遍历查询云模式防护域名列表,获取防护域名 ID + // REF: https://support.huaweicloud.com/api-waf/ListHost.html + hostId := "" + listHostPage := int32(1) + listHostPageSize := int32(100) + for { + listHostReq := &hcWafModel.ListHostRequest{ + Hostname: hwsdk.StringPtr(strings.TrimPrefix(d.config.Domain, "*")), + Page: hwsdk.Int32Ptr(listHostPage), + Pagesize: hwsdk.Int32Ptr(listHostPageSize), + } + listHostResp, err := d.sdkClient.ListHost(listHostReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'waf.ListHost'") + } + + if listHostResp.Items != nil { + for _, hostItem := range *listHostResp.Items { + if strings.TrimPrefix(d.config.Domain, "*") == *hostItem.Hostname { + hostId = *hostItem.Id + break + } + } + } + + if listHostResp.Items == nil || len(*listHostResp.Items) < int(listHostPageSize) { + break + } else { + listHostPage++ + } + } + if hostId == "" { + return errors.New("host not found") + } + + // 更新云模式防护域名的配置 + // REF: https://support.huaweicloud.com/api-waf/UpdateHost.html + updateHostReq := &hcWafModel.UpdateHostRequest{ + InstanceId: hostId, + Body: &hcWafModel.UpdateHostRequestBody{ + Certificateid: hwsdk.StringPtr(upres.CertId), + Certificatename: hwsdk.StringPtr(upres.CertName), + }, + } + updateHostResp, err := d.sdkClient.UpdateHost(updateHostReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'waf.UpdateHost'") + } else { + d.logger.Logt("已更新云模式防护域名的配置", updateHostResp) + } + + return nil +} + +func (d *DeployerProvider) deployToPremiumHost(ctx context.Context, certPem string, privkeyPem string) error { + if d.config.Domain == "" { + return errors.New("config `domain` is required") + } + + // 上传证书到 WAF + upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) + if err != nil { + return xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Logt("certificate file uploaded", upres) + } + + // 遍历查询独享模式域名列表,获取防护域名 ID + // REF: https://support.huaweicloud.com/api-waf/ListPremiumHost.html + hostId := "" + listPremiumHostPage := int32(1) + listPremiumHostPageSize := int32(100) + for { + listPremiumHostReq := &hcWafModel.ListPremiumHostRequest{ + Hostname: hwsdk.StringPtr(strings.TrimPrefix(d.config.Domain, "*")), + Page: hwsdk.StringPtr(fmt.Sprintf("%d", listPremiumHostPage)), + Pagesize: hwsdk.StringPtr(fmt.Sprintf("%d", listPremiumHostPageSize)), + } + listPremiumHostResp, err := d.sdkClient.ListPremiumHost(listPremiumHostReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'waf.ListPremiumHost'") + } + + if listPremiumHostResp.Items != nil { + for _, hostItem := range *listPremiumHostResp.Items { + if strings.TrimPrefix(d.config.Domain, "*") == *hostItem.Hostname { + hostId = *hostItem.Id + break + } + } + } + + if listPremiumHostResp.Items == nil || len(*listPremiumHostResp.Items) < int(listPremiumHostPageSize) { + break + } else { + listPremiumHostPage++ + } + } + if hostId == "" { + return errors.New("host not found") + } + + // 修改独享模式域名配置 + // REF: https://support.huaweicloud.com/api-waf/UpdatePremiumHost.html + updatePremiumHostReq := &hcWafModel.UpdatePremiumHostRequest{ + HostId: hostId, + Body: &hcWafModel.UpdatePremiumHostRequestBody{ + Certificateid: hwsdk.StringPtr(upres.CertId), + Certificatename: hwsdk.StringPtr(upres.CertName), + }, + } + updatePremiumHostResp, err := d.sdkClient.UpdatePremiumHost(updatePremiumHostReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'waf.UpdatePremiumHost'") + } else { + d.logger.Logt("已修改独享模式域名配置", updatePremiumHostResp) + } + + return nil +} + +func createSdkClient(accessKeyId, secretAccessKey, region string) (*hcWaf.WafClient, error) { + projectId, err := getSdkProjectId(accessKeyId, secretAccessKey, region) + if err != nil { + return nil, err + } + + auth, err := basic.NewCredentialsBuilder(). + WithAk(accessKeyId). + WithSk(secretAccessKey). + WithProjectId(projectId). + SafeBuild() + if err != nil { + return nil, err + } + + hcRegion, err := hcWafRegion.SafeValueOf(region) + if err != nil { + return nil, err + } + + hcClient, err := hcWaf.WafClientBuilder(). + WithRegion(hcRegion). + WithCredential(auth). + SafeBuild() + if err != nil { + return nil, err + } + + client := hcWaf.NewWafClient(hcClient) + return client, nil +} + +func getSdkProjectId(accessKeyId, secretAccessKey, region string) (string, error) { + auth, err := global.NewCredentialsBuilder(). + WithAk(accessKeyId). + WithSk(secretAccessKey). + SafeBuild() + if err != nil { + return "", err + } + + hcRegion, err := hcIamRegion.SafeValueOf(region) + if err != nil { + return "", err + } + + hcClient, err := hcIam.IamClientBuilder(). + WithRegion(hcRegion). + WithCredential(auth). + SafeBuild() + if err != nil { + return "", err + } + + client := hcIam.NewIamClient(hcClient) + + request := &hcIamModel.KeystoneListProjectsRequest{ + Name: ®ion, + } + response, err := client.KeystoneListProjects(request) + if err != nil { + return "", err + } else if response.Projects == nil || len(*response.Projects) == 0 { + return "", errors.New("no project found") + } + + return (*response.Projects)[0].Id, nil +} diff --git a/internal/pkg/core/deployer/providers/huaweicloud-waf/huaweicloud_waf_test.go b/internal/pkg/core/deployer/providers/huaweicloud-waf/huaweicloud_waf_test.go new file mode 100644 index 00000000..83142325 --- /dev/null +++ b/internal/pkg/core/deployer/providers/huaweicloud-waf/huaweicloud_waf_test.go @@ -0,0 +1,84 @@ +package huaweicloudwaf_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/huaweicloud-waf" +) + +var ( + fInputCertPath string + fInputKeyPath string + fAccessKeyId string + fSecretAccessKey string + fRegion string + fResourceType string + fDomain string +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_HUAWEICLOUDWAF_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "") + flag.StringVar(&fSecretAccessKey, argsPrefix+"SECRETACCESSKEY", "", "") + flag.StringVar(&fRegion, argsPrefix+"REGION", "", "") + flag.StringVar(&fResourceType, argsPrefix+"RESOURCETYPE", "", "") + flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "") +} + +/* +Shell command to run this test: + + go test -v ./huaweicloud_waf_test.go -args \ + --CERTIMATE_DEPLOYER_HUAWEICLOUDWAF_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_HUAWEICLOUDWAF_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_HUAWEICLOUDWAF_ACCESSKEYID="your-access-key-id" \ + --CERTIMATE_DEPLOYER_HUAWEICLOUDWAF_SECRETACCESSKEY="your-secret-access-key" \ + --CERTIMATE_DEPLOYER_HUAWEICLOUDWAF_REGION="cn-north-1" \ + --CERTIMATE_DEPLOYER_HUAWEICLOUDWAF_RESOURCETYPE="premium" \ + --CERTIMATE_DEPLOYER_HUAWEICLOUDWAF_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("REGION: %v", fRegion), + fmt.Sprintf("RESOURCETYPE: %v", fResourceType), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + AccessKeyId: fAccessKeyId, + SecretAccessKey: fSecretAccessKey, + Region: fRegion, + ResourceType: provider.ResourceType(fResourceType), + 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) + }) +} diff --git a/internal/pkg/core/deployer/providers/jdcloud-alb/consts.go b/internal/pkg/core/deployer/providers/jdcloud-alb/consts.go new file mode 100644 index 00000000..13525c20 --- /dev/null +++ b/internal/pkg/core/deployer/providers/jdcloud-alb/consts.go @@ -0,0 +1,10 @@ +package jdcloudalb + +type ResourceType string + +const ( + // 资源类型:部署到指定负载均衡器。 + RESOURCE_TYPE_LOADBALANCER = ResourceType("loadbalancer") + // 资源类型:部署到指定监听器。 + RESOURCE_TYPE_LISTENER = ResourceType("listener") +) diff --git a/internal/pkg/core/deployer/providers/jdcloud-alb/jdcloud_alb.go b/internal/pkg/core/deployer/providers/jdcloud-alb/jdcloud_alb.go new file mode 100644 index 00000000..41625b64 --- /dev/null +++ b/internal/pkg/core/deployer/providers/jdcloud-alb/jdcloud_alb.go @@ -0,0 +1,252 @@ +package jdcloudalb + +import ( + "context" + "errors" + "fmt" + "strings" + + jdCore "github.com/jdcloud-api/jdcloud-sdk-go/core" + jdCommon "github.com/jdcloud-api/jdcloud-sdk-go/services/common/models" + jdLbApi "github.com/jdcloud-api/jdcloud-sdk-go/services/lb/apis" + jdLbClient "github.com/jdcloud-api/jdcloud-sdk-go/services/lb/client" + jdLbModel "github.com/jdcloud-api/jdcloud-sdk-go/services/lb/models" + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/logger" + "github.com/usual2970/certimate/internal/pkg/core/uploader" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/jdcloud-ssl" + "github.com/usual2970/certimate/internal/pkg/utils/slices" +) + +type DeployerConfig struct { + // 京东云 AccessKeyId。 + AccessKeyId string `json:"accessKeyId"` + // 京东云 AccessKeySecret。 + AccessKeySecret string `json:"accessKeySecret"` + // 京东云地域 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"` + // SNI 域名(支持泛域名)。 + // 部署资源类型为 [RESOURCE_TYPE_LOADBALANCER]、[RESOURCE_TYPE_LISTENER] 时选填。 + Domain string `json:"domain,omitempty"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger logger.Logger + sdkClient *jdLbClient.LbClient + 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.AccessKeySecret) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ + AccessKeyId: config.AccessKeyId, + AccessKeySecret: config.AccessKeySecret, + }) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create ssl uploader") + } + + return &DeployerProvider{ + config: config, + logger: logger.NewNilLogger(), + sdkClient: client, + sslUploader: uploader, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { + // 上传证书到 SSL + upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) + if err != nil { + return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Logt("certificate file uploaded", 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://docs.jdcloud.com/cn/load-balancer/api/describeloadbalancer + describeLoadBalancerReq := jdLbApi.NewDescribeLoadBalancerRequest(d.config.RegionId, d.config.LoadbalancerId) + describeLoadBalancerResp, err := d.sdkClient.DescribeLoadBalancer(describeLoadBalancerReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'lb.DescribeLoadBalancer'") + } else { + d.logger.Logt("已查询到负载均衡器详情", describeLoadBalancerResp) + } + + // 查询监听器列表 + // REF: https://docs.jdcloud.com/cn/load-balancer/api/describelisteners + listenerIds := make([]string, 0) + describeListenersPageNumber := 1 + describeListenersPageSize := 100 + for { + describeListenersReq := jdLbApi.NewDescribeListenersRequest(d.config.RegionId) + describeListenersReq.SetFilters([]jdCommon.Filter{{Name: "loadBalancerId", Values: []string{d.config.LoadbalancerId}}}) + describeListenersReq.SetPageSize(describeListenersPageNumber) + describeListenersReq.SetPageSize(describeListenersPageSize) + describeListenersResp, err := d.sdkClient.DescribeListeners(describeListenersReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'lb.DescribeListeners'") + } + + for _, listener := range describeListenersResp.Result.Listeners { + if strings.EqualFold(listener.Protocol, "https") || strings.EqualFold(listener.Protocol, "tls") { + listenerIds = append(listenerIds, listener.ListenerId) + } + } + + if len(describeListenersResp.Result.Listeners) < int(describeListenersPageSize) { + break + } else { + describeListenersPageNumber++ + } + } + + // 遍历更新监听器证书 + if len(listenerIds) == 0 { + return errors.New("listener not found") + } else { + d.logger.Logt("已查询到负载均衡器下的全部 HTTPS/TLS 监听器", listenerIds) + + var errs []error + + for _, listenerId := range listenerIds { + 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://docs.jdcloud.com/cn/load-balancer/api/describelistener + describeListenerReq := jdLbApi.NewDescribeListenerRequest(d.config.RegionId, cloudListenerId) + describeListenerResp, err := d.sdkClient.DescribeListener(describeListenerReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'lb.DescribeListener'") + } else { + d.logger.Logt("已查询到监听器详情", describeListenerResp) + } + + if d.config.Domain == "" { + // 未指定 SNI,只需部署到监听器 + + // 修改监听器信息 + // REF: https://docs.jdcloud.com/cn/load-balancer/api/updatelistener + updateListenerReq := jdLbApi.NewUpdateListenerRequest(d.config.RegionId, cloudListenerId) + updateListenerReq.SetCertificateSpecs([]jdLbModel.CertificateSpec{{CertificateId: cloudCertId}}) + updateListenerResp, err := d.sdkClient.UpdateListener(updateListenerReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'lb.UpdateListener'") + } else { + d.logger.Logt("已修改监听器信息", updateListenerResp) + } + } else { + // 指定 SNI,需部署到扩展证书 + + extCertSpecs := slices.Filter(describeListenerResp.Result.Listener.ExtensionCertificateSpecs, func(extCertSpec jdLbModel.ExtensionCertificateSpec) bool { + return extCertSpec.Domain == d.config.Domain + }) + if len(extCertSpecs) == 0 { + return errors.New("extension certificate spec not found") + } + + // 批量修改扩展证书 + // REF: https://docs.jdcloud.com/cn/load-balancer/api/updatelistenercertificates + updateListenerCertificatesReq := jdLbApi.NewUpdateListenerCertificatesRequest( + d.config.RegionId, + cloudListenerId, + slices.Map(extCertSpecs, func(extCertSpec jdLbModel.ExtensionCertificateSpec) jdLbModel.ExtCertificateUpdateSpec { + return jdLbModel.ExtCertificateUpdateSpec{ + CertificateBindId: extCertSpec.CertificateBindId, + CertificateId: &cloudCertId, + Domain: &extCertSpec.Domain, + } + }), + ) + updateListenerCertificatesResp, err := d.sdkClient.UpdateListenerCertificates(updateListenerCertificatesReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'lb.UpdateListenerCertificates'") + } else { + d.logger.Logt("已批量修改扩展证书", updateListenerCertificatesResp) + } + } + + return nil +} + +func createSdkClient(accessKeyId, accessKeySecret string) (*jdLbClient.LbClient, error) { + clientCredentials := jdCore.NewCredentials(accessKeyId, accessKeySecret) + client := jdLbClient.NewLbClient(clientCredentials) + client.SetLogger(jdCore.NewDefaultLogger(jdCore.LogWarn)) + return client, nil +} diff --git a/internal/pkg/core/deployer/providers/jdcloud-alb/jdcloud_alb_test.go b/internal/pkg/core/deployer/providers/jdcloud-alb/jdcloud_alb_test.go new file mode 100644 index 00000000..9c9cc9cc --- /dev/null +++ b/internal/pkg/core/deployer/providers/jdcloud-alb/jdcloud_alb_test.go @@ -0,0 +1,118 @@ +package jdcloudalb_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/jdcloud-alb" +) + +var ( + fInputCertPath string + fInputKeyPath string + fAccessKeyId string + fAccessKeySecret string + fRegionId string + fLoadbalancerId string + fListenerId string +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_JDCLOUDALB_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "") + flag.StringVar(&fAccessKeySecret, argsPrefix+"ACCESSKEYSECRET", "", "") + flag.StringVar(&fRegionId, argsPrefix+"REGIONID", "", "") + flag.StringVar(&fLoadbalancerId, argsPrefix+"LOADBALANCERID", "", "") + flag.StringVar(&fListenerId, argsPrefix+"LISTENERID", "", "") +} + +/* +Shell command to run this test: + + go test -v ./jdcloud_alb_test.go -args \ + --CERTIMATE_DEPLOYER_JDCLOUDALB_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_JDCLOUDALB_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_JDCLOUDALB_ACCESSKEYID="your-access-key-id" \ + --CERTIMATE_DEPLOYER_JDCLOUDALB_ACCESSKEYSECRET="your-secret-access-key" \ + --CERTIMATE_DEPLOYER_JDCLOUDALB_REGION_ID="cn-north-1" \ + --CERTIMATE_DEPLOYER_JDCLOUDALB_LOADBALANCERID="your-alb-loadbalancer-id" \ + --CERTIMATE_DEPLOYER_JDCLOUDALB_LISTENERID="your-alb-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("ACCESSKEYSECRET: %v", fAccessKeySecret), + fmt.Sprintf("REGIONID: %v", fRegionId), + fmt.Sprintf("LOADBALANCERID: %v", fLoadbalancerId), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + AccessKeyId: fAccessKeyId, + AccessKeySecret: fAccessKeySecret, + 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("ACCESSKEYSECRET: %v", fAccessKeySecret), + fmt.Sprintf("REGIONID: %v", fRegionId), + fmt.Sprintf("LISTENERID: %v", fListenerId), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + AccessKeyId: fAccessKeyId, + AccessKeySecret: fAccessKeySecret, + 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) + }) +} diff --git a/internal/pkg/core/deployer/providers/jdcloud-cdn/jdcloud_cdn.go b/internal/pkg/core/deployer/providers/jdcloud-cdn/jdcloud_cdn.go new file mode 100644 index 00000000..d5bdae4f --- /dev/null +++ b/internal/pkg/core/deployer/providers/jdcloud-cdn/jdcloud_cdn.go @@ -0,0 +1,109 @@ +package jdcloudcdn + +import ( + "context" + + jdCore "github.com/jdcloud-api/jdcloud-sdk-go/core" + jdCdnApi "github.com/jdcloud-api/jdcloud-sdk-go/services/cdn/apis" + jdCdnClient "github.com/jdcloud-api/jdcloud-sdk-go/services/cdn/client" + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/logger" + "github.com/usual2970/certimate/internal/pkg/core/uploader" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/jdcloud-ssl" +) + +type DeployerConfig struct { + // 京东云 AccessKeyId。 + AccessKeyId string `json:"accessKeyId"` + // 京东云 AccessKeySecret。 + AccessKeySecret string `json:"accessKeySecret"` + // 加速域名(支持泛域名)。 + Domain string `json:"domain"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger logger.Logger + sdkClient *jdCdnClient.CdnClient + 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.AccessKeySecret) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ + AccessKeyId: config.AccessKeyId, + AccessKeySecret: config.AccessKeySecret, + }) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create ssl uploader") + } + + return &DeployerProvider{ + config: config, + logger: logger.NewNilLogger(), + sdkClient: client, + sslUploader: uploader, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { + // 查询域名配置信息 + // REF: https://docs.jdcloud.com/cn/cdn/api/querydomainconfig + queryDomainConfigReq := jdCdnApi.NewQueryDomainConfigRequest(d.config.Domain) + queryDomainConfigResp, err := d.sdkClient.QueryDomainConfig(queryDomainConfigReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.QueryDomainConfig'") + } else { + d.logger.Logt("已查询到域名配置信息", queryDomainConfigResp) + } + + // 上传证书到 SSL + upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) + if err != nil { + return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Logt("certificate file uploaded", upres) + } + + // 设置通讯协议 + // REF: https://docs.jdcloud.com/cn/cdn/api/sethttptype + setHttpTypeReq := jdCdnApi.NewSetHttpTypeRequest(d.config.Domain) + setHttpTypeReq.SetHttpType("https") + setHttpTypeReq.SetCertificate(certPem) + setHttpTypeReq.SetRsaKey(privkeyPem) + setHttpTypeReq.SetCertFrom("ssl") + setHttpTypeReq.SetSslCertId(upres.CertId) + setHttpTypeReq.SetJumpType(queryDomainConfigResp.Result.HttpsJumpType) + setHttpTypeResp, err := d.sdkClient.SetHttpType(setHttpTypeReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.SetHttpType'") + } else { + d.logger.Logt("已设置通讯协议", setHttpTypeResp) + } + + return &deployer.DeployResult{}, nil +} + +func createSdkClient(accessKeyId, accessKeySecret string) (*jdCdnClient.CdnClient, error) { + clientCredentials := jdCore.NewCredentials(accessKeyId, accessKeySecret) + client := jdCdnClient.NewCdnClient(clientCredentials) + client.SetLogger(jdCore.NewDefaultLogger(jdCore.LogWarn)) + return client, nil +} diff --git a/internal/pkg/core/deployer/providers/jdcloud-cdn/jdcloud_cdn_test.go b/internal/pkg/core/deployer/providers/jdcloud-cdn/jdcloud_cdn_test.go new file mode 100644 index 00000000..2d2f7ed0 --- /dev/null +++ b/internal/pkg/core/deployer/providers/jdcloud-cdn/jdcloud_cdn_test.go @@ -0,0 +1,75 @@ +package jdcloudcdn_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/jdcloud-cdn" +) + +var ( + fInputCertPath string + fInputKeyPath string + fAccessKeyId string + fAccessKeySecret string + fDomain string +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_JDCLOUDCDN_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "") + flag.StringVar(&fAccessKeySecret, argsPrefix+"ACCESSKEYSECRET", "", "") + flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "") +} + +/* +Shell command to run this test: + + go test -v ./jdcloud_cdn_test.go -args \ + --CERTIMATE_DEPLOYER_JDCLOUDCDN_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_JDCLOUDCDN_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_JDCLOUDCDN_ACCESSKEYID="your-access-key-id" \ + --CERTIMATE_DEPLOYER_JDCLOUDCDN_ACCESSKEYSECRET="your-secret-access-key" \ + --CERTIMATE_DEPLOYER_JDCLOUDCDN_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("ACCESSKEYSECRET: %v", fAccessKeySecret), + fmt.Sprintf("DOMAIN: %v", fDomain), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + AccessKeyId: fAccessKeyId, + AccessKeySecret: fAccessKeySecret, + 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) + }) +} diff --git a/internal/pkg/core/deployer/providers/jdcloud-live/jdcloud_live.go b/internal/pkg/core/deployer/providers/jdcloud-live/jdcloud_live.go new file mode 100644 index 00000000..7998fb16 --- /dev/null +++ b/internal/pkg/core/deployer/providers/jdcloud-live/jdcloud_live.go @@ -0,0 +1,75 @@ +package jdcloudlive + +import ( + "context" + + jdCore "github.com/jdcloud-api/jdcloud-sdk-go/core" + jdLiveApi "github.com/jdcloud-api/jdcloud-sdk-go/services/live/apis" + jdLiveClient "github.com/jdcloud-api/jdcloud-sdk-go/services/live/client" + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/logger" +) + +type DeployerConfig struct { + // 京东云 AccessKeyId。 + AccessKeyId string `json:"accessKeyId"` + // 京东云 AccessKeySecret。 + AccessKeySecret string `json:"accessKeySecret"` + // 直播播放域名(不支持泛域名)。 + Domain string `json:"domain"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger logger.Logger + sdkClient *jdLiveClient.LiveClient +} + +var _ deployer.Deployer = (*DeployerProvider)(nil) + +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { + if config == nil { + panic("config is nil") + } + + client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + return &DeployerProvider{ + config: config, + logger: logger.NewNilLogger(), + sdkClient: client, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { + // 设置直播证书 + // REF: https://docs.jdcloud.com/cn/live-video/api/setlivedomaincertificate + setLiveDomainCertificateReq := jdLiveApi.NewSetLiveDomainCertificateRequest(d.config.Domain, "on") + setLiveDomainCertificateReq.SetCert(certPem) + setLiveDomainCertificateReq.SetKey(privkeyPem) + setLiveDomainCertificateResp, err := d.sdkClient.SetLiveDomainCertificate(setLiveDomainCertificateReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'live.SetLiveDomainCertificate'") + } else { + d.logger.Logt("已设置直播证书", setLiveDomainCertificateResp) + } + + return &deployer.DeployResult{}, nil +} + +func createSdkClient(accessKeyId, accessKeySecret string) (*jdLiveClient.LiveClient, error) { + clientCredentials := jdCore.NewCredentials(accessKeyId, accessKeySecret) + client := jdLiveClient.NewLiveClient(clientCredentials) + client.SetLogger(jdCore.NewDefaultLogger(jdCore.LogWarn)) + return client, nil +} diff --git a/internal/pkg/core/deployer/providers/jdcloud-live/jdcloud_live_test.go b/internal/pkg/core/deployer/providers/jdcloud-live/jdcloud_live_test.go new file mode 100644 index 00000000..076202b5 --- /dev/null +++ b/internal/pkg/core/deployer/providers/jdcloud-live/jdcloud_live_test.go @@ -0,0 +1,75 @@ +package jdcloudlive_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/jdcloud-live" +) + +var ( + fInputCertPath string + fInputKeyPath string + fAccessKeyId string + fAccessKeySecret string + fDomain string +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_JDCLOUDLIVE_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "") + flag.StringVar(&fAccessKeySecret, argsPrefix+"ACCESSKEYSECRET", "", "") + flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "") +} + +/* +Shell command to run this test: + + go test -v ./jdcloud_live_test.go -args \ + --CERTIMATE_DEPLOYER_JDCLOUDLIVE_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_JDCLOUDLIVE_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_JDCLOUDLIVE_ACCESSKEYID="your-access-key-id" \ + --CERTIMATE_DEPLOYER_JDCLOUDLIVE_ACCESSKEYSECRET="your-secret-access-key" \ + --CERTIMATE_DEPLOYER_JDCLOUDLIVE_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("ACCESSKEYSECRET: %v", fAccessKeySecret), + fmt.Sprintf("DOMAIN: %v", fDomain), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + AccessKeyId: fAccessKeyId, + AccessKeySecret: fAccessKeySecret, + 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) + }) +} diff --git a/internal/pkg/core/deployer/providers/jdcloud-vod/jdcloud_vod.go b/internal/pkg/core/deployer/providers/jdcloud-vod/jdcloud_vod.go new file mode 100644 index 00000000..b83fd430 --- /dev/null +++ b/internal/pkg/core/deployer/providers/jdcloud-vod/jdcloud_vod.go @@ -0,0 +1,123 @@ +package jdcloudvod + +import ( + "context" + "fmt" + "strconv" + "time" + + jdCore "github.com/jdcloud-api/jdcloud-sdk-go/core" + jdVodApi "github.com/jdcloud-api/jdcloud-sdk-go/services/vod/apis" + jdVodClient "github.com/jdcloud-api/jdcloud-sdk-go/services/vod/client" + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/logger" +) + +type DeployerConfig struct { + // 京东云 AccessKeyId。 + AccessKeyId string `json:"accessKeyId"` + // 京东云 AccessKeySecret。 + AccessKeySecret string `json:"accessKeySecret"` + // 点播加速域名(不支持泛域名)。 + Domain string `json:"domain"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger logger.Logger + sdkClient *jdVodClient.VodClient +} + +var _ deployer.Deployer = (*DeployerProvider)(nil) + +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { + if config == nil { + panic("config is nil") + } + + client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + return &DeployerProvider{ + config: config, + logger: logger.NewNilLogger(), + sdkClient: client, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { + // 查询域名列表 + // REF: https://docs.jdcloud.com/cn/video-on-demand/api/listdomains + var domainId int + listDomainsPageNumber := 1 + listDomainsPageSize := 100 + for { + listDomainsReq := jdVodApi.NewListDomainsRequest() + listDomainsReq.SetPageNumber(1) + listDomainsReq.SetPageSize(100) + listDomainsResp, err := d.sdkClient.ListDomains(listDomainsReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'vod.ListDomains'") + } + + for _, domain := range listDomainsResp.Result.Content { + if domain.Name == d.config.Domain { + domainId, _ = strconv.Atoi(domain.Id) + break + } + } + + if len(listDomainsResp.Result.Content) < listDomainsPageSize { + break + } else { + listDomainsPageNumber++ + } + } + if domainId == 0 { + return nil, xerrors.New("domain not found") + } + + // 查询域名 SSL 配置 + // REF: https://docs.jdcloud.com/cn/video-on-demand/api/gethttpssl + getHttpSslReq := jdVodApi.NewGetHttpSslRequest(domainId) + getHttpSslResp, err := d.sdkClient.GetHttpSsl(getHttpSslReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'vod.GetHttpSsl'") + } else { + d.logger.Logt("已查询到域名 SSL 配置", getHttpSslResp) + } + + // 设置域名 SSL 配置 + // REF: https://docs.jdcloud.com/cn/video-on-demand/api/sethttpssl + setHttpSslReq := jdVodApi.NewSetHttpSslRequest(domainId) + setHttpSslReq.SetTitle(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())) + setHttpSslReq.SetSslCert(certPem) + setHttpSslReq.SetSslKey(privkeyPem) + setHttpSslReq.SetSource("default") + setHttpSslReq.SetJumpType(getHttpSslResp.Result.JumpType) + setHttpSslReq.SetEnabled(true) + setHttpSslResp, err := d.sdkClient.SetHttpSsl(setHttpSslReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'vod.SetHttpSsl'") + } else { + d.logger.Logt("已设置域名 SSL 配置", setHttpSslResp) + } + + return &deployer.DeployResult{}, nil +} + +func createSdkClient(accessKeyId, accessKeySecret string) (*jdVodClient.VodClient, error) { + clientCredentials := jdCore.NewCredentials(accessKeyId, accessKeySecret) + client := jdVodClient.NewVodClient(clientCredentials) + client.SetLogger(jdCore.NewDefaultLogger(jdCore.LogWarn)) + return client, nil +} diff --git a/internal/pkg/core/deployer/providers/jdcloud-vod/jdcloud_vod_test.go b/internal/pkg/core/deployer/providers/jdcloud-vod/jdcloud_vod_test.go new file mode 100644 index 00000000..6046982b --- /dev/null +++ b/internal/pkg/core/deployer/providers/jdcloud-vod/jdcloud_vod_test.go @@ -0,0 +1,75 @@ +package jdcloudvod_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/jdcloud-vod" +) + +var ( + fInputCertPath string + fInputKeyPath string + fAccessKeyId string + fAccessKeySecret string + fDomain string +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_JDCLOUDVOD_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "") + flag.StringVar(&fAccessKeySecret, argsPrefix+"ACCESSKEYSECRET", "", "") + flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "") +} + +/* +Shell command to run this test: + + go test -v ./jdcloud_vod_test.go -args \ + --CERTIMATE_DEPLOYER_JDCLOUDVOD_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_JDCLOUDVOD_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_JDCLOUDVOD_ACCESSKEYID="your-access-key-id" \ + --CERTIMATE_DEPLOYER_JDCLOUDVOD_ACCESSKEYSECRET="your-secret-access-key" \ + --CERTIMATE_DEPLOYER_JDCLOUDVOD_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("ACCESSKEYSECRET: %v", fAccessKeySecret), + fmt.Sprintf("DOMAIN: %v", fDomain), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + AccessKeyId: fAccessKeyId, + AccessKeySecret: fAccessKeySecret, + 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) + }) +} diff --git a/internal/pkg/core/deployer/providers/k8s-secret/k8s_secret.go b/internal/pkg/core/deployer/providers/k8s-secret/k8s_secret.go index 2b7ab8fd..c97e4386 100644 --- a/internal/pkg/core/deployer/providers/k8s-secret/k8s_secret.go +++ b/internal/pkg/core/deployer/providers/k8s-secret/k8s_secret.go @@ -17,7 +17,7 @@ import ( "github.com/usual2970/certimate/internal/pkg/utils/certs" ) -type K8sSecretDeployerConfig struct { +type DeployerConfig struct { // kubeconfig 文件内容。 KubeConfig string `json:"kubeConfig,omitempty"` // Kubernetes 命名空间。 @@ -32,33 +32,30 @@ type K8sSecretDeployerConfig struct { SecretDataKeyForKey string `json:"secretDataKeyForKey,omitempty"` } -type K8sSecretDeployer struct { - config *K8sSecretDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger } -var _ deployer.Deployer = (*K8sSecretDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *K8sSecretDeployerConfig) (*K8sSecretDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *K8sSecretDeployerConfig, logger logger.Logger) (*K8sSecretDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } - if logger == nil { - return nil, errors.New("logger is nil") - } - - return &K8sSecretDeployer{ - logger: logger, + return &DeployerProvider{ + logger: logger.NewNilLogger(), config: config, }, nil } -func (d *K8sSecretDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { if d.config.Namespace == "" { return nil, errors.New("config `namespace` is required") } diff --git a/internal/pkg/core/deployer/providers/k8s-secret/k8s_secret_test.go b/internal/pkg/core/deployer/providers/k8s-secret/k8s_secret_test.go index 913099ec..75f15502 100644 --- a/internal/pkg/core/deployer/providers/k8s-secret/k8s_secret_test.go +++ b/internal/pkg/core/deployer/providers/k8s-secret/k8s_secret_test.go @@ -56,7 +56,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("SECRETDATAKEYFORKEY: %v", fSecretDataKeyForKey), }, "\n")) - deployer, err := provider.New(&provider.K8sSecretDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ Namespace: fNamespace, SecretName: fSecretName, SecretDataKeyForCrt: fSecretDataKeyForCrt, diff --git a/internal/pkg/core/deployer/providers/local/local.go b/internal/pkg/core/deployer/providers/local/local.go index e254caf9..7952f63c 100644 --- a/internal/pkg/core/deployer/providers/local/local.go +++ b/internal/pkg/core/deployer/providers/local/local.go @@ -3,7 +3,6 @@ package local import ( "bytes" "context" - "errors" "fmt" "os/exec" "runtime" @@ -16,7 +15,7 @@ import ( "github.com/usual2970/certimate/internal/pkg/utils/files" ) -type LocalDeployerConfig struct { +type DeployerConfig struct { // Shell 执行环境。 // 零值时默认根据操作系统决定。 ShellEnv ShellEnvType `json:"shellEnv,omitempty"` @@ -44,33 +43,30 @@ type LocalDeployerConfig struct { JksStorepass string `json:"jksStorepass,omitempty"` } -type LocalDeployer struct { - config *LocalDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger } -var _ deployer.Deployer = (*LocalDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *LocalDeployerConfig) (*LocalDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *LocalDeployerConfig, logger logger.Logger) (*LocalDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } - if logger == nil { - return nil, errors.New("logger is nil") - } - - return &LocalDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), }, nil } -func (d *LocalDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // 执行前置命令 if d.config.PreCommand != "" { stdout, stderr, err := execCommand(d.config.ShellEnv, d.config.PreCommand) diff --git a/internal/pkg/core/deployer/providers/local/local_test.go b/internal/pkg/core/deployer/providers/local/local_test.go index 723ddf58..e86ba7e0 100644 --- a/internal/pkg/core/deployer/providers/local/local_test.go +++ b/internal/pkg/core/deployer/providers/local/local_test.go @@ -72,7 +72,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("POSTCOMMAND: %v", fPostCommand), }, "\n")) - deployer, err := provider.New(&provider.LocalDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ OutputFormat: provider.OUTPUT_FORMAT_PEM, OutputCertPath: fOutputCertPath + ".pem", OutputKeyPath: fOutputKeyPath + ".pem", @@ -123,7 +123,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("PFXPASSWORD: %v", fPfxPassword), }, "\n")) - deployer, err := provider.New(&provider.LocalDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ OutputFormat: provider.OUTPUT_FORMAT_PFX, OutputCertPath: fOutputCertPath + ".pfx", PfxPassword: fPfxPassword, @@ -164,7 +164,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("JKSSTOREPASS: %v", fJksStorepass), }, "\n")) - deployer, err := provider.New(&provider.LocalDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ OutputFormat: provider.OUTPUT_FORMAT_JKS, OutputCertPath: fOutputCertPath + ".jks", JksAlias: fJksAlias, diff --git a/internal/pkg/core/deployer/providers/qiniu-cdn/qiniu_cdn.go b/internal/pkg/core/deployer/providers/qiniu-cdn/qiniu_cdn.go index 8fac6459..cdb62b8c 100644 --- a/internal/pkg/core/deployer/providers/qiniu-cdn/qiniu_cdn.go +++ b/internal/pkg/core/deployer/providers/qiniu-cdn/qiniu_cdn.go @@ -2,7 +2,6 @@ import ( "context" - "errors" "strings" xerrors "github.com/pkg/errors" @@ -11,11 +10,11 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/qiniu-sslcert" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/qiniu-sslcert" qiniusdk "github.com/usual2970/certimate/internal/pkg/vendors/qiniu-sdk" ) -type QiniuCDNDeployerConfig struct { +type DeployerConfig struct { // 七牛云 AccessKey。 AccessKey string `json:"accessKey"` // 七牛云 SecretKey。 @@ -24,31 +23,23 @@ type QiniuCDNDeployerConfig struct { Domain string `json:"domain"` } -type QiniuCDNDeployer struct { - config *QiniuCDNDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *qiniusdk.Client sslUploader uploader.Uploader } -var _ deployer.Deployer = (*QiniuCDNDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *QiniuCDNDeployerConfig) (*QiniuCDNDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *QiniuCDNDeployerConfig, logger logger.Logger) (*QiniuCDNDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client := qiniusdk.NewClient(auth.New(config.AccessKey, config.SecretKey)) - uploader, err := uploaderp.New(&uploaderp.QiniuSSLCertUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ AccessKey: config.AccessKey, SecretKey: config.SecretKey, }) @@ -56,15 +47,20 @@ func NewWithLogger(config *QiniuCDNDeployerConfig, logger logger.Logger) (*Qiniu return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &QiniuCDNDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *QiniuCDNDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // 上传证书到 CDN upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { diff --git a/internal/pkg/core/deployer/providers/qiniu-cdn/qiniu_cdn_test.go b/internal/pkg/core/deployer/providers/qiniu-cdn/qiniu_cdn_test.go index 85ca8316..eff0ab48 100644 --- a/internal/pkg/core/deployer/providers/qiniu-cdn/qiniu_cdn_test.go +++ b/internal/pkg/core/deployer/providers/qiniu-cdn/qiniu_cdn_test.go @@ -52,7 +52,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) - deployer, err := provider.New(&provider.QiniuCDNDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKey: fAccessKey, SecretKey: fSecretKey, Domain: fDomain, diff --git a/internal/pkg/core/deployer/providers/qiniu-pili/qiniu_pili.go b/internal/pkg/core/deployer/providers/qiniu-pili/qiniu_pili.go index 4530071c..b9121694 100644 --- a/internal/pkg/core/deployer/providers/qiniu-pili/qiniu_pili.go +++ b/internal/pkg/core/deployer/providers/qiniu-pili/qiniu_pili.go @@ -2,7 +2,6 @@ import ( "context" - "errors" xerrors "github.com/pkg/errors" "github.com/qiniu/go-sdk/v7/pili" @@ -10,10 +9,10 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/qiniu-sslcert" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/qiniu-sslcert" ) -type QiniuPiliDeployerConfig struct { +type DeployerConfig struct { // 七牛云 AccessKey。 AccessKey string `json:"accessKey"` // 七牛云 SecretKey。 @@ -24,31 +23,23 @@ type QiniuPiliDeployerConfig struct { Domain string `json:"domain"` } -type QiniuPiliDeployer struct { - config *QiniuPiliDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *pili.Manager sslUploader uploader.Uploader } -var _ deployer.Deployer = (*QiniuPiliDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *QiniuPiliDeployerConfig) (*QiniuPiliDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *QiniuPiliDeployerConfig, logger logger.Logger) (*QiniuPiliDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } manager := pili.NewManager(pili.ManagerConfig{AccessKey: config.AccessKey, SecretKey: config.SecretKey}) - uploader, err := uploaderp.New(&uploaderp.QiniuSSLCertUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ AccessKey: config.AccessKey, SecretKey: config.SecretKey, }) @@ -56,15 +47,20 @@ func NewWithLogger(config *QiniuPiliDeployerConfig, logger logger.Logger) (*Qini return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &QiniuPiliDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: manager, sslUploader: uploader, }, nil } -func (d *QiniuPiliDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // 上传证书到 CDN upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { diff --git a/internal/pkg/core/deployer/providers/qiniu-pili/qiniu_pili_test.go b/internal/pkg/core/deployer/providers/qiniu-pili/qiniu_pili_test.go index 06ef47e4..1d307dda 100644 --- a/internal/pkg/core/deployer/providers/qiniu-pili/qiniu_pili_test.go +++ b/internal/pkg/core/deployer/providers/qiniu-pili/qiniu_pili_test.go @@ -56,7 +56,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) - deployer, err := provider.New(&provider.QiniuPiliDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKey: fAccessKey, SecretKey: fSecretKey, Domain: fDomain, diff --git a/internal/pkg/core/deployer/providers/safeline/consts.go b/internal/pkg/core/deployer/providers/safeline/consts.go new file mode 100644 index 00000000..a19e3866 --- /dev/null +++ b/internal/pkg/core/deployer/providers/safeline/consts.go @@ -0,0 +1,8 @@ +package safeline + +type ResourceType string + +const ( + // 资源类型:替换指定证书。 + RESOURCE_TYPE_CERTIFICATE = ResourceType("certificate") +) diff --git a/internal/pkg/core/deployer/providers/safeline/safeline.go b/internal/pkg/core/deployer/providers/safeline/safeline.go new file mode 100644 index 00000000..3b4006c4 --- /dev/null +++ b/internal/pkg/core/deployer/providers/safeline/safeline.go @@ -0,0 +1,108 @@ +package safeline + +import ( + "context" + "errors" + "fmt" + "net/url" + + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/logger" + safelinesdk "github.com/usual2970/certimate/internal/pkg/vendors/safeline-sdk" +) + +type DeployerConfig struct { + // 雷池 URL。 + ApiUrl string `json:"apiUrl"` + // 雷池 API Token。 + ApiToken string `json:"apiToken"` + // 部署资源类型。 + ResourceType ResourceType `json:"resourceType"` + // 证书 ID。 + // 部署资源类型为 [RESOURCE_TYPE_CERTIFICATE] 时必填。 + CertificateId int32 `json:"certificateId,omitempty"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger logger.Logger + sdkClient *safelinesdk.Client +} + +var _ deployer.Deployer = (*DeployerProvider)(nil) + +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { + if config == nil { + panic("config is nil") + } + + client, err := createSdkClient(config.ApiUrl, config.ApiToken) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk clients") + } + + return &DeployerProvider{ + config: config, + logger: logger.NewNilLogger(), + sdkClient: client, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + 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 == 0 { + return errors.New("config `certificateId` is required") + } + + // 更新证书 + updateCertificateReq := &safelinesdk.UpdateCertificateRequest{ + Id: d.config.CertificateId, + Type: 2, + Manual: &safelinesdk.UpdateCertificateRequestBodyManul{ + Crt: certPem, + Key: privkeyPem, + }, + } + updateCertificateResp, err := d.sdkClient.UpdateCertificate(updateCertificateReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'safeline.UpdateCertificate'") + } else { + d.logger.Logt("已更新证书", updateCertificateResp) + } + + return nil +} + +func createSdkClient(apiUrl, apiToken string) (*safelinesdk.Client, error) { + if _, err := url.Parse(apiUrl); err != nil { + return nil, errors.New("invalid safeline api url") + } + + if apiToken == "" { + return nil, errors.New("invalid safeline api token") + } + + client := safelinesdk.NewClient(apiUrl, apiToken) + return client, nil +} diff --git a/internal/pkg/core/deployer/providers/safeline/safeline_test.go b/internal/pkg/core/deployer/providers/safeline/safeline_test.go new file mode 100644 index 00000000..0d7f2223 --- /dev/null +++ b/internal/pkg/core/deployer/providers/safeline/safeline_test.go @@ -0,0 +1,76 @@ +package safeline_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/safeline" +) + +var ( + fInputCertPath string + fInputKeyPath string + fApiUrl string + fApiToken string + fCertificateId int +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_SAFELINE_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fApiUrl, argsPrefix+"APIURL", "", "") + flag.StringVar(&fApiToken, argsPrefix+"APITOKEN", "", "") + flag.IntVar(&fCertificateId, argsPrefix+"CERTIFICATEID", 0, "") +} + +/* +Shell command to run this test: + + go test -v ./safeline_test.go -args \ + --CERTIMATE_DEPLOYER_SAFELINE_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_SAFELINE_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_SAFELINE_APIURL="http://127.0.0.1:9443" \ + --CERTIMATE_DEPLOYER_SAFELINE_APITOKEN="your-api-token" \ + --CERTIMATE_DEPLOYER_SAFELINE_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("APIURL: %v", fApiUrl), + fmt.Sprintf("APITOKEN: %v", fApiToken), + fmt.Sprintf("CERTIFICATEID: %v", fCertificateId), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + ApiUrl: fApiUrl, + ApiToken: fApiToken, + ResourceType: provider.ResourceType("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) + }) +} diff --git a/internal/pkg/core/deployer/providers/ssh/ssh.go b/internal/pkg/core/deployer/providers/ssh/ssh.go index 20ea348a..a1617327 100644 --- a/internal/pkg/core/deployer/providers/ssh/ssh.go +++ b/internal/pkg/core/deployer/providers/ssh/ssh.go @@ -3,7 +3,6 @@ package ssh import ( "bytes" "context" - "errors" "fmt" "os" "path/filepath" @@ -18,7 +17,7 @@ import ( "github.com/usual2970/certimate/internal/pkg/utils/certs" ) -type SshDeployerConfig struct { +type DeployerConfig struct { // SSH 主机。 // 零值时默认为 "localhost"。 SshHost string `json:"sshHost,omitempty"` @@ -59,33 +58,30 @@ type SshDeployerConfig struct { JksStorepass string `json:"jksStorepass,omitempty"` } -type SshDeployer struct { - config *SshDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger } -var _ deployer.Deployer = (*SshDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *SshDeployerConfig) (*SshDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *SshDeployerConfig, logger logger.Logger) (*SshDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } - if logger == nil { - return nil, errors.New("logger is nil") - } - - return &SshDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), }, nil } -func (d *SshDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // 连接 client, err := createSshClient( d.config.SshHost, diff --git a/internal/pkg/core/deployer/providers/ssh/ssh_test.go b/internal/pkg/core/deployer/providers/ssh/ssh_test.go index 4221378e..8312d680 100644 --- a/internal/pkg/core/deployer/providers/ssh/ssh_test.go +++ b/internal/pkg/core/deployer/providers/ssh/ssh_test.go @@ -64,7 +64,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("OUTPUTKEYPATH: %v", fOutputKeyPath), }, "\n")) - deployer, err := provider.New(&provider.SshDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ SshHost: fSshHost, SshPort: int32(fSshPort), SshUsername: fSshUsername, diff --git a/internal/pkg/core/deployer/providers/tencentcloud-cdn/tencentcloud_cdn.go b/internal/pkg/core/deployer/providers/tencentcloud-cdn/tencentcloud_cdn.go index 61418845..1784354d 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-cdn/tencentcloud_cdn.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-cdn/tencentcloud_cdn.go @@ -2,7 +2,6 @@ import ( "context" - "errors" "strings" xerrors "github.com/pkg/errors" @@ -15,10 +14,10 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl" ) -type TencentCloudCDNDeployerConfig struct { +type DeployerConfig struct { // 腾讯云 SecretId。 SecretId string `json:"secretId"` // 腾讯云 SecretKey。 @@ -27,31 +26,23 @@ type TencentCloudCDNDeployerConfig struct { Domain string `json:"domain"` } -type TencentCloudCDNDeployer struct { - config *TencentCloudCDNDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClients *wSdkClients sslUploader uploader.Uploader } -var _ deployer.Deployer = (*TencentCloudCDNDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) type wSdkClients struct { ssl *tcSsl.Client cdn *tcCdn.Client } -func New(config *TencentCloudCDNDeployerConfig) (*TencentCloudCDNDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *TencentCloudCDNDeployerConfig, logger logger.Logger) (*TencentCloudCDNDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } clients, err := createSdkClients(config.SecretId, config.SecretKey) @@ -59,7 +50,7 @@ func NewWithLogger(config *TencentCloudCDNDeployerConfig, logger logger.Logger) return nil, xerrors.Wrap(err, "failed to create sdk clients") } - uploader, err := uploaderp.New(&uploaderp.TencentCloudSSLUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ SecretId: config.SecretId, SecretKey: config.SecretKey, }) @@ -67,15 +58,20 @@ func NewWithLogger(config *TencentCloudCDNDeployerConfig, logger logger.Logger) return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &TencentCloudCDNDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClients: clients, sslUploader: uploader, }, nil } -func (d *TencentCloudCDNDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // 上传证书到 SSL upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { @@ -135,7 +131,7 @@ func (d *TencentCloudCDNDeployer) Deploy(ctx context.Context, certPem string, pr return &deployer.DeployResult{}, nil } -func (d *TencentCloudCDNDeployer) getDomainsByCertificateId(cloudCertId string) ([]string, error) { +func (d *DeployerProvider) getDomainsByCertificateId(cloudCertId string) ([]string, error) { // 获取证书中的可用域名 // REF: https://cloud.tencent.com/document/product/228/42491 describeCertDomainsReq := tcCdn.NewDescribeCertDomainsRequest() @@ -156,7 +152,7 @@ func (d *TencentCloudCDNDeployer) getDomainsByCertificateId(cloudCertId string) return domains, nil } -func (d *TencentCloudCDNDeployer) getDeployedDomainsByCertificateId(cloudCertId string) ([]string, error) { +func (d *DeployerProvider) getDeployedDomainsByCertificateId(cloudCertId string) ([]string, error) { // 根据证书查询关联 CDN 域名 // REF: https://cloud.tencent.com/document/product/400/62674 describeDeployedResourcesReq := tcSsl.NewDescribeDeployedResourcesRequest() diff --git a/internal/pkg/core/deployer/providers/tencentcloud-cdn/tencentcloud_cdn_test.go b/internal/pkg/core/deployer/providers/tencentcloud-cdn/tencentcloud_cdn_test.go index 088251b1..0361e17b 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-cdn/tencentcloud_cdn_test.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-cdn/tencentcloud_cdn_test.go @@ -52,7 +52,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) - deployer, err := provider.New(&provider.TencentCloudCDNDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ SecretId: fSecretId, SecretKey: fSecretKey, Domain: fDomain, diff --git a/internal/pkg/core/deployer/providers/tencentcloud-clb/consts.go b/internal/pkg/core/deployer/providers/tencentcloud-clb/consts.go new file mode 100644 index 00000000..7d72d5d3 --- /dev/null +++ b/internal/pkg/core/deployer/providers/tencentcloud-clb/consts.go @@ -0,0 +1,14 @@ +package tencentcloudclb + +type ResourceType string + +const ( + // 资源类型:通过 SSL 服务部署到云资源实例。 + RESOURCE_TYPE_VIA_SSLDEPLOY = ResourceType("ssl-deploy") + // 资源类型:部署到指定负载均衡器。 + RESOURCE_TYPE_LOADBALANCER = ResourceType("loadbalancer") + // 资源类型:部署到指定监听器。 + RESOURCE_TYPE_LISTENER = ResourceType("listener") + // 资源类型:部署到指定转发规则域名。 + RESOURCE_TYPE_RULEDOMAIN = ResourceType("ruledomain") +) diff --git a/internal/pkg/core/deployer/providers/tencentcloud-clb/defines.go b/internal/pkg/core/deployer/providers/tencentcloud-clb/defines.go deleted file mode 100644 index 7e7eace9..00000000 --- a/internal/pkg/core/deployer/providers/tencentcloud-clb/defines.go +++ /dev/null @@ -1,14 +0,0 @@ -package tencentcloudclb - -type DeployResourceType string - -const ( - // 资源类型:通过 SSL 服务部署到云资源实例。 - DEPLOY_RESOURCE_VIA_SSLDEPLOY = DeployResourceType("ssl-deploy") - // 资源类型:部署到指定负载均衡器。 - DEPLOY_RESOURCE_LOADBALANCER = DeployResourceType("loadbalancer") - // 资源类型:部署到指定监听器。 - DEPLOY_RESOURCE_LISTENER = DeployResourceType("listener") - // 资源类型:部署到指定转发规则域名。 - DEPLOY_RESOURCE_RULEDOMAIN = DeployResourceType("ruledomain") -) diff --git a/internal/pkg/core/deployer/providers/tencentcloud-clb/tencentcloud_clb.go b/internal/pkg/core/deployer/providers/tencentcloud-clb/tencentcloud_clb.go index e6982817..521f3e34 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-clb/tencentcloud_clb.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-clb/tencentcloud_clb.go @@ -14,10 +14,10 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl" ) -type TencentCloudCLBDeployerConfig struct { +type DeployerConfig struct { // 腾讯云 SecretId。 SecretId string `json:"secretId"` // 腾讯云 SecretKey。 @@ -25,43 +25,35 @@ type TencentCloudCLBDeployerConfig struct { // 腾讯云地域。 Region string `json:"region"` // 部署资源类型。 - ResourceType DeployResourceType `json:"resourceType"` + ResourceType ResourceType `json:"resourceType"` // 负载均衡器 ID。 - // 部署资源类型为 [DEPLOY_RESOURCE_SSLDEPLOY]、[DEPLOY_RESOURCE_LOADBALANCER]、[DEPLOY_RESOURCE_RULEDOMAIN] 时必填。 + // 部署资源类型为 [RESOURCE_TYPE_SSLDEPLOY]、[RESOURCE_TYPE_LOADBALANCER]、[RESOURCE_TYPE_RULEDOMAIN] 时必填。 LoadbalancerId string `json:"loadbalancerId,omitempty"` // 负载均衡监听 ID。 - // 部署资源类型为 [DEPLOY_RESOURCE_SSLDEPLOY]、[DEPLOY_RESOURCE_LOADBALANCER]、[DEPLOY_RESOURCE_LISTENER]、[DEPLOY_RESOURCE_RULEDOMAIN] 时必填。 + // 部署资源类型为 [RESOURCE_TYPE_SSLDEPLOY]、[RESOURCE_TYPE_LOADBALANCER]、[RESOURCE_TYPE_LISTENER]、[RESOURCE_TYPE_RULEDOMAIN] 时必填。 ListenerId string `json:"listenerId,omitempty"` // SNI 域名或七层转发规则域名(支持泛域名)。 - // 部署资源类型为 [DEPLOY_RESOURCE_SSLDEPLOY] 时选填;部署资源类型为 [DEPLOY_RESOURCE_RULEDOMAIN] 时必填。 + // 部署资源类型为 [RESOURCE_TYPE_SSLDEPLOY] 时选填;部署资源类型为 [RESOURCE_TYPE_RULEDOMAIN] 时必填。 Domain string `json:"domain,omitempty"` } -type TencentCloudCLBDeployer struct { - config *TencentCloudCLBDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClients *wSdkClients sslUploader uploader.Uploader } -var _ deployer.Deployer = (*TencentCloudCLBDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) type wSdkClients struct { ssl *tcSsl.Client clb *tcClb.Client } -func New(config *TencentCloudCLBDeployerConfig) (*TencentCloudCLBDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *TencentCloudCLBDeployerConfig, logger logger.Logger) (*TencentCloudCLBDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } clients, err := createSdkClients(config.SecretId, config.SecretKey, config.Region) @@ -69,7 +61,7 @@ func NewWithLogger(config *TencentCloudCLBDeployerConfig, logger logger.Logger) return nil, xerrors.Wrap(err, "failed to create sdk clients") } - uploader, err := uploaderp.New(&uploaderp.TencentCloudSSLUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ SecretId: config.SecretId, SecretKey: config.SecretKey, }) @@ -77,15 +69,20 @@ func NewWithLogger(config *TencentCloudCLBDeployerConfig, logger logger.Logger) return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &TencentCloudCLBDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClients: clients, sslUploader: uploader, }, nil } -func (d *TencentCloudCLBDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // 上传证书到 SSL upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { @@ -96,22 +93,22 @@ func (d *TencentCloudCLBDeployer) Deploy(ctx context.Context, certPem string, pr // 根据部署资源类型决定部署方式 switch d.config.ResourceType { - case DEPLOY_RESOURCE_VIA_SSLDEPLOY: + case RESOURCE_TYPE_VIA_SSLDEPLOY: if err := d.deployViaSslService(ctx, upres.CertId); err != nil { return nil, err } - case DEPLOY_RESOURCE_LOADBALANCER: + case RESOURCE_TYPE_LOADBALANCER: if err := d.deployToLoadbalancer(ctx, upres.CertId); err != nil { return nil, err } - case DEPLOY_RESOURCE_LISTENER: + case RESOURCE_TYPE_LISTENER: if err := d.deployToListener(ctx, upres.CertId); err != nil { return nil, err } - case DEPLOY_RESOURCE_RULEDOMAIN: + case RESOURCE_TYPE_RULEDOMAIN: if err := d.deployToRuleDomain(ctx, upres.CertId); err != nil { return nil, err } @@ -123,7 +120,7 @@ func (d *TencentCloudCLBDeployer) Deploy(ctx context.Context, certPem string, pr return &deployer.DeployResult{}, nil } -func (d *TencentCloudCLBDeployer) deployViaSslService(ctx context.Context, cloudCertId string) error { +func (d *DeployerProvider) deployViaSslService(ctx context.Context, cloudCertId string) error { if d.config.LoadbalancerId == "" { return errors.New("config `loadbalancerId` is required") } @@ -141,7 +138,7 @@ func (d *TencentCloudCLBDeployer) deployViaSslService(ctx context.Context, cloud // 未指定 SNI,只需部署到监听器 deployCertificateInstanceReq.InstanceIdList = common.StringPtrs([]string{fmt.Sprintf("%s|%s", d.config.LoadbalancerId, d.config.ListenerId)}) } else { - // 指定 SNI,需部署到域名(支持泛域名) + // 指定 SNI,需部署到域名 deployCertificateInstanceReq.InstanceIdList = common.StringPtrs([]string{fmt.Sprintf("%s|%s|%s", d.config.LoadbalancerId, d.config.ListenerId, d.config.Domain)}) } deployCertificateInstanceResp, err := d.sdkClients.ssl.DeployCertificateInstance(deployCertificateInstanceReq) @@ -154,7 +151,7 @@ func (d *TencentCloudCLBDeployer) deployViaSslService(ctx context.Context, cloud return nil } -func (d *TencentCloudCLBDeployer) deployToLoadbalancer(ctx context.Context, cloudCertId string) error { +func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId string) error { if d.config.LoadbalancerId == "" { return errors.New("config `loadbalancerId` is required") } @@ -201,7 +198,7 @@ func (d *TencentCloudCLBDeployer) deployToLoadbalancer(ctx context.Context, clou return nil } -func (d *TencentCloudCLBDeployer) deployToListener(ctx context.Context, cloudCertId string) error { +func (d *DeployerProvider) deployToListener(ctx context.Context, cloudCertId string) error { if d.config.LoadbalancerId == "" { return errors.New("config `loadbalancerId` is required") } @@ -217,7 +214,7 @@ func (d *TencentCloudCLBDeployer) deployToListener(ctx context.Context, cloudCer return nil } -func (d *TencentCloudCLBDeployer) deployToRuleDomain(ctx context.Context, cloudCertId string) error { +func (d *DeployerProvider) deployToRuleDomain(ctx context.Context, cloudCertId string) error { if d.config.LoadbalancerId == "" { return errors.New("config `loadbalancerId` is required") } @@ -248,7 +245,7 @@ func (d *TencentCloudCLBDeployer) deployToRuleDomain(ctx context.Context, cloudC return nil } -func (d *TencentCloudCLBDeployer) modifyListenerCertificate(ctx context.Context, cloudLoadbalancerId, cloudListenerId, cloudCertId string) error { +func (d *DeployerProvider) modifyListenerCertificate(ctx context.Context, cloudLoadbalancerId, cloudListenerId, cloudCertId string) error { // 查询监听器列表 // REF: https://cloud.tencent.com/document/api/214/30686 describeListenersReq := tcClb.NewDescribeListenersRequest() diff --git a/internal/pkg/core/deployer/providers/tencentcloud-clb/tencentcloud_clb_test.go b/internal/pkg/core/deployer/providers/tencentcloud-clb/tencentcloud_clb_test.go index 74a1e23e..0aeb1e7c 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-clb/tencentcloud_clb_test.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-clb/tencentcloud_clb_test.go @@ -64,11 +64,11 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) - deployer, err := provider.New(&provider.TencentCloudCLBDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ SecretId: fSecretId, SecretKey: fSecretKey, Region: fRegion, - ResourceType: provider.DEPLOY_RESOURCE_VIA_SSLDEPLOY, + ResourceType: provider.RESOURCE_TYPE_VIA_SSLDEPLOY, LoadbalancerId: fLoadbalancerId, ListenerId: fListenerId, Domain: fDomain, @@ -100,11 +100,11 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("LOADBALANCERID: %v", fLoadbalancerId), }, "\n")) - deployer, err := provider.New(&provider.TencentCloudCLBDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ SecretId: fSecretId, SecretKey: fSecretKey, Region: fRegion, - ResourceType: provider.DEPLOY_RESOURCE_LOADBALANCER, + ResourceType: provider.RESOURCE_TYPE_LOADBALANCER, LoadbalancerId: fLoadbalancerId, }) if err != nil { @@ -135,11 +135,11 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("LISTENERID: %v", fListenerId), }, "\n")) - deployer, err := provider.New(&provider.TencentCloudCLBDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ SecretId: fSecretId, SecretKey: fSecretKey, Region: fRegion, - ResourceType: provider.DEPLOY_RESOURCE_LISTENER, + ResourceType: provider.RESOURCE_TYPE_LISTENER, LoadbalancerId: fLoadbalancerId, ListenerId: fListenerId, }) @@ -172,11 +172,11 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) - deployer, err := provider.New(&provider.TencentCloudCLBDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ SecretId: fSecretId, SecretKey: fSecretKey, Region: fRegion, - ResourceType: provider.DEPLOY_RESOURCE_RULEDOMAIN, + ResourceType: provider.RESOURCE_TYPE_RULEDOMAIN, LoadbalancerId: fLoadbalancerId, ListenerId: fListenerId, Domain: fDomain, diff --git a/internal/pkg/core/deployer/providers/tencentcloud-cos/tencentcloud_cos.go b/internal/pkg/core/deployer/providers/tencentcloud-cos/tencentcloud_cos.go index c2af84fb..d3b3f881 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-cos/tencentcloud_cos.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-cos/tencentcloud_cos.go @@ -1,4 +1,4 @@ -package tencentcloudcdn +package tencentcloudcos import ( "context" @@ -13,10 +13,10 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl" ) -type TencentCloudCOSDeployerConfig struct { +type DeployerConfig struct { // 腾讯云 SecretId。 SecretId string `json:"secretId"` // 腾讯云 SecretKey。 @@ -29,26 +29,18 @@ type TencentCloudCOSDeployerConfig struct { Domain string `json:"domain"` } -type TencentCloudCOSDeployer struct { - config *TencentCloudCOSDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *tcSsl.Client sslUploader uploader.Uploader } -var _ deployer.Deployer = (*TencentCloudCOSDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *TencentCloudCOSDeployerConfig) (*TencentCloudCOSDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *TencentCloudCOSDeployerConfig, logger logger.Logger) (*TencentCloudCOSDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client, err := createSdkClient(config.SecretId, config.SecretKey, config.Region) @@ -56,7 +48,7 @@ func NewWithLogger(config *TencentCloudCOSDeployerConfig, logger logger.Logger) return nil, xerrors.Wrap(err, "failed to create sdk clients") } - uploader, err := uploaderp.New(&uploaderp.TencentCloudSSLUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ SecretId: config.SecretId, SecretKey: config.SecretKey, }) @@ -64,15 +56,20 @@ func NewWithLogger(config *TencentCloudCOSDeployerConfig, logger logger.Logger) return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &TencentCloudCOSDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *TencentCloudCOSDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { if d.config.Bucket == "" { return nil, errors.New("config `bucket` is required") } diff --git a/internal/pkg/core/deployer/providers/tencentcloud-cos/tencentcloud_cos_test.go b/internal/pkg/core/deployer/providers/tencentcloud-cos/tencentcloud_cos_test.go index d58e4f50..ab29a893 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-cos/tencentcloud_cos_test.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-cos/tencentcloud_cos_test.go @@ -1,4 +1,4 @@ -package tencentcloudcdn_test +package tencentcloudcos_test import ( "context" @@ -60,7 +60,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) - deployer, err := provider.New(&provider.TencentCloudCOSDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ SecretId: fSecretId, SecretKey: fSecretKey, Region: fRegion, diff --git a/internal/pkg/core/deployer/providers/tencentcloud-css/tencentcloud_css.go b/internal/pkg/core/deployer/providers/tencentcloud-css/tencentcloud_css.go index 31057017..ad5dbed5 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-css/tencentcloud_css.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-css/tencentcloud_css.go @@ -2,7 +2,6 @@ import ( "context" - "errors" xerrors "github.com/pkg/errors" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" @@ -12,10 +11,10 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl" ) -type TencentCloudCSSDeployerConfig struct { +type DeployerConfig struct { // 腾讯云 SecretId。 SecretId string `json:"secretId"` // 腾讯云 SecretKey。 @@ -24,26 +23,18 @@ type TencentCloudCSSDeployerConfig struct { Domain string `json:"domain"` } -type TencentCloudCSSDeployer struct { - config *TencentCloudCSSDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *tcLive.Client sslUploader uploader.Uploader } -var _ deployer.Deployer = (*TencentCloudCSSDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *TencentCloudCSSDeployerConfig) (*TencentCloudCSSDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *TencentCloudCSSDeployerConfig, logger logger.Logger) (*TencentCloudCSSDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client, err := createSdkClient(config.SecretId, config.SecretKey) @@ -51,7 +42,7 @@ func NewWithLogger(config *TencentCloudCSSDeployerConfig, logger logger.Logger) return nil, xerrors.Wrap(err, "failed to create sdk client") } - uploader, err := uploaderp.New(&uploaderp.TencentCloudSSLUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ SecretId: config.SecretId, SecretKey: config.SecretKey, }) @@ -59,15 +50,20 @@ func NewWithLogger(config *TencentCloudCSSDeployerConfig, logger logger.Logger) return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &TencentCloudCSSDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *TencentCloudCSSDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // 上传证书到 SSL upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { diff --git a/internal/pkg/core/deployer/providers/tencentcloud-css/tencentcloud_css_test.go b/internal/pkg/core/deployer/providers/tencentcloud-css/tencentcloud_css_test.go index 4efe7bba..92127b3b 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-css/tencentcloud_css_test.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-css/tencentcloud_css_test.go @@ -52,7 +52,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) - deployer, err := provider.New(&provider.TencentCloudCSSDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ SecretId: fSecretId, SecretKey: fSecretKey, Domain: fDomain, diff --git a/internal/pkg/core/deployer/providers/tencentcloud-ecdn/tencentcloud_ecdn.go b/internal/pkg/core/deployer/providers/tencentcloud-ecdn/tencentcloud_ecdn.go index 4cddbc59..e9438898 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-ecdn/tencentcloud_ecdn.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-ecdn/tencentcloud_ecdn.go @@ -2,7 +2,6 @@ import ( "context" - "errors" "strings" xerrors "github.com/pkg/errors" @@ -14,10 +13,10 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl" ) -type TencentCloudECDNDeployerConfig struct { +type DeployerConfig struct { // 腾讯云 SecretId。 SecretId string `json:"secretId"` // 腾讯云 SecretKey。 @@ -26,31 +25,23 @@ type TencentCloudECDNDeployerConfig struct { Domain string `json:"domain"` } -type TencentCloudECDNDeployer struct { - config *TencentCloudECDNDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClients *wSdkClients sslUploader uploader.Uploader } -var _ deployer.Deployer = (*TencentCloudECDNDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) type wSdkClients struct { ssl *tcSsl.Client cdn *tcCdn.Client } -func New(config *TencentCloudECDNDeployerConfig) (*TencentCloudECDNDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *TencentCloudECDNDeployerConfig, logger logger.Logger) (*TencentCloudECDNDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } clients, err := createSdkClients(config.SecretId, config.SecretKey) @@ -58,7 +49,7 @@ func NewWithLogger(config *TencentCloudECDNDeployerConfig, logger logger.Logger) return nil, xerrors.Wrap(err, "failed to create sdk clients") } - uploader, err := uploaderp.New(&uploaderp.TencentCloudSSLUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ SecretId: config.SecretId, SecretKey: config.SecretKey, }) @@ -66,15 +57,20 @@ func NewWithLogger(config *TencentCloudECDNDeployerConfig, logger logger.Logger) return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &TencentCloudECDNDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClients: clients, sslUploader: uploader, }, nil } -func (d *TencentCloudECDNDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // 上传证书到 SSL upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { @@ -118,7 +114,7 @@ func (d *TencentCloudECDNDeployer) Deploy(ctx context.Context, certPem string, p return &deployer.DeployResult{}, nil } -func (d *TencentCloudECDNDeployer) getDomainsByCertificateId(cloudCertId string) ([]string, error) { +func (d *DeployerProvider) getDomainsByCertificateId(cloudCertId string) ([]string, error) { // 获取证书中的可用域名 // REF: https://cloud.tencent.com/document/product/228/42491 describeCertDomainsReq := tcCdn.NewDescribeCertDomainsRequest() diff --git a/internal/pkg/core/deployer/providers/tencentcloud-ecdn/tencentcloud_ecdn_test.go b/internal/pkg/core/deployer/providers/tencentcloud-ecdn/tencentcloud_ecdn_test.go index 764aa5fb..da03a7ab 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-ecdn/tencentcloud_ecdn_test.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-ecdn/tencentcloud_ecdn_test.go @@ -52,7 +52,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) - deployer, err := provider.New(&provider.TencentCloudECDNDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ SecretId: fSecretId, SecretKey: fSecretKey, Domain: fDomain, diff --git a/internal/pkg/core/deployer/providers/tencentcloud-eo/tencentcloud_eo.go b/internal/pkg/core/deployer/providers/tencentcloud-eo/tencentcloud_eo.go index 2de4dcc5..99669038 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-eo/tencentcloud_eo.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-eo/tencentcloud_eo.go @@ -1,4 +1,4 @@ -package tencentcloudeteo +package tencentcloudeo import ( "context" @@ -13,10 +13,10 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl" ) -type TencentCloudEODeployerConfig struct { +type DeployerConfig struct { // 腾讯云 SecretId。 SecretId string `json:"secretId"` // 腾讯云 SecretKey。 @@ -27,31 +27,23 @@ type TencentCloudEODeployerConfig struct { Domain string `json:"domain"` } -type TencentCloudEODeployer struct { - config *TencentCloudEODeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClients *wSdkClients sslUploader uploader.Uploader } -var _ deployer.Deployer = (*TencentCloudEODeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) type wSdkClients struct { ssl *tcSsl.Client teo *tcTeo.Client } -func New(config *TencentCloudEODeployerConfig) (*TencentCloudEODeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *TencentCloudEODeployerConfig, logger logger.Logger) (*TencentCloudEODeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } clients, err := createSdkClients(config.SecretId, config.SecretKey) @@ -59,7 +51,7 @@ func NewWithLogger(config *TencentCloudEODeployerConfig, logger logger.Logger) ( return nil, xerrors.Wrap(err, "failed to create sdk clients") } - uploader, err := uploaderp.New(&uploaderp.TencentCloudSSLUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ SecretId: config.SecretId, SecretKey: config.SecretKey, }) @@ -67,15 +59,20 @@ func NewWithLogger(config *TencentCloudEODeployerConfig, logger logger.Logger) ( return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &TencentCloudEODeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClients: clients, sslUploader: uploader, }, nil } -func (d *TencentCloudEODeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { if d.config.ZoneId == "" { return nil, errors.New("config `zoneId` is required") } diff --git a/internal/pkg/core/deployer/providers/tencentcloud-eo/tencentcloud_eo_test.go b/internal/pkg/core/deployer/providers/tencentcloud-eo/tencentcloud_eo_test.go index bc5280f7..8e5b70fe 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-eo/tencentcloud_eo_test.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-eo/tencentcloud_eo_test.go @@ -1,4 +1,4 @@ -package tencentcloudeteo_test +package tencentcloudeo_test import ( "context" @@ -56,7 +56,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) - deployer, err := provider.New(&provider.TencentCloudEODeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ SecretId: fSecretId, SecretKey: fSecretKey, ZoneId: fZoneId, diff --git a/internal/pkg/core/deployer/providers/tencentcloud-ssl-deploy/tencentcloud_ssl_deploy.go b/internal/pkg/core/deployer/providers/tencentcloud-ssl-deploy/tencentcloud_ssl_deploy.go index 37c00ea4..f943ad6e 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-ssl-deploy/tencentcloud_ssl_deploy.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-ssl-deploy/tencentcloud_ssl_deploy.go @@ -14,10 +14,10 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl" ) -type TencentCloudSSLDeployDeployerConfig struct { +type DeployerConfig struct { // 腾讯云 SecretId。 SecretId string `json:"secretId"` // 腾讯云 SecretKey。 @@ -30,26 +30,18 @@ type TencentCloudSSLDeployDeployerConfig struct { ResourceIds []string `json:"resourceIds"` } -type TencentCloudSSLDeployDeployer struct { - config *TencentCloudSSLDeployDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *tcSsl.Client sslUploader uploader.Uploader } -var _ deployer.Deployer = (*TencentCloudSSLDeployDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *TencentCloudSSLDeployDeployerConfig) (*TencentCloudSSLDeployDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *TencentCloudSSLDeployDeployerConfig, logger logger.Logger) (*TencentCloudSSLDeployDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client, err := createSdkClient(config.SecretId, config.SecretKey, config.Region) @@ -57,7 +49,7 @@ func NewWithLogger(config *TencentCloudSSLDeployDeployerConfig, logger logger.Lo return nil, xerrors.Wrap(err, "failed to create sdk client") } - uploader, err := uploaderp.New(&uploaderp.TencentCloudSSLUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ SecretId: config.SecretId, SecretKey: config.SecretKey, }) @@ -65,15 +57,20 @@ func NewWithLogger(config *TencentCloudSSLDeployDeployerConfig, logger logger.Lo return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &TencentCloudSSLDeployDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *TencentCloudSSLDeployDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { if d.config.ResourceType == "" { return nil, errors.New("config `resourceType` is required") } diff --git a/internal/pkg/core/deployer/providers/tencentcloud-vod/tencentcloud_vod.go b/internal/pkg/core/deployer/providers/tencentcloud-vod/tencentcloud_vod.go new file mode 100644 index 00000000..fbce8d6f --- /dev/null +++ b/internal/pkg/core/deployer/providers/tencentcloud-vod/tencentcloud_vod.go @@ -0,0 +1,104 @@ +package tencentcloudvod + +import ( + "context" + + xerrors "github.com/pkg/errors" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile" + tcVod "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod/v20180717" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/logger" + "github.com/usual2970/certimate/internal/pkg/core/uploader" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl" +) + +type DeployerConfig struct { + // 腾讯云 SecretId。 + SecretId string `json:"secretId"` + // 腾讯云 SecretKey。 + SecretKey string `json:"secretKey"` + // 点播应用 ID。 + SubAppId int64 `json:"subAppId"` + // 点播加速域名(不支持泛域名)。 + Domain string `json:"domain"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger logger.Logger + sdkClient *tcVod.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.SecretId, config.SecretKey) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk clients") + } + + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ + SecretId: config.SecretId, + SecretKey: config.SecretKey, + }) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create ssl uploader") + } + + return &DeployerProvider{ + config: config, + logger: logger.NewNilLogger(), + sdkClient: client, + sslUploader: uploader, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { + // 上传证书到 SSL + upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) + if err != nil { + return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Logt("certificate file uploaded", upres) + } + + // 设置点播域名 HTTPS 证书 + // REF: https://cloud.tencent.com/document/api/266/102015 + setVodDomainCertificateReq := tcVod.NewSetVodDomainCertificateRequest() + setVodDomainCertificateReq.Domain = common.StringPtr(d.config.Domain) + setVodDomainCertificateReq.Operation = common.StringPtr("Set") + setVodDomainCertificateReq.CertID = common.StringPtr(upres.CertId) + if d.config.SubAppId != 0 { + setVodDomainCertificateReq.SubAppId = common.Uint64Ptr(uint64(d.config.SubAppId)) + } + setVodDomainCertificateResp, err := d.sdkClient.SetVodDomainCertificate(setVodDomainCertificateReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'vod.SetVodDomainCertificate'") + } else { + d.logger.Logt("已设置点播域名 HTTPS 证书", setVodDomainCertificateResp.Response) + } + + return &deployer.DeployResult{}, nil +} + +func createSdkClient(secretId, secretKey string) (*tcVod.Client, error) { + credential := common.NewCredential(secretId, secretKey) + client, err := tcVod.NewClient(credential, "", profile.NewClientProfile()) + if err != nil { + return nil, err + } + + return client, nil +} diff --git a/internal/pkg/core/deployer/providers/tencentcloud-vod/tencentcloud_vod_test.go b/internal/pkg/core/deployer/providers/tencentcloud-vod/tencentcloud_vod_test.go new file mode 100644 index 00000000..60871a31 --- /dev/null +++ b/internal/pkg/core/deployer/providers/tencentcloud-vod/tencentcloud_vod_test.go @@ -0,0 +1,87 @@ +package tencentcloudvod_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-vod" +) + +var ( + fInputCertPath string + fInputKeyPath string + fSecretId string + fSecretKey string + fRegion string + fDomain string + fSubAppId int64 + fInstanceId string +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_TENCENTCLOUDVOD_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fSecretId, argsPrefix+"SECRETID", "", "") + flag.StringVar(&fSecretKey, argsPrefix+"SECRETKEY", "", "") + flag.StringVar(&fRegion, argsPrefix+"REGION", "", "") + flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "") + flag.Int64Var(&fSubAppId, argsPrefix+"SUBAPPID", 0, "") + flag.StringVar(&fInstanceId, argsPrefix+"INSTANCEID", "", "") +} + +/* +Shell command to run this test: + + go test -v ./tencentcloud_vod_test.go -args \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDVOD_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDVOD_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDVOD_SECRETID="your-secret-id" \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDVOD_SECRETKEY="your-secret-key" \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDVOD_REGION="ap-guangzhou" \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDVOD_SUBAPPID="your-app-id" \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDVOD_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("SECRETID: %v", fSecretId), + fmt.Sprintf("SECRETKEY: %v", fSecretKey), + fmt.Sprintf("REGION: %v", fRegion), + fmt.Sprintf("DOMAIN: %v", fDomain), + fmt.Sprintf("INSTANCEID: %v", fInstanceId), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + SecretId: fSecretId, + SecretKey: fSecretKey, + Region: fRegion, + SubAppId: fSubAppId, + 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) + }) +} diff --git a/internal/pkg/core/deployer/providers/tencentcloud-waf/tencentcloud_waf.go b/internal/pkg/core/deployer/providers/tencentcloud-waf/tencentcloud_waf.go new file mode 100644 index 00000000..7919516c --- /dev/null +++ b/internal/pkg/core/deployer/providers/tencentcloud-waf/tencentcloud_waf.go @@ -0,0 +1,131 @@ +package tencentcloudwaf + +import ( + "context" + "errors" + + xerrors "github.com/pkg/errors" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile" + tcWaf "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf/v20180125" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/logger" + "github.com/usual2970/certimate/internal/pkg/core/uploader" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl" +) + +type DeployerConfig struct { + // 腾讯云 SecretId。 + SecretId string `json:"secretId"` + // 腾讯云 SecretKey。 + SecretKey string `json:"secretKey"` + // 腾讯云地域。 + Region string `json:"region"` + // 防护域名(不支持泛域名)。 + Domain string `json:"domain"` + // 防护域名 ID。 + DomainId string `json:"domainId"` + // 防护域名所属实例 ID。 + InstanceId string `json:"instanceId"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger logger.Logger + sdkClient *tcWaf.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.SecretId, config.SecretKey, config.Region) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk clients") + } + + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ + SecretId: config.SecretId, + SecretKey: config.SecretKey, + }) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create ssl uploader") + } + + return &DeployerProvider{ + config: config, + logger: logger.NewNilLogger(), + sdkClient: client, + sslUploader: uploader, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + 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") + } + if d.config.DomainId == "" { + return nil, errors.New("config `domainId` is required") + } + if d.config.InstanceId == "" { + return nil, errors.New("config `instanceId` is required") + } + + // 上传证书到 SSL + upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) + if err != nil { + return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Logt("certificate file uploaded", upres) + } + + // 查询单个 SaaS 型 WAF 域名详情 + // REF: https://cloud.tencent.com/document/api/627/82938 + describeDomainDetailsSaasReq := tcWaf.NewDescribeDomainDetailsSaasRequest() + describeDomainDetailsSaasReq.Domain = common.StringPtr(d.config.Domain) + describeDomainDetailsSaasReq.DomainId = common.StringPtr(d.config.DomainId) + describeDomainDetailsSaasReq.InstanceId = common.StringPtr(d.config.InstanceId) + describeDomainDetailsSaasResp, err := d.sdkClient.DescribeDomainDetailsSaas(describeDomainDetailsSaasReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'waf.DescribeDomainDetailsSaas'") + } else { + d.logger.Logt("已查询到 SaaS 型 WAF 域名详情", describeDomainDetailsSaasResp.Response) + } + + // 编辑 SaaS 型 WAF 域名 + // REF: https://cloud.tencent.com/document/api/627/94309 + modifySpartaProtectionReq := tcWaf.NewModifySpartaProtectionRequest() + modifySpartaProtectionReq.Domain = common.StringPtr(d.config.Domain) + modifySpartaProtectionReq.DomainId = common.StringPtr(d.config.DomainId) + modifySpartaProtectionReq.InstanceID = common.StringPtr(d.config.InstanceId) + modifySpartaProtectionReq.CertType = common.Int64Ptr(2) + modifySpartaProtectionReq.SSLId = common.StringPtr(upres.CertId) + modifySpartaProtectionResp, err := d.sdkClient.ModifySpartaProtection(modifySpartaProtectionReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'waf.ModifySpartaProtection'") + } else { + d.logger.Logt("已编辑 SaaS 型 WAF 域名", modifySpartaProtectionResp.Response) + } + + return &deployer.DeployResult{}, nil +} + +func createSdkClient(secretId, secretKey, region string) (*tcWaf.Client, error) { + credential := common.NewCredential(secretId, secretKey) + client, err := tcWaf.NewClient(credential, region, profile.NewClientProfile()) + if err != nil { + return nil, err + } + + return client, nil +} diff --git a/internal/pkg/core/deployer/providers/tencentcloud-waf/tencentcloud_waf_test.go b/internal/pkg/core/deployer/providers/tencentcloud-waf/tencentcloud_waf_test.go new file mode 100644 index 00000000..42ba1ffe --- /dev/null +++ b/internal/pkg/core/deployer/providers/tencentcloud-waf/tencentcloud_waf_test.go @@ -0,0 +1,89 @@ +package tencentcloudwaf_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-waf" +) + +var ( + fInputCertPath string + fInputKeyPath string + fSecretId string + fSecretKey string + fRegion string + fDomain string + fDomainId string + fInstanceId string +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_TENCENTCLOUDWAF_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fSecretId, argsPrefix+"SECRETID", "", "") + flag.StringVar(&fSecretKey, argsPrefix+"SECRETKEY", "", "") + flag.StringVar(&fRegion, argsPrefix+"REGION", "", "") + flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "") + flag.StringVar(&fDomainId, argsPrefix+"DOMAINID", "", "") + flag.StringVar(&fInstanceId, argsPrefix+"INSTANCEID", "", "") +} + +/* +Shell command to run this test: + + go test -v ./tencentcloud_waf_test.go -args \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDWAF_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDWAF_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDWAF_SECRETID="your-secret-id" \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDWAF_SECRETKEY="your-secret-key" \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDWAF_REGION="ap-guangzhou" \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDWAF_DOMAIN="example.com" \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDWAF_DOMAINID="your-domain-id" \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDWAF_INSTANCEID="your-instance-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("SECRETID: %v", fSecretId), + fmt.Sprintf("SECRETKEY: %v", fSecretKey), + fmt.Sprintf("REGION: %v", fRegion), + fmt.Sprintf("DOMAIN: %v", fDomain), + fmt.Sprintf("INSTANCEID: %v", fInstanceId), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + SecretId: fSecretId, + SecretKey: fSecretKey, + Region: fRegion, + Domain: fDomain, + DomainId: fDomainId, + InstanceId: fInstanceId, + }) + 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) + }) +} diff --git a/internal/pkg/core/deployer/providers/ucloud-ucdn/ucloud_ucdn.go b/internal/pkg/core/deployer/providers/ucloud-ucdn/ucloud_ucdn.go index fa104ba3..8c19621b 100644 --- a/internal/pkg/core/deployer/providers/ucloud-ucdn/ucloud_ucdn.go +++ b/internal/pkg/core/deployer/providers/ucloud-ucdn/ucloud_ucdn.go @@ -13,10 +13,10 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/ucloud-ussl" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/ucloud-ussl" ) -type UCloudUCDNDeployerConfig struct { +type DeployerConfig struct { // 优刻得 API 私钥。 PrivateKey string `json:"privateKey"` // 优刻得 API 公钥。 @@ -27,26 +27,18 @@ type UCloudUCDNDeployerConfig struct { DomainId string `json:"domainId"` } -type UCloudUCDNDeployer struct { - config *UCloudUCDNDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *uCdn.UCDNClient sslUploader uploader.Uploader } -var _ deployer.Deployer = (*UCloudUCDNDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *UCloudUCDNDeployerConfig) (*UCloudUCDNDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *UCloudUCDNDeployerConfig, logger logger.Logger) (*UCloudUCDNDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client, err := createSdkClient(config.PrivateKey, config.PublicKey) @@ -54,7 +46,7 @@ func NewWithLogger(config *UCloudUCDNDeployerConfig, logger logger.Logger) (*UCl return nil, xerrors.Wrap(err, "failed to create sdk client") } - uploader, err := uploaderp.New(&uploaderp.UCloudUSSLUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ PrivateKey: config.PrivateKey, PublicKey: config.PublicKey, ProjectId: config.ProjectId, @@ -63,15 +55,20 @@ func NewWithLogger(config *UCloudUCDNDeployerConfig, logger logger.Logger) (*UCl return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &UCloudUCDNDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *UCloudUCDNDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // 上传证书到 USSL upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { diff --git a/internal/pkg/core/deployer/providers/ucloud-ucdn/ucloud_ucdn_test.go b/internal/pkg/core/deployer/providers/ucloud-ucdn/ucloud_ucdn_test.go index d8b703b5..fc952da1 100644 --- a/internal/pkg/core/deployer/providers/ucloud-ucdn/ucloud_ucdn_test.go +++ b/internal/pkg/core/deployer/providers/ucloud-ucdn/ucloud_ucdn_test.go @@ -52,7 +52,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DOMAIN: %v", fDomainId), }, "\n")) - deployer, err := provider.New(&provider.UCloudUCDNDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ PrivateKey: fPrivateKey, PublicKey: fPublicKey, DomainId: fDomainId, diff --git a/internal/pkg/core/deployer/providers/ucloud-us3/ucloud_us3.go b/internal/pkg/core/deployer/providers/ucloud-us3/ucloud_us3.go index ccf03224..592a1cf6 100644 --- a/internal/pkg/core/deployer/providers/ucloud-us3/ucloud_us3.go +++ b/internal/pkg/core/deployer/providers/ucloud-us3/ucloud_us3.go @@ -2,7 +2,6 @@ import ( "context" - "errors" xerrors "github.com/pkg/errors" usdk "github.com/ucloud/ucloud-sdk-go/ucloud" @@ -11,11 +10,11 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/ucloud-ussl" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/ucloud-ussl" usdkFile "github.com/usual2970/certimate/internal/pkg/vendors/ucloud-sdk/ufile" ) -type UCloudUS3DeployerConfig struct { +type DeployerConfig struct { // 优刻得 API 私钥。 PrivateKey string `json:"privateKey"` // 优刻得 API 公钥。 @@ -30,26 +29,18 @@ type UCloudUS3DeployerConfig struct { Domain string `json:"domain"` } -type UCloudUS3Deployer struct { - config *UCloudUS3DeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *usdkFile.UFileClient sslUploader uploader.Uploader } -var _ deployer.Deployer = (*UCloudUS3Deployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *UCloudUS3DeployerConfig) (*UCloudUS3Deployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *UCloudUS3DeployerConfig, logger logger.Logger) (*UCloudUS3Deployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client, err := createSdkClient(config.PrivateKey, config.PublicKey, config.Region) @@ -57,7 +48,7 @@ func NewWithLogger(config *UCloudUS3DeployerConfig, logger logger.Logger) (*UClo return nil, xerrors.Wrap(err, "failed to create sdk client") } - uploader, err := uploaderp.New(&uploaderp.UCloudUSSLUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ PrivateKey: config.PrivateKey, PublicKey: config.PublicKey, ProjectId: config.ProjectId, @@ -66,15 +57,20 @@ func NewWithLogger(config *UCloudUS3DeployerConfig, logger logger.Logger) (*UClo return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &UCloudUS3Deployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *UCloudUS3Deployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // 上传证书到 USSL upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { diff --git a/internal/pkg/core/deployer/providers/ucloud-us3/ucloud_us3_test.go b/internal/pkg/core/deployer/providers/ucloud-us3/ucloud_us3_test.go index e4175bfc..52f78664 100644 --- a/internal/pkg/core/deployer/providers/ucloud-us3/ucloud_us3_test.go +++ b/internal/pkg/core/deployer/providers/ucloud-us3/ucloud_us3_test.go @@ -60,7 +60,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) - deployer, err := provider.New(&provider.UCloudUS3DeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ PrivateKey: fPrivateKey, PublicKey: fPublicKey, Region: fRegion, diff --git a/internal/pkg/core/deployer/providers/volcengine-cdn/volcengine_cdn.go b/internal/pkg/core/deployer/providers/volcengine-cdn/volcengine_cdn.go index de3e76e4..229c3c01 100644 --- a/internal/pkg/core/deployer/providers/volcengine-cdn/volcengine_cdn.go +++ b/internal/pkg/core/deployer/providers/volcengine-cdn/volcengine_cdn.go @@ -12,10 +12,10 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/volcengine-cdn" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/volcengine-cdn" ) -type VolcEngineCDNDeployerConfig struct { +type DeployerConfig struct { // 火山引擎 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 火山引擎 AccessKeySecret。 @@ -24,33 +24,25 @@ type VolcEngineCDNDeployerConfig struct { Domain string `json:"domain"` } -type VolcEngineCDNDeployer struct { - config *VolcEngineCDNDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *veCdn.CDN sslUploader uploader.Uploader } -var _ deployer.Deployer = (*VolcEngineCDNDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *VolcEngineCDNDeployerConfig) (*VolcEngineCDNDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *VolcEngineCDNDeployerConfig, logger logger.Logger) (*VolcEngineCDNDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client := veCdn.NewInstance() client.Client.SetAccessKey(config.AccessKeyId) client.Client.SetSecretKey(config.AccessKeySecret) - uploader, err := uploaderp.New(&uploaderp.VolcEngineCDNUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ AccessKeyId: config.AccessKeyId, AccessKeySecret: config.AccessKeySecret, }) @@ -58,15 +50,20 @@ func NewWithLogger(config *VolcEngineCDNDeployerConfig, logger logger.Logger) (* return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &VolcEngineCDNDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *VolcEngineCDNDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // 上传证书到 CDN upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { diff --git a/internal/pkg/core/deployer/providers/volcengine-cdn/volcengine_cdn_test.go b/internal/pkg/core/deployer/providers/volcengine-cdn/volcengine_cdn_test.go index 3a3ff62d..c94b9828 100644 --- a/internal/pkg/core/deployer/providers/volcengine-cdn/volcengine_cdn_test.go +++ b/internal/pkg/core/deployer/providers/volcengine-cdn/volcengine_cdn_test.go @@ -52,7 +52,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) - deployer, err := provider.New(&provider.VolcEngineCDNDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKeyId: fAccessKeyId, AccessKeySecret: fAccessKeySecret, Domain: fDomain, diff --git a/internal/pkg/core/deployer/providers/volcengine-clb/consts.go b/internal/pkg/core/deployer/providers/volcengine-clb/consts.go new file mode 100644 index 00000000..dc1e992b --- /dev/null +++ b/internal/pkg/core/deployer/providers/volcengine-clb/consts.go @@ -0,0 +1,8 @@ +package volcengineclb + +type ResourceType string + +const ( + // 资源类型:部署到指定监听器。 + RESOURCE_TYPE_LISTENER = ResourceType("listener") +) diff --git a/internal/pkg/core/deployer/providers/volcengine-clb/defines.go b/internal/pkg/core/deployer/providers/volcengine-clb/defines.go deleted file mode 100644 index ec211199..00000000 --- a/internal/pkg/core/deployer/providers/volcengine-clb/defines.go +++ /dev/null @@ -1,8 +0,0 @@ -package volcengineclb - -type DeployResourceType string - -const ( - // 资源类型:部署到指定监听器。 - DEPLOY_RESOURCE_LISTENER = DeployResourceType("listener") -) diff --git a/internal/pkg/core/deployer/providers/volcengine-clb/volcengine_clb.go b/internal/pkg/core/deployer/providers/volcengine-clb/volcengine_clb.go index 08c096fd..73372781 100644 --- a/internal/pkg/core/deployer/providers/volcengine-clb/volcengine_clb.go +++ b/internal/pkg/core/deployer/providers/volcengine-clb/volcengine_clb.go @@ -13,10 +13,10 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/volcengine-certcenter" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/volcengine-certcenter" ) -type VolcEngineCLBDeployerConfig struct { +type DeployerConfig struct { // 火山引擎 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 火山引擎 AccessKeySecret。 @@ -24,32 +24,24 @@ type VolcEngineCLBDeployerConfig struct { // 火山引擎地域。 Region string `json:"region"` // 部署资源类型。 - ResourceType DeployResourceType `json:"resourceType"` + ResourceType ResourceType `json:"resourceType"` // 负载均衡监听器 ID。 - // 部署资源类型为 [DEPLOY_RESOURCE_LISTENER] 时必填。 + // 部署资源类型为 [RESOURCE_TYPE_LISTENER] 时必填。 ListenerId string `json:"listenerId,omitempty"` } -type VolcEngineCLBDeployer struct { - config *VolcEngineCLBDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *veClb.CLB sslUploader uploader.Uploader } -var _ deployer.Deployer = (*VolcEngineCLBDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *VolcEngineCLBDeployerConfig) (*VolcEngineCLBDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *VolcEngineCLBDeployerConfig, logger logger.Logger) (*VolcEngineCLBDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region) @@ -57,7 +49,7 @@ func NewWithLogger(config *VolcEngineCLBDeployerConfig, logger logger.Logger) (* return nil, xerrors.Wrap(err, "failed to create sdk client") } - uploader, err := uploaderp.New(&uploaderp.VolcEngineCertCenterUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ AccessKeyId: config.AccessKeyId, AccessKeySecret: config.AccessKeySecret, Region: config.Region, @@ -66,15 +58,19 @@ func NewWithLogger(config *VolcEngineCLBDeployerConfig, logger logger.Logger) (* return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &VolcEngineCLBDeployer{ - logger: logger, + return &DeployerProvider{ config: config, sdkClient: client, sslUploader: uploader, }, nil } -func (d *VolcEngineCLBDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // 上传证书到证书中心 upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { @@ -85,7 +81,7 @@ func (d *VolcEngineCLBDeployer) Deploy(ctx context.Context, certPem string, priv // 根据部署资源类型决定部署方式 switch d.config.ResourceType { - case DEPLOY_RESOURCE_LISTENER: + case RESOURCE_TYPE_LISTENER: if err := d.deployToListener(ctx, upres.CertId); err != nil { return nil, err } @@ -97,7 +93,7 @@ func (d *VolcEngineCLBDeployer) Deploy(ctx context.Context, certPem string, priv return &deployer.DeployResult{}, nil } -func (d *VolcEngineCLBDeployer) deployToListener(ctx context.Context, cloudCertId string) error { +func (d *DeployerProvider) deployToListener(ctx context.Context, cloudCertId string) error { if d.config.ListenerId == "" { return errors.New("config `listenerId` is required") } diff --git a/internal/pkg/core/deployer/providers/volcengine-clb/volcengine_clb_test.go b/internal/pkg/core/deployer/providers/volcengine-clb/volcengine_clb_test.go index 45d79f44..0b589f88 100644 --- a/internal/pkg/core/deployer/providers/volcengine-clb/volcengine_clb_test.go +++ b/internal/pkg/core/deployer/providers/volcengine-clb/volcengine_clb_test.go @@ -56,11 +56,11 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("LISTENERID: %v", fListenerId), }, "\n")) - deployer, err := provider.New(&provider.VolcEngineCLBDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKeyId: fAccessKeyId, AccessKeySecret: fAccessKeySecret, Region: fRegion, - ResourceType: provider.DEPLOY_RESOURCE_LISTENER, + ResourceType: provider.RESOURCE_TYPE_LISTENER, ListenerId: fListenerId, }) if err != nil { diff --git a/internal/pkg/core/deployer/providers/volcengine-dcdn/volcengine_dcdn.go b/internal/pkg/core/deployer/providers/volcengine-dcdn/volcengine_dcdn.go index 0f9f8e51..835eae4b 100644 --- a/internal/pkg/core/deployer/providers/volcengine-dcdn/volcengine_dcdn.go +++ b/internal/pkg/core/deployer/providers/volcengine-dcdn/volcengine_dcdn.go @@ -2,7 +2,6 @@ import ( "context" - "errors" "strings" xerrors "github.com/pkg/errors" @@ -13,10 +12,10 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/volcengine-certcenter" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/volcengine-certcenter" ) -type VolcEngineDCDNDeployerConfig struct { +type DeployerConfig struct { // 火山引擎 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 火山引擎 AccessKeySecret。 @@ -27,26 +26,18 @@ type VolcEngineDCDNDeployerConfig struct { Domain string `json:"domain"` } -type VolcEngineDCDNDeployer struct { - config *VolcEngineDCDNDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *veDcdn.DCDN sslUploader uploader.Uploader } -var _ deployer.Deployer = (*VolcEngineDCDNDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *VolcEngineDCDNDeployerConfig) (*VolcEngineDCDNDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *VolcEngineDCDNDeployerConfig, logger logger.Logger) (*VolcEngineDCDNDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region) @@ -54,7 +45,7 @@ func NewWithLogger(config *VolcEngineDCDNDeployerConfig, logger logger.Logger) ( return nil, xerrors.Wrap(err, "failed to create sdk client") } - uploader, err := uploaderp.New(&uploaderp.VolcEngineCertCenterUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ AccessKeyId: config.AccessKeyId, AccessKeySecret: config.AccessKeySecret, Region: config.Region, @@ -63,15 +54,20 @@ func NewWithLogger(config *VolcEngineDCDNDeployerConfig, logger logger.Logger) ( return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &VolcEngineDCDNDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *VolcEngineDCDNDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // 上传证书到证书中心 upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { diff --git a/internal/pkg/core/deployer/providers/volcengine-dcdn/volcengine_dcdn_test.go b/internal/pkg/core/deployer/providers/volcengine-dcdn/volcengine_dcdn_test.go index 2236b1e1..1d34a295 100644 --- a/internal/pkg/core/deployer/providers/volcengine-dcdn/volcengine_dcdn_test.go +++ b/internal/pkg/core/deployer/providers/volcengine-dcdn/volcengine_dcdn_test.go @@ -52,7 +52,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) - deployer, err := provider.New(&provider.VolcEngineDCDNDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKeyId: fAccessKeyId, AccessKeySecret: fAccessKeySecret, Domain: fDomain, diff --git a/internal/pkg/core/deployer/providers/volcengine-imagex/volcengine_imagex.go b/internal/pkg/core/deployer/providers/volcengine-imagex/volcengine_imagex.go new file mode 100644 index 00000000..57d133ec --- /dev/null +++ b/internal/pkg/core/deployer/providers/volcengine-imagex/volcengine_imagex.go @@ -0,0 +1,144 @@ +package volcengineimagex + +import ( + "context" + "errors" + + xerrors "github.com/pkg/errors" + veBase "github.com/volcengine/volc-sdk-golang/base" + veImageX "github.com/volcengine/volc-sdk-golang/service/imagex/v2" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/logger" + "github.com/usual2970/certimate/internal/pkg/core/uploader" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/volcengine-certcenter" +) + +type DeployerConfig struct { + // 火山引擎 AccessKeyId。 + AccessKeyId string `json:"accessKeyId"` + // 火山引擎 AccessKeySecret。 + AccessKeySecret string `json:"accessKeySecret"` + // 火山引擎地域。 + Region string `json:"region"` + // 服务 ID。 + ServiceId string `json:"serviceId"` + // 自定义域名(不支持泛域名)。 + Domain string `json:"domain"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger logger.Logger + sdkClient *veImageX.Imagex + 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.AccessKeySecret, config.Region) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ + AccessKeyId: config.AccessKeyId, + AccessKeySecret: config.AccessKeySecret, + Region: config.Region, + }) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create ssl uploader") + } + + return &DeployerProvider{ + config: config, + logger: logger.NewNilLogger(), + sdkClient: client, + sslUploader: uploader, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { + if d.config.ServiceId == "" { + return nil, errors.New("config `serviceId` is required") + } + if d.config.Domain == "" { + return nil, errors.New("config `domain` is required") + } + + // 上传证书到证书中心 + upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) + if err != nil { + return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Logt("certificate file uploaded", upres) + } + + // 获取域名配置 + // REF: https://www.volcengine.com/docs/508/9366 + getDomainConfigReq := &veImageX.GetDomainConfigQuery{ + ServiceID: d.config.ServiceId, + DomainName: d.config.Domain, + } + getDomainConfigResp, err := d.sdkClient.GetDomainConfig(context.TODO(), getDomainConfigReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'imagex.GetDomainConfig'") + } else { + d.logger.Logt("已获取域名配置", getDomainConfigResp) + } + + // 更新 HTTPS 配置 + // REF: https://www.volcengine.com/docs/508/66012 + updateHttpsReq := &veImageX.UpdateHTTPSReq{ + UpdateHTTPSQuery: &veImageX.UpdateHTTPSQuery{ + ServiceID: d.config.ServiceId, + }, + UpdateHTTPSBody: &veImageX.UpdateHTTPSBody{ + Domain: getDomainConfigResp.Result.Domain, + HTTPS: &veImageX.UpdateHTTPSBodyHTTPS{ + CertID: upres.CertId, + EnableHTTP2: getDomainConfigResp.Result.HTTPSConfig.EnableHTTP2, + EnableHTTPS: getDomainConfigResp.Result.HTTPSConfig.EnableHTTPS, + EnableOcsp: getDomainConfigResp.Result.HTTPSConfig.EnableOcsp, + TLSVersions: getDomainConfigResp.Result.HTTPSConfig.TLSVersions, + EnableForceRedirect: getDomainConfigResp.Result.HTTPSConfig.EnableForceRedirect, + ForceRedirectType: getDomainConfigResp.Result.HTTPSConfig.ForceRedirectType, + ForceRedirectCode: getDomainConfigResp.Result.HTTPSConfig.ForceRedirectCode, + }, + }, + } + updateHttpsResp, err := d.sdkClient.UpdateHTTPS(context.TODO(), updateHttpsReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'imagex.UpdateHttps'") + } else { + d.logger.Logt("已更新 HTTPS 配置", updateHttpsResp) + } + + return &deployer.DeployResult{}, nil +} + +func createSdkClient(accessKeyId, accessKeySecret, region string) (*veImageX.Imagex, error) { + var instance *veImageX.Imagex + if region == "" { + instance = veImageX.NewInstance() + } else { + instance = veImageX.NewInstanceWithRegion(region) + } + + instance.SetCredential(veBase.Credentials{ + AccessKeyID: accessKeyId, + SecretAccessKey: accessKeySecret, + }) + + return instance, nil +} diff --git a/internal/pkg/core/deployer/providers/volcengine-imagex/volcengine_imagex_test.go b/internal/pkg/core/deployer/providers/volcengine-imagex/volcengine_imagex_test.go new file mode 100644 index 00000000..f2acb8f2 --- /dev/null +++ b/internal/pkg/core/deployer/providers/volcengine-imagex/volcengine_imagex_test.go @@ -0,0 +1,85 @@ +package volcengineimagex_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/volcengine-imagex" +) + +var ( + fInputCertPath string + fInputKeyPath string + fAccessKeyId string + fAccessKeySecret string + fRegion string + fServiceId string + fDomain string +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_VOLCENGINEIMAGEX_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "") + flag.StringVar(&fAccessKeySecret, argsPrefix+"ACCESSKEYSECRET", "", "") + flag.StringVar(&fRegion, argsPrefix+"REGION", "", "") + flag.StringVar(&fServiceId, argsPrefix+"SERVICEID", "", "") + flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "") +} + +/* +Shell command to run this test: + + go test -v ./volcengine_imagex_test.go -args \ + --CERTIMATE_DEPLOYER_VOLCENGINEIMAGEX_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_VOLCENGINEIMAGEX_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_VOLCENGINEIMAGEX_ACCESSKEYID="your-access-key-id" \ + --CERTIMATE_DEPLOYER_VOLCENGINEIMAGEX_ACCESSKEYSECRET="your-access-key-secret" \ + --CERTIMATE_DEPLOYER_VOLCENGINEIMAGEX_REGION="cn-north-1" \ + --CERTIMATE_DEPLOYER_VOLCENGINEIMAGEX_SERVICEID="your-service-id" \ + --CERTIMATE_DEPLOYER_VOLCENGINEIMAGEX_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("ACCESSKEYSECRET: %v", fAccessKeySecret), + fmt.Sprintf("REGION: %v", fRegion), + fmt.Sprintf("SERVICEID: %v", fServiceId), + fmt.Sprintf("DOMAIN: %v", fDomain), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + AccessKeyId: fAccessKeyId, + AccessKeySecret: fAccessKeySecret, + Region: fRegion, + ServiceId: fServiceId, + 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) + }) +} diff --git a/internal/pkg/core/deployer/providers/volcengine-live/volcengine_live.go b/internal/pkg/core/deployer/providers/volcengine-live/volcengine_live.go index b23f4c6c..240e5c9c 100644 --- a/internal/pkg/core/deployer/providers/volcengine-live/volcengine_live.go +++ b/internal/pkg/core/deployer/providers/volcengine-live/volcengine_live.go @@ -13,10 +13,10 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/volcengine-live" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/volcengine-live" ) -type VolcEngineLiveDeployerConfig struct { +type DeployerConfig struct { // 火山引擎 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 火山引擎 AccessKeySecret。 @@ -25,33 +25,25 @@ type VolcEngineLiveDeployerConfig struct { Domain string `json:"domain"` } -type VolcEngineLiveDeployer struct { - config *VolcEngineLiveDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *veLive.Live sslUploader uploader.Uploader } -var _ deployer.Deployer = (*VolcEngineLiveDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *VolcEngineLiveDeployerConfig) (*VolcEngineLiveDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *VolcEngineLiveDeployerConfig, logger logger.Logger) (*VolcEngineLiveDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client := veLive.NewInstance() client.SetAccessKey(config.AccessKeyId) client.SetSecretKey(config.AccessKeySecret) - uploader, err := uploaderp.New(&uploaderp.VolcEngineLiveUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ AccessKeyId: config.AccessKeyId, AccessKeySecret: config.AccessKeySecret, }) @@ -59,15 +51,20 @@ func NewWithLogger(config *VolcEngineLiveDeployerConfig, logger logger.Logger) ( return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &VolcEngineLiveDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *VolcEngineLiveDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { // 上传证书到 Live upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { diff --git a/internal/pkg/core/deployer/providers/volcengine-live/volcengine_live_test.go b/internal/pkg/core/deployer/providers/volcengine-live/volcengine_live_test.go index 28097c75..2222e7b9 100644 --- a/internal/pkg/core/deployer/providers/volcengine-live/volcengine_live_test.go +++ b/internal/pkg/core/deployer/providers/volcengine-live/volcengine_live_test.go @@ -52,7 +52,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) - deployer, err := provider.New(&provider.VolcEngineLiveDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKeyId: fAccessKeyId, AccessKeySecret: fAccessKeySecret, Domain: fDomain, diff --git a/internal/pkg/core/deployer/providers/volcengine-tos/volcengine_tos.go b/internal/pkg/core/deployer/providers/volcengine-tos/volcengine_tos.go index 9a238f27..142a8b9f 100644 --- a/internal/pkg/core/deployer/providers/volcengine-tos/volcengine_tos.go +++ b/internal/pkg/core/deployer/providers/volcengine-tos/volcengine_tos.go @@ -11,10 +11,10 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/deployer" "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/pkg/core/uploader" - uploaderp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/volcengine-certcenter" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/volcengine-certcenter" ) -type VolcEngineTOSDeployerConfig struct { +type DeployerConfig struct { // 火山引擎 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 火山引擎 AccessKeySecret。 @@ -27,26 +27,18 @@ type VolcEngineTOSDeployerConfig struct { Domain string `json:"domain"` } -type VolcEngineTOSDeployer struct { - config *VolcEngineTOSDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger sdkClient *veTos.ClientV2 sslUploader uploader.Uploader } -var _ deployer.Deployer = (*VolcEngineTOSDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *VolcEngineTOSDeployerConfig) (*VolcEngineTOSDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *VolcEngineTOSDeployerConfig, logger logger.Logger) (*VolcEngineTOSDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region) @@ -54,7 +46,7 @@ func NewWithLogger(config *VolcEngineTOSDeployerConfig, logger logger.Logger) (* return nil, xerrors.Wrap(err, "failed to create sdk client") } - uploader, err := uploaderp.New(&uploaderp.VolcEngineCertCenterUploaderConfig{ + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ AccessKeyId: config.AccessKeyId, AccessKeySecret: config.AccessKeySecret, Region: config.Region, @@ -63,15 +55,20 @@ func NewWithLogger(config *VolcEngineTOSDeployerConfig, logger logger.Logger) (* return nil, xerrors.Wrap(err, "failed to create ssl uploader") } - return &VolcEngineTOSDeployer{ - logger: logger, + return &DeployerProvider{ config: config, + logger: logger.NewNilLogger(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *VolcEngineTOSDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { if d.config.Bucket == "" { return nil, errors.New("config `bucket` is required") } diff --git a/internal/pkg/core/deployer/providers/volcengine-tos/volcengine_tos_test.go b/internal/pkg/core/deployer/providers/volcengine-tos/volcengine_tos_test.go index b70130c4..0c9b398a 100644 --- a/internal/pkg/core/deployer/providers/volcengine-tos/volcengine_tos_test.go +++ b/internal/pkg/core/deployer/providers/volcengine-tos/volcengine_tos_test.go @@ -60,9 +60,11 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) - deployer, err := provider.New(&provider.VolcEngineTOSDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKeyId: fAccessKeyId, AccessKeySecret: fAccessKeySecret, + Region: fRegion, + Bucket: fBucket, Domain: fDomain, }) if err != nil { diff --git a/internal/pkg/core/deployer/providers/webhook/webhook.go b/internal/pkg/core/deployer/providers/webhook/webhook.go index 694befc5..7a9edfda 100644 --- a/internal/pkg/core/deployer/providers/webhook/webhook.go +++ b/internal/pkg/core/deployer/providers/webhook/webhook.go @@ -3,7 +3,6 @@ package webhook import ( "context" "encoding/json" - "errors" "strings" "time" @@ -15,32 +14,24 @@ import ( "github.com/usual2970/certimate/internal/pkg/utils/certs" ) -type WebhookDeployerConfig struct { +type DeployerConfig struct { // Webhook URL。 WebhookUrl string `json:"webhookUrl"` // Webhook 回调数据(JSON 格式)。 WebhookData string `json:"webhookData,omitempty"` } -type WebhookDeployer struct { - config *WebhookDeployerConfig +type DeployerProvider struct { + config *DeployerConfig logger logger.Logger httpClient *resty.Client } -var _ deployer.Deployer = (*WebhookDeployer)(nil) +var _ deployer.Deployer = (*DeployerProvider)(nil) -func New(config *WebhookDeployerConfig) (*WebhookDeployer, error) { - return NewWithLogger(config, logger.NewNilLogger()) -} - -func NewWithLogger(config *WebhookDeployerConfig, logger logger.Logger) (*WebhookDeployer, error) { +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { if config == nil { - return nil, errors.New("config is nil") - } - - if logger == nil { - return nil, errors.New("logger is nil") + panic("config is nil") } client := resty.New(). @@ -48,14 +39,19 @@ func NewWithLogger(config *WebhookDeployerConfig, logger logger.Logger) (*Webhoo SetRetryCount(3). SetRetryWaitTime(5 * time.Second) - return &WebhookDeployer{ + return &DeployerProvider{ config: config, - logger: logger, + logger: logger.NewNilLogger(), httpClient: client, }, nil } -func (d *WebhookDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { +func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { + d.logger = logger + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { certX509, err := certs.ParseCertificateFromPEM(certPem) if err != nil { return nil, xerrors.Wrap(err, "failed to parse x509") diff --git a/internal/pkg/core/deployer/providers/webhook/webhook_test.go b/internal/pkg/core/deployer/providers/webhook/webhook_test.go index 92b57e56..7dd6f24a 100644 --- a/internal/pkg/core/deployer/providers/webhook/webhook_test.go +++ b/internal/pkg/core/deployer/providers/webhook/webhook_test.go @@ -48,7 +48,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("WEBHOOKDATA: %v", fWebhookData), }, "\n")) - deployer, err := provider.New(&provider.WebhookDeployerConfig{ + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ WebhookUrl: fWebhookUrl, WebhookData: fWebhookData, }) diff --git a/internal/pkg/core/logger/builtin.go b/internal/pkg/core/logger/builtin.go index 9787817d..fa8932dc 100644 --- a/internal/pkg/core/logger/builtin.go +++ b/internal/pkg/core/logger/builtin.go @@ -35,8 +35,8 @@ func (l *DefaultLogger) Logt(tag string, data ...any) { reflect.Float32, reflect.Float64: s = fmt.Sprintf("%v", v) default: - jsonData, _ := json.Marshal(v) - s = string(jsonData) + jbytes, _ := json.Marshal(v) + s = string(jbytes) } } diff --git a/internal/pkg/core/notifier/providers/bark/bark.go b/internal/pkg/core/notifier/providers/bark/bark.go index 74683f82..f9589096 100644 --- a/internal/pkg/core/notifier/providers/bark/bark.go +++ b/internal/pkg/core/notifier/providers/bark/bark.go @@ -2,7 +2,6 @@ import ( "context" - "errors" "github.com/nikoksr/notify" "github.com/nikoksr/notify/service/bark" @@ -10,7 +9,7 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/notifier" ) -type BarkNotifierConfig struct { +type NotifierConfig struct { // Bark 服务地址。 // 零值时默认使用官方服务器。 ServerUrl string `json:"serverUrl"` @@ -18,23 +17,23 @@ type BarkNotifierConfig struct { DeviceKey string `json:"deviceKey"` } -type BarkNotifier struct { - config *BarkNotifierConfig +type NotifierProvider struct { + config *NotifierConfig } -var _ notifier.Notifier = (*BarkNotifier)(nil) +var _ notifier.Notifier = (*NotifierProvider)(nil) -func New(config *BarkNotifierConfig) (*BarkNotifier, error) { +func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } - return &BarkNotifier{ + return &NotifierProvider{ config: config, }, nil } -func (n *BarkNotifier) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { +func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { var srv notify.Notifier if n.config.ServerUrl == "" { srv = bark.New(n.config.DeviceKey) diff --git a/internal/pkg/core/notifier/providers/bark/bark_test.go b/internal/pkg/core/notifier/providers/bark/bark_test.go index e3045cae..bd0441b4 100644 --- a/internal/pkg/core/notifier/providers/bark/bark_test.go +++ b/internal/pkg/core/notifier/providers/bark/bark_test.go @@ -44,7 +44,7 @@ func TestNotify(t *testing.T) { fmt.Sprintf("DEVICEKEY: %v", fDeviceKey), }, "\n")) - notifier, err := provider.New(&provider.BarkNotifierConfig{ + notifier, err := provider.NewNotifier(&provider.NotifierConfig{ ServerUrl: fServerUrl, DeviceKey: fDeviceKey, }) diff --git a/internal/pkg/core/notifier/providers/dingtalk/dingtalk.go b/internal/pkg/core/notifier/providers/dingtalk/dingtalk.go index 52fe5f27..f8eba8a7 100644 --- a/internal/pkg/core/notifier/providers/dingtalk/dingtalk.go +++ b/internal/pkg/core/notifier/providers/dingtalk/dingtalk.go @@ -2,37 +2,36 @@ import ( "context" - "errors" "github.com/nikoksr/notify/service/dingding" "github.com/usual2970/certimate/internal/pkg/core/notifier" ) -type DingTalkNotifierConfig struct { +type NotifierConfig struct { // 钉钉机器人的 Token。 AccessToken string `json:"accessToken"` // 钉钉机器人的 Secret。 Secret string `json:"secret"` } -type DingTalkNotifier struct { - config *DingTalkNotifierConfig +type NotifierProvider struct { + config *NotifierConfig } -var _ notifier.Notifier = (*DingTalkNotifier)(nil) +var _ notifier.Notifier = (*NotifierProvider)(nil) -func New(config *DingTalkNotifierConfig) (*DingTalkNotifier, error) { +func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } - return &DingTalkNotifier{ + return &NotifierProvider{ config: config, }, nil } -func (n *DingTalkNotifier) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { +func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { srv := dingding.New(&dingding.Config{ Token: n.config.AccessToken, Secret: n.config.Secret, diff --git a/internal/pkg/core/notifier/providers/dingtalk/dingtalk_test.go b/internal/pkg/core/notifier/providers/dingtalk/dingtalk_test.go index 621a57ca..836cf498 100644 --- a/internal/pkg/core/notifier/providers/dingtalk/dingtalk_test.go +++ b/internal/pkg/core/notifier/providers/dingtalk/dingtalk_test.go @@ -43,7 +43,7 @@ func TestNotify(t *testing.T) { fmt.Sprintf("SECRET: %v", fSecret), }, "\n")) - notifier, err := provider.New(&provider.DingTalkNotifierConfig{ + notifier, err := provider.NewNotifier(&provider.NotifierConfig{ AccessToken: fAccessToken, Secret: fSecret, }) diff --git a/internal/pkg/core/notifier/providers/email/email.go b/internal/pkg/core/notifier/providers/email/email.go index 127c5528..4a69d50a 100644 --- a/internal/pkg/core/notifier/providers/email/email.go +++ b/internal/pkg/core/notifier/providers/email/email.go @@ -3,7 +3,6 @@ import ( "context" "crypto/tls" - "errors" "fmt" "net/smtp" @@ -12,7 +11,7 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/notifier" ) -type EmailNotifierConfig struct { +type NotifierConfig struct { // SMTP 服务器地址。 SmtpHost string `json:"smtpHost"` // SMTP 服务器端口。 @@ -30,23 +29,23 @@ type EmailNotifierConfig struct { ReceiverAddress string `json:"receiverAddress"` } -type EmailNotifier struct { - config *EmailNotifierConfig +type NotifierProvider struct { + config *NotifierConfig } -var _ notifier.Notifier = (*EmailNotifier)(nil) +var _ notifier.Notifier = (*NotifierProvider)(nil) -func New(config *EmailNotifierConfig) (*EmailNotifier, error) { +func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } - return &EmailNotifier{ + return &NotifierProvider{ config: config, }, nil } -func (n *EmailNotifier) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { +func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { var smtpAuth smtp.Auth if n.config.Username != "" || n.config.Password != "" { smtpAuth = smtp.PlainAuth("", n.config.Username, n.config.Password, n.config.SmtpHost) diff --git a/internal/pkg/core/notifier/providers/email/email_test.go b/internal/pkg/core/notifier/providers/email/email_test.go index 1c52d4de..df006c24 100644 --- a/internal/pkg/core/notifier/providers/email/email_test.go +++ b/internal/pkg/core/notifier/providers/email/email_test.go @@ -64,7 +64,7 @@ func TestNotify(t *testing.T) { fmt.Sprintf("RECEIVERADDRESS: %v", fReceiverAddress), }, "\n")) - notifier, err := provider.New(&provider.EmailNotifierConfig{ + notifier, err := provider.NewNotifier(&provider.NotifierConfig{ SmtpHost: fSmtpHost, SmtpPort: int32(fSmtpPort), SmtpTLS: fSmtpTLS, diff --git a/internal/pkg/core/notifier/providers/lark/lark.go b/internal/pkg/core/notifier/providers/lark/lark.go index 4714e280..9c92691a 100644 --- a/internal/pkg/core/notifier/providers/lark/lark.go +++ b/internal/pkg/core/notifier/providers/lark/lark.go @@ -2,35 +2,34 @@ import ( "context" - "errors" "github.com/nikoksr/notify/service/lark" "github.com/usual2970/certimate/internal/pkg/core/notifier" ) -type LarkNotifierConfig struct { +type NotifierConfig struct { // 飞书机器人 Webhook 地址。 WebhookUrl string `json:"webhookUrl"` } -type LarkNotifier struct { - config *LarkNotifierConfig +type NotifierProvider struct { + config *NotifierConfig } -var _ notifier.Notifier = (*LarkNotifier)(nil) +var _ notifier.Notifier = (*NotifierProvider)(nil) -func New(config *LarkNotifierConfig) (*LarkNotifier, error) { +func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } - return &LarkNotifier{ + return &NotifierProvider{ config: config, }, nil } -func (n *LarkNotifier) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { +func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { srv := lark.NewWebhookService(n.config.WebhookUrl) err = srv.Send(ctx, subject, message) diff --git a/internal/pkg/core/notifier/providers/lark/lark_test.go b/internal/pkg/core/notifier/providers/lark/lark_test.go index 0b91ebd7..2b04a7a6 100644 --- a/internal/pkg/core/notifier/providers/lark/lark_test.go +++ b/internal/pkg/core/notifier/providers/lark/lark_test.go @@ -38,7 +38,7 @@ func TestNotify(t *testing.T) { fmt.Sprintf("WEBHOOKURL: %v", fWebhookUrl), }, "\n")) - notifier, err := provider.New(&provider.LarkNotifierConfig{ + notifier, err := provider.NewNotifier(&provider.NotifierConfig{ WebhookUrl: fWebhookUrl, }) if err != nil { diff --git a/internal/pkg/core/notifier/providers/serverchan/serverchan.go b/internal/pkg/core/notifier/providers/serverchan/serverchan.go index 7b5a6de0..51df0893 100644 --- a/internal/pkg/core/notifier/providers/serverchan/serverchan.go +++ b/internal/pkg/core/notifier/providers/serverchan/serverchan.go @@ -2,7 +2,6 @@ import ( "context" - "errors" "net/http" notifyHttp "github.com/nikoksr/notify/service/http" @@ -10,28 +9,28 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/notifier" ) -type ServerChanNotifierConfig struct { +type NotifierConfig struct { // ServerChan 服务地址。 Url string `json:"url"` } -type ServerChanNotifier struct { - config *ServerChanNotifierConfig +type NotifierProvider struct { + config *NotifierConfig } -var _ notifier.Notifier = (*ServerChanNotifier)(nil) +var _ notifier.Notifier = (*NotifierProvider)(nil) -func New(config *ServerChanNotifierConfig) (*ServerChanNotifier, error) { +func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } - return &ServerChanNotifier{ + return &NotifierProvider{ config: config, }, nil } -func (n *ServerChanNotifier) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { +func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { srv := notifyHttp.New() srv.AddReceivers(¬ifyHttp.Webhook{ diff --git a/internal/pkg/core/notifier/providers/serverchan/serverchan_test.go b/internal/pkg/core/notifier/providers/serverchan/serverchan_test.go index db2a4946..6f9c61a3 100644 --- a/internal/pkg/core/notifier/providers/serverchan/serverchan_test.go +++ b/internal/pkg/core/notifier/providers/serverchan/serverchan_test.go @@ -38,7 +38,7 @@ func TestNotify(t *testing.T) { fmt.Sprintf("URL: %v", fUrl), }, "\n")) - notifier, err := provider.New(&provider.ServerChanNotifierConfig{ + notifier, err := provider.NewNotifier(&provider.NotifierConfig{ Url: fUrl, }) if err != nil { diff --git a/internal/pkg/core/notifier/providers/telegram/telegram.go b/internal/pkg/core/notifier/providers/telegram/telegram.go index d1dcc45f..6a1889b3 100644 --- a/internal/pkg/core/notifier/providers/telegram/telegram.go +++ b/internal/pkg/core/notifier/providers/telegram/telegram.go @@ -2,37 +2,36 @@ import ( "context" - "errors" "github.com/nikoksr/notify/service/telegram" "github.com/usual2970/certimate/internal/pkg/core/notifier" ) -type TelegramNotifierConfig struct { +type NotifierConfig struct { // Telegram API Token。 ApiToken string `json:"apiToken"` // Telegram Chat ID。 ChatId int64 `json:"chatId"` } -type TelegramNotifier struct { - config *TelegramNotifierConfig +type NotifierProvider struct { + config *NotifierConfig } -var _ notifier.Notifier = (*TelegramNotifier)(nil) +var _ notifier.Notifier = (*NotifierProvider)(nil) -func New(config *TelegramNotifierConfig) (*TelegramNotifier, error) { +func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } - return &TelegramNotifier{ + return &NotifierProvider{ config: config, }, nil } -func (n *TelegramNotifier) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { +func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { srv, err := telegram.New(n.config.ApiToken) if err != nil { return nil, err diff --git a/internal/pkg/core/notifier/providers/telegram/telegram_test.go b/internal/pkg/core/notifier/providers/telegram/telegram_test.go index fca71e8a..10e93547 100644 --- a/internal/pkg/core/notifier/providers/telegram/telegram_test.go +++ b/internal/pkg/core/notifier/providers/telegram/telegram_test.go @@ -44,7 +44,7 @@ func TestNotify(t *testing.T) { fmt.Sprintf("CHATID: %v", fChartId), }, "\n")) - notifier, err := provider.New(&provider.TelegramNotifierConfig{ + notifier, err := provider.NewNotifier(&provider.NotifierConfig{ ApiToken: fApiToken, ChatId: fChartId, }) diff --git a/internal/pkg/core/notifier/providers/webhook/webhook.go b/internal/pkg/core/notifier/providers/webhook/webhook.go index 3c2bc05f..55c0e668 100644 --- a/internal/pkg/core/notifier/providers/webhook/webhook.go +++ b/internal/pkg/core/notifier/providers/webhook/webhook.go @@ -2,35 +2,34 @@ import ( "context" - "errors" "github.com/nikoksr/notify/service/http" "github.com/usual2970/certimate/internal/pkg/core/notifier" ) -type WebhookNotifierConfig struct { +type NotifierConfig struct { // Webhook URL。 Url string `json:"url"` } -type WebhookNotifier struct { - config *WebhookNotifierConfig +type NotifierProvider struct { + config *NotifierConfig } -var _ notifier.Notifier = (*WebhookNotifier)(nil) +var _ notifier.Notifier = (*NotifierProvider)(nil) -func New(config *WebhookNotifierConfig) (*WebhookNotifier, error) { +func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } - return &WebhookNotifier{ + return &NotifierProvider{ config: config, }, nil } -func (n *WebhookNotifier) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { +func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { srv := http.New() srv.AddReceiversURLs(n.config.Url) diff --git a/internal/pkg/core/notifier/providers/webhook/webhook_test.go b/internal/pkg/core/notifier/providers/webhook/webhook_test.go index 14e2adf6..7afe6be4 100644 --- a/internal/pkg/core/notifier/providers/webhook/webhook_test.go +++ b/internal/pkg/core/notifier/providers/webhook/webhook_test.go @@ -38,7 +38,7 @@ func TestNotify(t *testing.T) { fmt.Sprintf("URL: %v", fUrl), }, "\n")) - notifier, err := provider.New(&provider.WebhookNotifierConfig{ + notifier, err := provider.NewNotifier(&provider.NotifierConfig{ Url: fUrl, }) if err != nil { diff --git a/internal/pkg/core/notifier/providers/wecom/wecom.go b/internal/pkg/core/notifier/providers/wecom/wecom.go index 20938009..63342cb5 100644 --- a/internal/pkg/core/notifier/providers/wecom/wecom.go +++ b/internal/pkg/core/notifier/providers/wecom/wecom.go @@ -2,7 +2,6 @@ import ( "context" - "errors" "net/http" notifyHttp "github.com/nikoksr/notify/service/http" @@ -10,28 +9,28 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/notifier" ) -type WeComNotifierConfig struct { +type NotifierConfig struct { // 企业微信机器人 Webhook 地址。 WebhookUrl string `json:"webhookUrl"` } -type WeComNotifier struct { - config *WeComNotifierConfig +type NotifierProvider struct { + config *NotifierConfig } -var _ notifier.Notifier = (*WeComNotifier)(nil) +var _ notifier.Notifier = (*NotifierProvider)(nil) -func New(config *WeComNotifierConfig) (*WeComNotifier, error) { +func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } - return &WeComNotifier{ + return &NotifierProvider{ config: config, }, nil } -func (n *WeComNotifier) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { +func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { srv := notifyHttp.New() srv.AddReceivers(¬ifyHttp.Webhook{ diff --git a/internal/pkg/core/notifier/providers/wecom/wecom_test.go b/internal/pkg/core/notifier/providers/wecom/wecom_test.go index e1378849..b823adea 100644 --- a/internal/pkg/core/notifier/providers/wecom/wecom_test.go +++ b/internal/pkg/core/notifier/providers/wecom/wecom_test.go @@ -38,7 +38,7 @@ func TestNotify(t *testing.T) { fmt.Sprintf("WEBHOOKURL: %v", fWebhookUrl), }, "\n")) - notifier, err := provider.New(&provider.WeComNotifierConfig{ + notifier, err := provider.NewNotifier(&provider.NotifierConfig{ WebhookUrl: fWebhookUrl, }) if err != nil { diff --git a/internal/pkg/core/uploader/providers/aliyun-cas/aliyun_cas.go b/internal/pkg/core/uploader/providers/aliyun-cas/aliyun_cas.go index ac71202e..202339c4 100644 --- a/internal/pkg/core/uploader/providers/aliyun-cas/aliyun_cas.go +++ b/internal/pkg/core/uploader/providers/aliyun-cas/aliyun_cas.go @@ -2,7 +2,6 @@ import ( "context" - "errors" "fmt" "strings" "time" @@ -16,7 +15,7 @@ import ( "github.com/usual2970/certimate/internal/pkg/utils/certs" ) -type AliyunCASUploaderConfig struct { +type UploaderConfig struct { // 阿里云 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 阿里云 AccessKeySecret。 @@ -25,16 +24,16 @@ type AliyunCASUploaderConfig struct { Region string `json:"region"` } -type AliyunCASUploader struct { - config *AliyunCASUploaderConfig +type UploaderProvider struct { + config *UploaderConfig sdkClient *aliyunCas.Client } -var _ uploader.Uploader = (*AliyunCASUploader)(nil) +var _ uploader.Uploader = (*UploaderProvider)(nil) -func New(config *AliyunCASUploaderConfig) (*AliyunCASUploader, error) { +func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } client, err := createSdkClient( @@ -46,13 +45,13 @@ func New(config *AliyunCASUploaderConfig) (*AliyunCASUploader, error) { return nil, xerrors.Wrap(err, "failed to create sdk client") } - return &AliyunCASUploader{ + return &UploaderProvider{ config: config, sdkClient: client, }, nil } -func (u *AliyunCASUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { +func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 解析证书内容 certX509, err := certs.ParseCertificateFromPEM(certPem) if err != nil { @@ -112,7 +111,7 @@ func (u *AliyunCASUploader) Upload(ctx context.Context, certPem string, privkeyP if listUserCertificateOrderResp.Body.CertificateOrderList == nil || len(listUserCertificateOrderResp.Body.CertificateOrderList) < int(listUserCertificateOrderLimit) { break } else { - listUserCertificateOrderPage += 1 + listUserCertificateOrderPage++ } } diff --git a/internal/pkg/core/uploader/providers/aliyun-slb/aliyun_slb.go b/internal/pkg/core/uploader/providers/aliyun-slb/aliyun_slb.go index 63779b48..c53eced2 100644 --- a/internal/pkg/core/uploader/providers/aliyun-slb/aliyun_slb.go +++ b/internal/pkg/core/uploader/providers/aliyun-slb/aliyun_slb.go @@ -4,7 +4,6 @@ import ( "context" "crypto/sha256" "encoding/hex" - "errors" "fmt" "regexp" "strings" @@ -19,7 +18,7 @@ import ( "github.com/usual2970/certimate/internal/pkg/utils/certs" ) -type AliyunSLBUploaderConfig struct { +type UploaderConfig struct { // 阿里云 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 阿里云 AccessKeySecret。 @@ -28,16 +27,16 @@ type AliyunSLBUploaderConfig struct { Region string `json:"region"` } -type AliyunSLBUploader struct { - config *AliyunSLBUploaderConfig +type UploaderProvider struct { + config *UploaderConfig sdkClient *aliyunSlb.Client } -var _ uploader.Uploader = (*AliyunSLBUploader)(nil) +var _ uploader.Uploader = (*UploaderProvider)(nil) -func New(config *AliyunSLBUploaderConfig) (*AliyunSLBUploader, error) { +func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } client, err := createSdkClient( @@ -49,13 +48,13 @@ func New(config *AliyunSLBUploaderConfig) (*AliyunSLBUploader, error) { return nil, xerrors.Wrap(err, "failed to create sdk client") } - return &AliyunSLBUploader{ + return &UploaderProvider{ config: config, sdkClient: client, }, nil } -func (u *AliyunSLBUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { +func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 解析证书内容 certX509, err := certs.ParseCertificateFromPEM(certPem) if err != nil { diff --git a/internal/pkg/core/uploader/providers/aws-acm/aws_acm.go b/internal/pkg/core/uploader/providers/aws-acm/aws_acm.go index cac4d833..18ffd3aa 100644 --- a/internal/pkg/core/uploader/providers/aws-acm/aws_acm.go +++ b/internal/pkg/core/uploader/providers/aws-acm/aws_acm.go @@ -2,7 +2,6 @@ import ( "context" - "errors" "fmt" "time" @@ -16,7 +15,7 @@ import ( "github.com/usual2970/certimate/internal/pkg/utils/certs" ) -type AWSCertificateManagerUploaderConfig struct { +type UploaderConfig struct { // AWS AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // AWS SecretAccessKey。 @@ -25,16 +24,16 @@ type AWSCertificateManagerUploaderConfig struct { Region string `json:"region"` } -type AWSCertificateManagerUploader struct { - config *AWSCertificateManagerUploaderConfig +type UploaderProvider struct { + config *UploaderConfig sdkClient *awsAcm.Client } -var _ uploader.Uploader = (*AWSCertificateManagerUploader)(nil) +var _ uploader.Uploader = (*UploaderProvider)(nil) -func New(config *AWSCertificateManagerUploaderConfig) (*AWSCertificateManagerUploader, error) { +func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } client, err := createSdkClient(config.AccessKeyId, config.SecretAccessKey, config.Region) @@ -42,13 +41,13 @@ func New(config *AWSCertificateManagerUploaderConfig) (*AWSCertificateManagerUpl return nil, xerrors.Wrap(err, "failed to create sdk client") } - return &AWSCertificateManagerUploader{ + return &UploaderProvider{ config: config, sdkClient: client, }, nil } -func (u *AWSCertificateManagerUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { +func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 解析证书内容 certX509, err := certs.ParseCertificateFromPEM(certPem) if err != nil { diff --git a/internal/pkg/core/uploader/providers/byteplus-cdn/byteplus_cdn.go b/internal/pkg/core/uploader/providers/byteplus-cdn/byteplus_cdn.go index f1bf2b46..04116e31 100644 --- a/internal/pkg/core/uploader/providers/byteplus-cdn/byteplus_cdn.go +++ b/internal/pkg/core/uploader/providers/byteplus-cdn/byteplus_cdn.go @@ -5,7 +5,6 @@ import ( "crypto/sha1" "crypto/sha256" "encoding/hex" - "errors" "fmt" "strings" "time" @@ -17,36 +16,36 @@ import ( "github.com/usual2970/certimate/internal/pkg/utils/certs" ) -type ByteplusCDNUploaderConfig struct { +type UploaderConfig struct { // BytePlus AccessKey。 AccessKey string `json:"accessKey"` // BytePlus SecretKey。 SecretKey string `json:"secretKey"` } -type ByteplusCDNUploader struct { - config *ByteplusCDNUploaderConfig +type UploaderProvider struct { + config *UploaderConfig sdkClient *bpCdn.CDN } -var _ uploader.Uploader = (*ByteplusCDNUploader)(nil) +var _ uploader.Uploader = (*UploaderProvider)(nil) -func New(config *ByteplusCDNUploaderConfig) (*ByteplusCDNUploader, error) { +func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } client := bpCdn.NewInstance() client.Client.SetAccessKey(config.AccessKey) client.Client.SetSecretKey(config.SecretKey) - return &ByteplusCDNUploader{ + return &UploaderProvider{ config: config, sdkClient: client, }, nil } -func (u *ByteplusCDNUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { +func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 解析证书内容 certX509, err := certs.ParseCertificateFromPEM(certPem) if err != nil { diff --git a/internal/pkg/core/uploader/providers/dogecloud/dogecloud.go b/internal/pkg/core/uploader/providers/dogecloud/dogecloud.go index a38e832c..82856b6e 100644 --- a/internal/pkg/core/uploader/providers/dogecloud/dogecloud.go +++ b/internal/pkg/core/uploader/providers/dogecloud/dogecloud.go @@ -2,7 +2,6 @@ import ( "context" - "errors" "fmt" "time" @@ -12,23 +11,23 @@ import ( doge "github.com/usual2970/certimate/internal/pkg/vendors/dogecloud-sdk" ) -type DogeCloudUploaderConfig struct { +type UploaderConfig struct { // 多吉云 AccessKey。 AccessKey string `json:"accessKey"` // 多吉云 SecretKey。 SecretKey string `json:"secretKey"` } -type DogeCloudUploader struct { - config *DogeCloudUploaderConfig +type UploaderProvider struct { + config *UploaderConfig sdkClient *doge.Client } -var _ uploader.Uploader = (*DogeCloudUploader)(nil) +var _ uploader.Uploader = (*UploaderProvider)(nil) -func New(config *DogeCloudUploaderConfig) (*DogeCloudUploader, error) { +func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } client, err := createSdkClient( @@ -39,13 +38,13 @@ func New(config *DogeCloudUploaderConfig) (*DogeCloudUploader, error) { return nil, xerrors.Wrap(err, "failed to create sdk client") } - return &DogeCloudUploader{ + return &UploaderProvider{ config: config, sdkClient: client, }, nil } -func (u *DogeCloudUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { +func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 生成新证书名(需符合多吉云命名规则) var certId, certName string certName = fmt.Sprintf("certimate-%d", time.Now().UnixMilli()) diff --git a/internal/pkg/core/uploader/providers/gcore-cdn/gcore_cdn.go b/internal/pkg/core/uploader/providers/gcore-cdn/gcore_cdn.go new file mode 100644 index 00000000..b990c694 --- /dev/null +++ b/internal/pkg/core/uploader/providers/gcore-cdn/gcore_cdn.go @@ -0,0 +1,83 @@ +package gcorecdn + +import ( + "context" + "errors" + "fmt" + "time" + + gprovider "github.com/G-Core/gcorelabscdn-go/gcore/provider" + gsslcerts "github.com/G-Core/gcorelabscdn-go/sslcerts" + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/uploader" + gcoresdk "github.com/usual2970/certimate/internal/pkg/vendors/gcore-sdk/common" +) + +type UploaderConfig struct { + // Gcore API Token。 + ApiToken string `json:"apiToken"` +} + +type UploaderProvider struct { + config *UploaderConfig + sdkClient *gsslcerts.Service +} + +var _ uploader.Uploader = (*UploaderProvider)(nil) + +func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { + if config == nil { + panic("config is nil") + } + + client, err := createSdkClient(config.ApiToken) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + return &UploaderProvider{ + config: config, + sdkClient: client, + }, nil +} + +func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { + // 生成新证书名(需符合 Gcore 命名规则) + var certId, certName string + certName = fmt.Sprintf("certimate_%d", time.Now().UnixMilli()) + + // 新增证书 + // REF: https://api.gcore.com/docs/cdn#tag/CA-certificates/operation/ca_certificates-add + createCertificateReq := &gsslcerts.CreateRequest{ + Name: certName, + Cert: certPem, + PrivateKey: privkeyPem, + Automated: false, + ValidateRootCA: false, + } + createCertificateResp, err := u.sdkClient.Create(context.TODO(), createCertificateReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'sslcerts.Create'") + } + + certId = fmt.Sprintf("%d", createCertificateResp.ID) + certName = createCertificateResp.Name + return &uploader.UploadResult{ + CertId: certId, + CertName: certName, + }, nil +} + +func createSdkClient(apiToken string) (*gsslcerts.Service, error) { + if apiToken == "" { + return nil, errors.New("invalid gcore api token") + } + + requester := gprovider.NewClient( + gcoresdk.BASE_URL, + gprovider.WithSigner(gcoresdk.NewAuthRequestSigner(apiToken)), + ) + service := gsslcerts.NewService(requester) + return service, nil +} diff --git a/internal/pkg/core/uploader/providers/huaweicloud-elb/huaweicloud_elb.go b/internal/pkg/core/uploader/providers/huaweicloud-elb/huaweicloud_elb.go index 2ea7d031..96a1ff7b 100644 --- a/internal/pkg/core/uploader/providers/huaweicloud-elb/huaweicloud_elb.go +++ b/internal/pkg/core/uploader/providers/huaweicloud-elb/huaweicloud_elb.go @@ -21,7 +21,7 @@ import ( hwsdk "github.com/usual2970/certimate/internal/pkg/vendors/huaweicloud-sdk" ) -type HuaweiCloudELBUploaderConfig struct { +type UploaderConfig struct { // 华为云 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 华为云 SecretAccessKey。 @@ -30,16 +30,16 @@ type HuaweiCloudELBUploaderConfig struct { Region string `json:"region"` } -type HuaweiCloudELBUploader struct { - config *HuaweiCloudELBUploaderConfig +type UploaderProvider struct { + config *UploaderConfig sdkClient *hcElb.ElbClient } -var _ uploader.Uploader = (*HuaweiCloudELBUploader)(nil) +var _ uploader.Uploader = (*UploaderProvider)(nil) -func New(config *HuaweiCloudELBUploaderConfig) (*HuaweiCloudELBUploader, error) { +func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } client, err := createSdkClient( @@ -51,13 +51,13 @@ func New(config *HuaweiCloudELBUploaderConfig) (*HuaweiCloudELBUploader, error) return nil, xerrors.Wrap(err, "failed to create sdk client") } - return &HuaweiCloudELBUploader{ + return &UploaderProvider{ config: config, sdkClient: client, }, nil } -func (u *HuaweiCloudELBUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { +func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 解析证书内容 certX509, err := certs.ParseCertificateFromPEM(certPem) if err != nil { diff --git a/internal/pkg/core/uploader/providers/huaweicloud-scm/huaweicloud_scm.go b/internal/pkg/core/uploader/providers/huaweicloud-scm/huaweicloud_scm.go index c0618da0..9406c55d 100644 --- a/internal/pkg/core/uploader/providers/huaweicloud-scm/huaweicloud_scm.go +++ b/internal/pkg/core/uploader/providers/huaweicloud-scm/huaweicloud_scm.go @@ -2,7 +2,6 @@ import ( "context" - "errors" "fmt" "time" @@ -17,7 +16,7 @@ import ( hwsdk "github.com/usual2970/certimate/internal/pkg/vendors/huaweicloud-sdk" ) -type HuaweiCloudSCMUploaderConfig struct { +type UploaderConfig struct { // 华为云 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 华为云 SecretAccessKey。 @@ -26,16 +25,16 @@ type HuaweiCloudSCMUploaderConfig struct { Region string `json:"region"` } -type HuaweiCloudSCMUploader struct { - config *HuaweiCloudSCMUploaderConfig +type UploaderProvider struct { + config *UploaderConfig sdkClient *hcScm.ScmClient } -var _ uploader.Uploader = (*HuaweiCloudSCMUploader)(nil) +var _ uploader.Uploader = (*UploaderProvider)(nil) -func New(config *HuaweiCloudSCMUploaderConfig) (*HuaweiCloudSCMUploader, error) { +func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } client, err := createSdkClient( @@ -47,13 +46,13 @@ func New(config *HuaweiCloudSCMUploaderConfig) (*HuaweiCloudSCMUploader, error) return nil, xerrors.Wrap(err, "failed to create sdk client") } - return &HuaweiCloudSCMUploader{ + return &UploaderProvider{ config: config, sdkClient: client, }, nil } -func (u *HuaweiCloudSCMUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { +func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 解析证书内容 certX509, err := certs.ParseCertificateFromPEM(certPem) if err != nil { diff --git a/internal/pkg/core/uploader/providers/huaweicloud-waf/huaweicloud_waf.go b/internal/pkg/core/uploader/providers/huaweicloud-waf/huaweicloud_waf.go new file mode 100644 index 00000000..19e7cea7 --- /dev/null +++ b/internal/pkg/core/uploader/providers/huaweicloud-waf/huaweicloud_waf.go @@ -0,0 +1,214 @@ +package huaweicloudwaf + +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic" + "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/global" + hcIam "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/iam/v3" + hcIamModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/iam/v3/model" + hcIamRegion "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/iam/v3/region" + hcWaf "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/waf/v1" + hcWafModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/waf/v1/model" + hcWafRegion "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/waf/v1/region" + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/uploader" + "github.com/usual2970/certimate/internal/pkg/utils/certs" + hwsdk "github.com/usual2970/certimate/internal/pkg/vendors/huaweicloud-sdk" +) + +type UploaderConfig struct { + // 华为云 AccessKeyId。 + AccessKeyId string `json:"accessKeyId"` + // 华为云 SecretAccessKey。 + SecretAccessKey string `json:"secretAccessKey"` + // 华为云区域。 + Region string `json:"region"` +} + +type UploaderProvider struct { + config *UploaderConfig + sdkClient *hcWaf.WafClient +} + +var _ uploader.Uploader = (*UploaderProvider)(nil) + +func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { + if config == nil { + panic("config is nil") + } + + client, err := createSdkClient( + config.AccessKeyId, + config.SecretAccessKey, + config.Region, + ) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + return &UploaderProvider{ + config: config, + sdkClient: client, + }, nil +} + +func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { + // 解析证书内容 + certX509, err := certs.ParseCertificateFromPEM(certPem) + if err != nil { + return nil, err + } + + // 遍历查询已有证书,避免重复上传 + // REF: https://support.huaweicloud.com/api-waf/ListCertificates.html + // REF: https://support.huaweicloud.com/api-waf/ShowCertificate.html + listCertificatesPage := int32(1) + listCertificatesPageSize := int32(100) + for { + listCertificatesReq := &hcWafModel.ListCertificatesRequest{ + Page: hwsdk.Int32Ptr(listCertificatesPage), + Pagesize: hwsdk.Int32Ptr(listCertificatesPageSize), + } + listCertificatesResp, err := u.sdkClient.ListCertificates(listCertificatesReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'waf.ListCertificates'") + } + + if listCertificatesResp.Items != nil { + for _, certItem := range *listCertificatesResp.Items { + showCertificateReq := &hcWafModel.ShowCertificateRequest{ + CertificateId: certItem.Id, + } + showCertificateResp, err := u.sdkClient.ShowCertificate(showCertificateReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'waf.ShowCertificate'") + } + + var isSameCert bool + if *showCertificateResp.Content == certPem { + isSameCert = true + } else { + oldCertX509, err := certs.ParseCertificateFromPEM(*showCertificateResp.Content) + if err != nil { + continue + } + + isSameCert = certs.EqualCertificate(certX509, oldCertX509) + } + + // 如果已存在相同证书,直接返回已有的证书信息 + if isSameCert { + return &uploader.UploadResult{ + CertId: certItem.Id, + CertName: certItem.Name, + }, nil + } + } + } + + if listCertificatesResp.Items == nil || len(*listCertificatesResp.Items) < int(listCertificatesPageSize) { + break + } else { + listCertificatesPage++ + } + } + + // 生成新证书名(需符合华为云命名规则) + var certId, certName string + certName = fmt.Sprintf("certimate-%d", time.Now().UnixMilli()) + + // 创建证书 + // REF: https://support.huaweicloud.com/api-waf/CreateCertificate.html + createCertificateReq := &hcWafModel.CreateCertificateRequest{ + Body: &hcWafModel.CreateCertificateRequestBody{ + Name: certName, + Content: certPem, + Key: privkeyPem, + }, + } + createCertificateResp, err := u.sdkClient.CreateCertificate(createCertificateReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'waf.CreateCertificate'") + } + + certId = *createCertificateResp.Id + certName = *createCertificateResp.Name + return &uploader.UploadResult{ + CertId: certId, + CertName: certName, + }, nil +} + +func createSdkClient(accessKeyId, secretAccessKey, region string) (*hcWaf.WafClient, error) { + projectId, err := getSdkProjectId(accessKeyId, secretAccessKey, region) + if err != nil { + return nil, err + } + + auth, err := basic.NewCredentialsBuilder(). + WithAk(accessKeyId). + WithSk(secretAccessKey). + WithProjectId(projectId). + SafeBuild() + if err != nil { + return nil, err + } + + hcRegion, err := hcWafRegion.SafeValueOf(region) + if err != nil { + return nil, err + } + + hcClient, err := hcWaf.WafClientBuilder(). + WithRegion(hcRegion). + WithCredential(auth). + SafeBuild() + if err != nil { + return nil, err + } + + client := hcWaf.NewWafClient(hcClient) + return client, nil +} + +func getSdkProjectId(accessKeyId, secretAccessKey, region string) (string, error) { + auth, err := global.NewCredentialsBuilder(). + WithAk(accessKeyId). + WithSk(secretAccessKey). + SafeBuild() + if err != nil { + return "", err + } + + hcRegion, err := hcIamRegion.SafeValueOf(region) + if err != nil { + return "", err + } + + hcClient, err := hcIam.IamClientBuilder(). + WithRegion(hcRegion). + WithCredential(auth). + SafeBuild() + if err != nil { + return "", err + } + + client := hcIam.NewIamClient(hcClient) + + request := &hcIamModel.KeystoneListProjectsRequest{ + Name: ®ion, + } + response, err := client.KeystoneListProjects(request) + if err != nil { + return "", err + } else if response.Projects == nil || len(*response.Projects) == 0 { + return "", errors.New("no project found") + } + + return (*response.Projects)[0].Id, nil +} diff --git a/internal/pkg/core/uploader/providers/jdcloud-ssl/jdcloud_ssl.go b/internal/pkg/core/uploader/providers/jdcloud-ssl/jdcloud_ssl.go new file mode 100644 index 00000000..afbbf3e1 --- /dev/null +++ b/internal/pkg/core/uploader/providers/jdcloud-ssl/jdcloud_ssl.go @@ -0,0 +1,139 @@ +package jdcloudssl + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "fmt" + "strings" + "time" + + jdCore "github.com/jdcloud-api/jdcloud-sdk-go/core" + jdSslApi "github.com/jdcloud-api/jdcloud-sdk-go/services/ssl/apis" + jdSslClient "github.com/jdcloud-api/jdcloud-sdk-go/services/ssl/client" + xerrors "github.com/pkg/errors" + "golang.org/x/exp/slices" + + "github.com/usual2970/certimate/internal/pkg/core/uploader" + "github.com/usual2970/certimate/internal/pkg/utils/certs" +) + +type UploaderConfig struct { + // 京东云 AccessKeyId。 + AccessKeyId string `json:"accessKeyId"` + // 京东云 AccessKeySecret。 + AccessKeySecret string `json:"accessKeySecret"` +} + +type UploaderProvider struct { + config *UploaderConfig + sdkClient *jdSslClient.SslClient +} + +var _ uploader.Uploader = (*UploaderProvider)(nil) + +func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { + if config == nil { + panic("config is nil") + } + + client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + return &UploaderProvider{ + config: config, + sdkClient: client, + }, nil +} + +func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { + // 解析证书内容 + certX509, err := certs.ParseCertificateFromPEM(certPem) + if err != nil { + return nil, err + } + + // 格式化私钥内容,以便后续计算私钥摘要 + privkeyPem = strings.TrimSpace(privkeyPem) + privkeyPem = strings.ReplaceAll(privkeyPem, "\r", "") + privkeyPem = strings.ReplaceAll(privkeyPem, "\n", "\r\n") + privkeyPem = privkeyPem + "\r\n" + + // 遍历查看证书列表,避免重复上传 + // REF: https://docs.jdcloud.com/cn/ssl-certificate/api/describecerts + describeCertsPageNumber := 1 + describeCertsPageSize := 10 + for { + describeCertsReq := jdSslApi.NewDescribeCertsRequest() + describeCertsReq.SetDomainName(certX509.Subject.CommonName) + describeCertsReq.SetPageNumber(describeCertsPageNumber) + describeCertsReq.SetPageSize(describeCertsPageSize) + describeCertsResp, err := u.sdkClient.DescribeCerts(describeCertsReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'ssl.DescribeCerts'") + } + + for _, certDetail := range describeCertsResp.Result.CertListDetails { + // 先尝试匹配 CN + if !strings.EqualFold(certX509.Subject.CommonName, certDetail.CommonName) { + continue + } + + // 再尝试匹配 SAN + if !slices.Equal(certX509.DNSNames, certDetail.DnsNames) { + continue + } + + // 再尝试匹配证书有效期 + oldCertNotBefore, _ := time.Parse(time.RFC3339, certDetail.StartTime) + oldCertNotAfter, _ := time.Parse(time.RFC3339, certDetail.EndTime) + if !certX509.NotBefore.Equal(oldCertNotBefore) || !certX509.NotAfter.Equal(oldCertNotAfter) { + continue + } + + // 最后尝试匹配私钥摘要 + newKeyDigest := sha256.Sum256([]byte(privkeyPem)) + newKeyDigestHex := hex.EncodeToString(newKeyDigest[:]) + if !strings.EqualFold(newKeyDigestHex, certDetail.Digest) { + continue + } + + // 如果以上都匹配,则视为已存在相同证书,直接返回已有的证书信息 + return &uploader.UploadResult{ + CertId: certDetail.CertId, + CertName: certDetail.CertName, + }, nil + } + + if len(describeCertsResp.Result.CertListDetails) < int(describeCertsPageSize) { + break + } else { + describeCertsPageNumber++ + } + } + + // 生成新证书名(需符合京东云命名规则) + certName := fmt.Sprintf("certimate-%d", time.Now().UnixMilli()) + + // 上传证书 + // REF: https://docs.jdcloud.com/cn/ssl-certificate/api/uploadcert + uploadCertReq := jdSslApi.NewUploadCertRequest(certName, privkeyPem, certPem) + uploadCertResp, err := u.sdkClient.UploadCert(uploadCertReq) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'ssl.UploadCertificate'") + } + + return &uploader.UploadResult{ + CertId: uploadCertResp.Result.CertId, + CertName: certName, + }, nil +} + +func createSdkClient(accessKeyId, accessKeySecret string) (*jdSslClient.SslClient, error) { + clientCredentials := jdCore.NewCredentials(accessKeyId, accessKeySecret) + client := jdSslClient.NewSslClient(clientCredentials) + client.SetLogger(jdCore.NewDefaultLogger(jdCore.LogWarn)) + return client, nil +} diff --git a/internal/pkg/core/uploader/providers/jdcloud-ssl/jdcloud_ssl_test.go b/internal/pkg/core/uploader/providers/jdcloud-ssl/jdcloud_ssl_test.go new file mode 100644 index 00000000..ec02ce49 --- /dev/null +++ b/internal/pkg/core/uploader/providers/jdcloud-ssl/jdcloud_ssl_test.go @@ -0,0 +1,72 @@ +package jdcloudssl_test + +import ( + "context" + "encoding/json" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/jdcloud-ssl" +) + +var ( + fInputCertPath string + fInputKeyPath string + fAccessKeyId string + fAccessKeySecret string +) + +func init() { + argsPrefix := "CERTIMATE_UPLOADER_JDCLOUDSSL_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "") + flag.StringVar(&fAccessKeySecret, argsPrefix+"ACCESSKEYSECRET", "", "") +} + +/* +Shell command to run this test: + + go test -v ./jdcloud_ssl_test.go -args \ + --CERTIMATE_UPLOADER_JDCLOUDSSL_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_UPLOADER_JDCLOUDSSL_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_UPLOADER_JDCLOUDSSL_ACCESSKEYID="your-access-key-id" \ + --CERTIMATE_UPLOADER_JDCLOUDSSL_ACCESSKEYSECRET="your-access-key-secret" +*/ +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("ACCESSKEYSECRET: %v", fAccessKeySecret), + }, "\n")) + + uploader, err := provider.NewUploader(&provider.UploaderConfig{ + AccessKeyId: fAccessKeyId, + AccessKeySecret: fAccessKeySecret, + }) + if err != nil { + t.Errorf("err: %+v", err) + return + } + + fInputCertData, _ := os.ReadFile(fInputCertPath) + fInputKeyData, _ := os.ReadFile(fInputKeyPath) + res, err := uploader.Upload(context.Background(), string(fInputCertData), string(fInputKeyData)) + if err != nil { + t.Errorf("err: %+v", err) + return + } + + sres, _ := json.Marshal(res) + t.Logf("ok: %s", string(sres)) + }) +} diff --git a/internal/pkg/core/uploader/providers/qiniu-sslcert/qiniu_sslcert.go b/internal/pkg/core/uploader/providers/qiniu-sslcert/qiniu_sslcert.go index 851cbf01..05c57be8 100644 --- a/internal/pkg/core/uploader/providers/qiniu-sslcert/qiniu_sslcert.go +++ b/internal/pkg/core/uploader/providers/qiniu-sslcert/qiniu_sslcert.go @@ -2,7 +2,6 @@ import ( "context" - "errors" "fmt" "time" @@ -14,23 +13,23 @@ import ( qiniuEx "github.com/usual2970/certimate/internal/pkg/vendors/qiniu-sdk" ) -type QiniuSSLCertUploaderConfig struct { +type UploaderConfig struct { // 七牛云 AccessKey。 AccessKey string `json:"accessKey"` // 七牛云 SecretKey。 SecretKey string `json:"secretKey"` } -type QiniuSSLCertUploader struct { - config *QiniuSSLCertUploaderConfig +type UploaderProvider struct { + config *UploaderConfig sdkClient *qiniuEx.Client } -var _ uploader.Uploader = (*QiniuSSLCertUploader)(nil) +var _ uploader.Uploader = (*UploaderProvider)(nil) -func New(config *QiniuSSLCertUploaderConfig) (*QiniuSSLCertUploader, error) { +func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } client, err := createSdkClient( @@ -41,13 +40,13 @@ func New(config *QiniuSSLCertUploaderConfig) (*QiniuSSLCertUploader, error) { return nil, xerrors.Wrap(err, "failed to create sdk client") } - return &QiniuSSLCertUploader{ + return &UploaderProvider{ config: config, sdkClient: client, }, nil } -func (u *QiniuSSLCertUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { +func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 解析证书内容 certX509, err := certs.ParseCertificateFromPEM(certPem) if err != nil { diff --git a/internal/pkg/core/uploader/providers/tencentcloud-ssl/tencentcloud_ssl.go b/internal/pkg/core/uploader/providers/tencentcloud-ssl/tencentcloud_ssl.go index a94af000..a76bf2a0 100644 --- a/internal/pkg/core/uploader/providers/tencentcloud-ssl/tencentcloud_ssl.go +++ b/internal/pkg/core/uploader/providers/tencentcloud-ssl/tencentcloud_ssl.go @@ -2,7 +2,6 @@ import ( "context" - "errors" xerrors "github.com/pkg/errors" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" @@ -12,23 +11,23 @@ import ( "github.com/usual2970/certimate/internal/pkg/core/uploader" ) -type TencentCloudSSLUploaderConfig struct { +type UploaderConfig struct { // 腾讯云 SecretId。 SecretId string `json:"secretId"` // 腾讯云 SecretKey。 SecretKey string `json:"secretKey"` } -type TencentCloudSSLUploader struct { - config *TencentCloudSSLUploaderConfig +type UploaderProvider struct { + config *UploaderConfig sdkClient *tcSsl.Client } -var _ uploader.Uploader = (*TencentCloudSSLUploader)(nil) +var _ uploader.Uploader = (*UploaderProvider)(nil) -func New(config *TencentCloudSSLUploaderConfig) (*TencentCloudSSLUploader, error) { +func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } client, err := createSdkClient( @@ -39,13 +38,13 @@ func New(config *TencentCloudSSLUploaderConfig) (*TencentCloudSSLUploader, error return nil, xerrors.Wrap(err, "failed to create sdk client") } - return &TencentCloudSSLUploader{ + return &UploaderProvider{ config: config, sdkClient: client, }, nil } -func (u *TencentCloudSSLUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { +func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 上传新证书 // REF: https://cloud.tencent.com/document/product/400/41665 uploadCertificateReq := tcSsl.NewUploadCertificateRequest() diff --git a/internal/pkg/core/uploader/providers/ucloud-ussl/ucloud_ussl.go b/internal/pkg/core/uploader/providers/ucloud-ussl/ucloud_ussl.go index 9c5fa2b3..aaa03999 100644 --- a/internal/pkg/core/uploader/providers/ucloud-ussl/ucloud_ussl.go +++ b/internal/pkg/core/uploader/providers/ucloud-ussl/ucloud_ussl.go @@ -20,7 +20,7 @@ import ( usdkSsl "github.com/usual2970/certimate/internal/pkg/vendors/ucloud-sdk/ussl" ) -type UCloudUSSLUploaderConfig struct { +type UploaderConfig struct { // 优刻得 API 私钥。 PrivateKey string `json:"privateKey"` // 优刻得 API 公钥。 @@ -29,16 +29,16 @@ type UCloudUSSLUploaderConfig struct { ProjectId string `json:"projectId,omitempty"` } -type UCloudUSSLUploader struct { - config *UCloudUSSLUploaderConfig +type UploaderProvider struct { + config *UploaderConfig sdkClient *usdkSsl.USSLClient } -var _ uploader.Uploader = (*UCloudUSSLUploader)(nil) +var _ uploader.Uploader = (*UploaderProvider)(nil) -func New(config *UCloudUSSLUploaderConfig) (*UCloudUSSLUploader, error) { +func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } client, err := createSdkClient(config.PrivateKey, config.PublicKey) @@ -46,13 +46,13 @@ func New(config *UCloudUSSLUploaderConfig) (*UCloudUSSLUploader, error) { return nil, xerrors.Wrap(err, "failed to create sdk client") } - return &UCloudUSSLUploader{ + return &UploaderProvider{ config: config, sdkClient: client, }, nil } -func (u *UCloudUSSLUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { +func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 生成新证书名(需符合优刻得命名规则) var certId, certName string certName = fmt.Sprintf("certimate-%d", time.Now().UnixMilli()) @@ -92,7 +92,7 @@ func (u *UCloudUSSLUploader) Upload(ctx context.Context, certPem string, privkey }, nil } -func (u *UCloudUSSLUploader) getExistCert(ctx context.Context, certPem string) (res *uploader.UploadResult, err error) { +func (u *UploaderProvider) getExistCert(ctx context.Context, certPem string) (res *uploader.UploadResult, err error) { // 解析证书内容 certX509, err := certs.ParseCertificateFromPEM(certPem) if err != nil { diff --git a/internal/pkg/core/uploader/providers/ucloud-ussl/ucloud_ussl_test.go b/internal/pkg/core/uploader/providers/ucloud-ussl/ucloud_ussl_test.go index c0a0f719..b6324fd5 100644 --- a/internal/pkg/core/uploader/providers/ucloud-ussl/ucloud_ussl_test.go +++ b/internal/pkg/core/uploader/providers/ucloud-ussl/ucloud_ussl_test.go @@ -49,7 +49,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("PUBLICKEY: %v", fPublicKey), }, "\n")) - uploader, err := provider.New(&provider.UCloudUSSLUploaderConfig{ + uploader, err := provider.NewUploader(&provider.UploaderConfig{ PrivateKey: fPrivateKey, PublicKey: fPublicKey, }) diff --git a/internal/pkg/core/uploader/providers/volcengine-cdn/volcengine_cdn.go b/internal/pkg/core/uploader/providers/volcengine-cdn/volcengine_cdn.go index 23f05281..9b5c9b56 100644 --- a/internal/pkg/core/uploader/providers/volcengine-cdn/volcengine_cdn.go +++ b/internal/pkg/core/uploader/providers/volcengine-cdn/volcengine_cdn.go @@ -5,7 +5,6 @@ import ( "crypto/sha1" "crypto/sha256" "encoding/hex" - "errors" "fmt" "strings" "time" @@ -18,36 +17,36 @@ import ( "github.com/usual2970/certimate/internal/pkg/utils/certs" ) -type VolcEngineCDNUploaderConfig struct { +type UploaderConfig struct { // 火山引擎 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 火山引擎 AccessKeySecret。 AccessKeySecret string `json:"accessKeySecret"` } -type VolcEngineCDNUploader struct { - config *VolcEngineCDNUploaderConfig +type UploaderProvider struct { + config *UploaderConfig sdkClient *veCdn.CDN } -var _ uploader.Uploader = (*VolcEngineCDNUploader)(nil) +var _ uploader.Uploader = (*UploaderProvider)(nil) -func New(config *VolcEngineCDNUploaderConfig) (*VolcEngineCDNUploader, error) { +func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } client := veCdn.NewInstance() client.Client.SetAccessKey(config.AccessKeyId) client.Client.SetSecretKey(config.AccessKeySecret) - return &VolcEngineCDNUploader{ + return &UploaderProvider{ config: config, sdkClient: client, }, nil } -func (u *VolcEngineCDNUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { +func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 解析证书内容 certX509, err := certs.ParseCertificateFromPEM(certPem) if err != nil { diff --git a/internal/pkg/core/uploader/providers/volcengine-certcenter/volcengine_certcenter.go b/internal/pkg/core/uploader/providers/volcengine-certcenter/volcengine_certcenter.go index 5e301ebd..1ff133e5 100644 --- a/internal/pkg/core/uploader/providers/volcengine-certcenter/volcengine_certcenter.go +++ b/internal/pkg/core/uploader/providers/volcengine-certcenter/volcengine_certcenter.go @@ -2,7 +2,6 @@ package volcenginecertcenter import ( "context" - "errors" xerrors "github.com/pkg/errors" ve "github.com/volcengine/volcengine-go-sdk/volcengine" @@ -12,7 +11,7 @@ import ( vesdkCc "github.com/usual2970/certimate/internal/pkg/vendors/volcengine-sdk/certcenter" ) -type VolcEngineCertCenterUploaderConfig struct { +type UploaderConfig struct { // 火山引擎 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 火山引擎 AccessKeySecret。 @@ -21,16 +20,16 @@ type VolcEngineCertCenterUploaderConfig struct { Region string `json:"region"` } -type VolcEngineCertCenterUploader struct { - config *VolcEngineCertCenterUploaderConfig +type UploaderProvider struct { + config *UploaderConfig sdkClient *vesdkCc.CertCenter } -var _ uploader.Uploader = (*VolcEngineCertCenterUploader)(nil) +var _ uploader.Uploader = (*UploaderProvider)(nil) -func New(config *VolcEngineCertCenterUploaderConfig) (*VolcEngineCertCenterUploader, error) { +func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region) @@ -38,13 +37,13 @@ func New(config *VolcEngineCertCenterUploaderConfig) (*VolcEngineCertCenterUploa return nil, xerrors.Wrap(err, "failed to create sdk client") } - return &VolcEngineCertCenterUploader{ + return &UploaderProvider{ config: config, sdkClient: client, }, nil } -func (u *VolcEngineCertCenterUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { +func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 上传证书 // REF: https://www.volcengine.com/docs/6638/1365580 importCertificateReq := &vesdkCc.ImportCertificateInput{ diff --git a/internal/pkg/core/uploader/providers/volcengine-certcenter/volcengine_certcenter_test.go b/internal/pkg/core/uploader/providers/volcengine-certcenter/volcengine_certcenter_test.go index 5f15c44f..5c312707 100644 --- a/internal/pkg/core/uploader/providers/volcengine-certcenter/volcengine_certcenter_test.go +++ b/internal/pkg/core/uploader/providers/volcengine-certcenter/volcengine_certcenter_test.go @@ -49,7 +49,7 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("ACCESSKEYSECRET: %v", fAccessKeySecret), }, "\n")) - uploader, err := provider.New(&provider.VolcEngineCertCenterUploaderConfig{ + uploader, err := provider.NewUploader(&provider.UploaderConfig{ AccessKeyId: fAccessKeyId, AccessKeySecret: fAccessKeySecret, }) diff --git a/internal/pkg/core/uploader/providers/volcengine-live/volcengine_live.go b/internal/pkg/core/uploader/providers/volcengine-live/volcengine_live.go index c7861cb6..3a7a39eb 100644 --- a/internal/pkg/core/uploader/providers/volcengine-live/volcengine_live.go +++ b/internal/pkg/core/uploader/providers/volcengine-live/volcengine_live.go @@ -2,7 +2,6 @@ package volcenginelive import ( "context" - "errors" "fmt" "strings" "time" @@ -15,36 +14,36 @@ import ( "github.com/usual2970/certimate/internal/pkg/utils/certs" ) -type VolcEngineLiveUploaderConfig struct { +type UploaderConfig struct { // 火山引擎 AccessKeyId。 AccessKeyId string `json:"accessKeyId"` // 火山引擎 AccessKeySecret。 AccessKeySecret string `json:"accessKeySecret"` } -type VolcEngineLiveUploader struct { - config *VolcEngineLiveUploaderConfig +type UploaderProvider struct { + config *UploaderConfig sdkClient *veLive.Live } -var _ uploader.Uploader = (*VolcEngineLiveUploader)(nil) +var _ uploader.Uploader = (*UploaderProvider)(nil) -func New(config *VolcEngineLiveUploaderConfig) (*VolcEngineLiveUploader, error) { +func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { if config == nil { - return nil, errors.New("config is nil") + panic("config is nil") } client := veLive.NewInstance() client.SetAccessKey(config.AccessKeyId) client.SetSecretKey(config.AccessKeySecret) - return &VolcEngineLiveUploader{ + return &UploaderProvider{ config: config, sdkClient: client, }, nil } -func (u *VolcEngineLiveUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { +func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 解析证书内容 certX509, err := certs.ParseCertificateFromPEM(certPem) if err != nil { diff --git a/internal/pkg/utils/maps/maps.go b/internal/pkg/utils/maps/maps.go index a88b6629..4a4417d0 100644 --- a/internal/pkg/utils/maps/maps.go +++ b/internal/pkg/utils/maps/maps.go @@ -207,8 +207,3 @@ func Populate(dict map[string]any, output any) error { return decoder.Decode(dict) } - -// Deprecated: Use [Populate] instead. -func Decode(dict map[string]any, output any) error { - return Populate(dict, output) -} diff --git a/internal/pkg/vendors/baishan-sdk/api.go b/internal/pkg/vendors/baishan-sdk/api.go new file mode 100644 index 00000000..c2f76adc --- /dev/null +++ b/internal/pkg/vendors/baishan-sdk/api.go @@ -0,0 +1,32 @@ +package baishansdk + +import ( + "net/http" +) + +func (c *Client) CreateCertificate(req *CreateCertificateRequest) (*CreateCertificateResponse, error) { + resp := CreateCertificateResponse{} + err := c.sendRequestWithResult(http.MethodPost, "/v2/domain/certificate", req, &resp) + if err != nil { + return nil, err + } + return &resp, nil +} + +func (c *Client) GetDomainConfig(req *GetDomainConfigRequest) (*GetDomainConfigResponse, error) { + resp := GetDomainConfigResponse{} + err := c.sendRequestWithResult(http.MethodGet, "/v2/domain/config", req, &resp) + if err != nil { + return nil, err + } + return &resp, nil +} + +func (c *Client) SetDomainConfig(req *SetDomainConfigRequest) (*SetDomainConfigResponse, error) { + resp := SetDomainConfigResponse{} + err := c.sendRequestWithResult(http.MethodPost, "/v2/domain/config", req, &resp) + if err != nil { + return nil, err + } + return &resp, nil +} diff --git a/internal/pkg/vendors/baishan-sdk/client.go b/internal/pkg/vendors/baishan-sdk/client.go new file mode 100644 index 00000000..44015b62 --- /dev/null +++ b/internal/pkg/vendors/baishan-sdk/client.go @@ -0,0 +1,83 @@ +package baishansdk + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + "time" + + "github.com/go-resty/resty/v2" +) + +type Client struct { + apiToken string + + client *resty.Client +} + +func NewClient(apiToken string) *Client { + client := resty.New() + + return &Client{ + apiToken: apiToken, + client: client, + } +} + +func (c *Client) WithTimeout(timeout time.Duration) *Client { + c.client.SetTimeout(timeout) + return c +} + +func (c *Client) sendRequest(method string, path string, params interface{}) (*resty.Response, error) { + req := c.client.R() + req.Method = method + req.URL = "https://cdn.api.baishan.com" + path + if strings.EqualFold(method, http.MethodGet) { + qs := make(map[string]string) + if params != nil { + temp := make(map[string]any) + jsonb, _ := json.Marshal(params) + json.Unmarshal(jsonb, &temp) + for k, v := range temp { + if v != nil { + qs[k] = fmt.Sprintf("%v", v) + } + } + } + + req = req. + SetQueryParams(qs). + SetQueryParam("token", c.apiToken) + } else { + req = req. + SetHeader("Content-Type", "application/json"). + SetQueryParam("token", c.apiToken). + SetBody(params) + } + + resp, err := req.Send() + if err != nil { + return nil, fmt.Errorf("baishan api error: failed to send request: %w", err) + } else if resp.IsError() { + return nil, fmt.Errorf("baishan api error: unexpected status code: %d, %s", resp.StatusCode(), resp.Body()) + } + + return resp, nil +} + +func (c *Client) sendRequestWithResult(method string, path string, params interface{}, result BaseResponse) error { + resp, err := c.sendRequest(method, path, params) + if err != nil { + return err + } + + if err := json.Unmarshal(resp.Body(), &result); err != nil { + return fmt.Errorf("baishan api error: failed to parse response: %w", err) + } else if errcode := result.GetCode(); errcode != 0 { + return fmt.Errorf("baishan api error: %d - %s", errcode, result.GetMessage()) + } + + return nil +} diff --git a/internal/pkg/vendors/baishan-sdk/models.go b/internal/pkg/vendors/baishan-sdk/models.go new file mode 100644 index 00000000..78685571 --- /dev/null +++ b/internal/pkg/vendors/baishan-sdk/models.go @@ -0,0 +1,73 @@ +package baishansdk + +type BaseResponse interface { + GetCode() int + GetMessage() string +} + +type baseResponse struct { + Code int `json:"code"` + Message string `json:"message"` +} + +func (r *baseResponse) GetCode() int { + return r.Code +} + +func (r *baseResponse) GetMessage() string { + return r.Message +} + +type CreateCertificateRequest struct { + Certificate string `json:"certificate"` + Key string `json:"key"` + Name string `json:"name"` +} + +type CreateCertificateResponse struct { + baseResponse + Data *DomainCertificate `json:"data"` +} + +type GetDomainConfigRequest struct { + Domains string `json:"domains"` + Config string `json:"config"` +} + +type GetDomainConfigResponse struct { + baseResponse + Data []*struct { + Domain string `json:"domain"` + Config *DomainConfig `json:"config"` + } `json:"data"` +} + +type SetDomainConfigRequest struct { + Domains string `json:"domains"` + Config *DomainConfig `json:"config"` +} + +type SetDomainConfigResponse struct { + baseResponse + Data *struct { + Config *DomainConfig `json:"config"` + } `json:"data"` +} + +type DomainCertificate struct { + CertId int64 `json:"cert_id"` + Name string `json:"name"` + CertStartTime string `json:"cert_start_time"` + CertExpireTime string `json:"cert_expire_time"` +} + +type DomainConfig struct { + Https *DomainConfigHttps `json:"https"` +} + +type DomainConfigHttps struct { + CertId int64 `json:"cert_id"` + ForceHttps *string `json:"force_https,omitempty"` + EnableHttp2 *string `json:"http2,omitempty"` + EnableOcsp *string `json:"ocsp,omitempty"` +} diff --git a/internal/pkg/vendors/btpanel-sdk/api.go b/internal/pkg/vendors/btpanel-sdk/api.go index 5c58e3df..434e7f6e 100644 --- a/internal/pkg/vendors/btpanel-sdk/api.go +++ b/internal/pkg/vendors/btpanel-sdk/api.go @@ -1,26 +1,46 @@ package btpanelsdk -type BaseResponse interface { - GetStatus() *bool - GetMsg() *string +func (c *Client) ConfigSavePanelSSL(req *ConfigSavePanelSSLRequest) (*ConfigSavePanelSSLResponse, error) { + resp := ConfigSavePanelSSLResponse{} + err := c.sendRequestWithResult("/config?action=SavePanelSSL", req, &resp) + if err != nil { + return nil, err + } + return &resp, nil } -type SetSiteSSLRequest struct { - Type string `json:"type"` - SiteName string `json:"siteName"` - Key string `json:"key"` - Csr string `json:"csr"` +func (c *Client) SiteSetSSL(req *SiteSetSSLRequest) (*SiteSetSSLResponse, error) { + resp := SiteSetSSLResponse{} + err := c.sendRequestWithResult("/site?action=SetSSL", req, &resp) + if err != nil { + return nil, err + } + return &resp, nil } -type SetSiteSSLResponse struct { - Status *bool `json:"status,omitempty"` - Msg *string `json:"msg,omitempty"` +func (c *Client) SystemServiceAdmin(req *SystemServiceAdminRequest) (*SystemServiceAdminResponse, error) { + resp := SystemServiceAdminResponse{} + err := c.sendRequestWithResult("/system?action=ServiceAdmin", req, &resp) + if err != nil { + return nil, err + } + return &resp, nil } -func (r *SetSiteSSLResponse) GetStatus() *bool { - return r.Status +func (c *Client) SSLCertSaveCert(req *SSLCertSaveCertRequest) (*SSLCertSaveCertResponse, error) { + resp := SSLCertSaveCertResponse{} + err := c.sendRequestWithResult("/ssl/cert/save_cert", req, &resp) + if err != nil { + return nil, err + } + return &resp, nil } -func (r *SetSiteSSLResponse) GetMsg() *string { - return r.Msg +func (c *Client) SSLSetBatchCertToSite(req *SSLSetBatchCertToSiteRequest) (*SSLSetBatchCertToSiteResponse, error) { + resp := SSLSetBatchCertToSiteResponse{} + err := c.sendRequestWithResult("/ssl?action=SetBatchCertToSite", req, &resp) + if err != nil { + return nil, err + } + return &resp, nil } diff --git a/internal/pkg/vendors/btpanel-sdk/client.go b/internal/pkg/vendors/btpanel-sdk/client.go index 9557612a..67e9fdb1 100644 --- a/internal/pkg/vendors/btpanel-sdk/client.go +++ b/internal/pkg/vendors/btpanel-sdk/client.go @@ -9,45 +9,31 @@ import ( "time" "github.com/go-resty/resty/v2" - - "github.com/usual2970/certimate/internal/pkg/utils/maps" ) -type BaoTaPanelClient struct { +type Client struct { apiHost string apiKey string - client *resty.Client + + client *resty.Client } -func NewBaoTaPanelClient(apiHost, apiKey string) *BaoTaPanelClient { +func NewClient(apiHost, apiKey string) *Client { client := resty.New() - return &BaoTaPanelClient{ - apiHost: apiHost, + return &Client{ + apiHost: strings.TrimRight(apiHost, "/"), apiKey: apiKey, client: client, } } -func (c *BaoTaPanelClient) WithTimeout(timeout time.Duration) *BaoTaPanelClient { +func (c *Client) WithTimeout(timeout time.Duration) *Client { c.client.SetTimeout(timeout) return c } -func (c *BaoTaPanelClient) SetSiteSSL(req *SetSiteSSLRequest) (*SetSiteSSLResponse, error) { - params := make(map[string]any) - jsonData, _ := json.Marshal(req) - json.Unmarshal(jsonData, ¶ms) - - result := SetSiteSSLResponse{} - err := c.sendRequestWithResult("/site?action=SetSSL", params, &result) - if err != nil { - return nil, err - } - return &result, nil -} - -func (c *BaoTaPanelClient) generateSignature(timestamp string) string { +func (c *Client) generateSignature(timestamp string) string { keyMd5 := md5.Sum([]byte(c.apiKey)) keyMd5Hex := strings.ToLower(hex.EncodeToString(keyMd5[:])) @@ -56,50 +42,50 @@ func (c *BaoTaPanelClient) generateSignature(timestamp string) string { return signMd5Hex } -func (c *BaoTaPanelClient) sendRequest(path string, params map[string]any) (*resty.Response, error) { - if params == nil { - params = make(map[string]any) - } - +func (c *Client) sendRequest(path string, params interface{}) (*resty.Response, error) { timestamp := time.Now().Unix() - params["request_time"] = timestamp - params["request_token"] = c.generateSignature(fmt.Sprintf("%d", timestamp)) - url := strings.TrimRight(c.apiHost, "/") + path + data := make(map[string]any) + if params != nil { + temp := make(map[string]any) + jsonb, _ := json.Marshal(params) + json.Unmarshal(jsonb, &temp) + for k, v := range temp { + if v != nil { + data[k] = v + } + } + } + data["request_time"] = timestamp + data["request_token"] = c.generateSignature(fmt.Sprintf("%d", timestamp)) + + url := c.apiHost + path req := c.client.R(). SetHeader("Content-Type", "application/json"). - SetBody(params) + SetBody(data) resp, err := req.Post(url) if err != nil { - return nil, fmt.Errorf("baota: failed to send request: %w", err) - } - - if resp.IsError() { - return nil, fmt.Errorf("baota: unexpected status code: %d, %s", resp.StatusCode(), resp.Body()) + return nil, fmt.Errorf("baota api error: failed to send request: %w", err) + } else if resp.IsError() { + return nil, fmt.Errorf("baota api error: unexpected status code: %d, %s", resp.StatusCode(), resp.Body()) } return resp, nil } -func (c *BaoTaPanelClient) sendRequestWithResult(path string, params map[string]any, result BaseResponse) error { +func (c *Client) sendRequestWithResult(path string, params interface{}, result BaseResponse) error { resp, err := c.sendRequest(path, params) if err != nil { return err } - jsonResp := make(map[string]any) - if err := json.Unmarshal(resp.Body(), &jsonResp); err != nil { - return fmt.Errorf("baota: failed to parse response: %w", err) - } - if err := maps.Populate(jsonResp, &result); err != nil { - return fmt.Errorf("baota: failed to parse response: %w", err) - } - - if result.GetStatus() != nil && !*result.GetStatus() { - if result.GetMsg() == nil { + if err := json.Unmarshal(resp.Body(), &result); err != nil { + return fmt.Errorf("baota api error: failed to parse response: %w", err) + } else if errstatus := result.GetStatus(); errstatus != nil && !*errstatus { + if result.GetMessage() == nil { return fmt.Errorf("baota api error: unknown error") } else { - return fmt.Errorf("baota api error: %s", *result.GetMsg()) + return fmt.Errorf("baota api error: %s", *result.GetMessage()) } } diff --git a/internal/pkg/vendors/btpanel-sdk/models.go b/internal/pkg/vendors/btpanel-sdk/models.go new file mode 100644 index 00000000..8625e539 --- /dev/null +++ b/internal/pkg/vendors/btpanel-sdk/models.go @@ -0,0 +1,75 @@ +package btpanelsdk + +type BaseResponse interface { + GetStatus() *bool + GetMessage() *string +} + +type baseResponse struct { + Status *bool `json:"status,omitempty"` + Message *string `json:"msg,omitempty"` +} + +func (r *baseResponse) GetStatus() *bool { + return r.Status +} + +func (r *baseResponse) GetMessage() *string { + return r.Message +} + +type ConfigSavePanelSSLRequest struct { + PrivateKey string `json:"privateKey"` + Certificate string `json:"certPem"` +} + +type ConfigSavePanelSSLResponse struct { + baseResponse +} + +type SiteSetSSLRequest struct { + Type string `json:"type"` + SiteName string `json:"siteName"` + PrivateKey string `json:"key"` + Certificate string `json:"csr"` +} + +type SiteSetSSLResponse struct { + baseResponse +} + +type SystemServiceAdminRequest struct { + Name string `json:"name"` + Type string `json:"type"` +} + +type SystemServiceAdminResponse struct { + baseResponse +} + +type SSLCertSaveCertRequest struct { + PrivateKey string `json:"key"` + Certificate string `json:"csr"` +} + +type SSLCertSaveCertResponse struct { + baseResponse + SSLHash string `json:"ssl_hash"` +} + +type SSLSetBatchCertToSiteRequest struct { + BatchInfo []*SSLSetBatchCertToSiteRequestBatchInfo `json:"BatchInfo"` +} + +type SSLSetBatchCertToSiteRequestBatchInfo struct { + SSLHash string `json:"ssl_hash"` + SiteName string `json:"siteName"` + CertName string `json:"certName"` +} + +type SSLSetBatchCertToSiteResponse struct { + baseResponse + TotalCount int32 `json:"total"` + SuccessCount int32 `json:"success"` + FailedCount int32 `json:"faild"` +} diff --git a/internal/pkg/vendors/cachefly-sdk/api.go b/internal/pkg/vendors/cachefly-sdk/api.go new file mode 100644 index 00000000..ad6e3b8d --- /dev/null +++ b/internal/pkg/vendors/cachefly-sdk/api.go @@ -0,0 +1,14 @@ +package cacheflysdk + +import ( + "net/http" +) + +func (c *Client) CreateCertificate(req *CreateCertificateRequest) (*CreateCertificateResponse, error) { + resp := CreateCertificateResponse{} + err := c.sendRequestWithResult(http.MethodPost, "/certificates", req, &resp) + if err != nil { + return nil, err + } + return &resp, nil +} diff --git a/internal/pkg/vendors/cachefly-sdk/client.go b/internal/pkg/vendors/cachefly-sdk/client.go new file mode 100644 index 00000000..505aafaf --- /dev/null +++ b/internal/pkg/vendors/cachefly-sdk/client.go @@ -0,0 +1,79 @@ +package cacheflysdk + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + "time" + + "github.com/go-resty/resty/v2" +) + +type Client struct { + apiToken string + + client *resty.Client +} + +func NewClient(apiToken string) *Client { + client := resty.New() + + return &Client{ + apiToken: apiToken, + client: client, + } +} + +func (c *Client) WithTimeout(timeout time.Duration) *Client { + c.client.SetTimeout(timeout) + return c +} + +func (c *Client) sendRequest(method string, path string, params interface{}) (*resty.Response, error) { + req := c.client.R() + req.Method = method + req.URL = "https://api.cachefly.com/api/2.5" + path + req = req.SetHeader("x-cf-authorization", "Bearer "+c.apiToken) + if strings.EqualFold(method, http.MethodGet) { + qs := make(map[string]string) + if params != nil { + temp := make(map[string]any) + jsonb, _ := json.Marshal(params) + json.Unmarshal(jsonb, &temp) + for k, v := range temp { + if v != nil { + qs[k] = fmt.Sprintf("%v", v) + } + } + } + + req = req.SetQueryParams(qs) + } else { + req = req. + SetHeader("Content-Type", "application/json"). + SetBody(params) + } + + resp, err := req.Send() + if err != nil { + return nil, fmt.Errorf("cachefly api error: failed to send request: %w", err) + } else if resp.IsError() { + return nil, fmt.Errorf("cachefly api error: unexpected status code: %d, %s", resp.StatusCode(), resp.Body()) + } + + return resp, nil +} + +func (c *Client) sendRequestWithResult(method string, path string, params interface{}, result BaseResponse) error { + resp, err := c.sendRequest(method, path, params) + if err != nil { + return err + } + + if err := json.Unmarshal(resp.Body(), &result); err != nil { + return fmt.Errorf("cachefly api error: failed to parse response: %w", err) + } + + return nil +} diff --git a/internal/pkg/vendors/cachefly-sdk/models.go b/internal/pkg/vendors/cachefly-sdk/models.go new file mode 100644 index 00000000..aaca7723 --- /dev/null +++ b/internal/pkg/vendors/cachefly-sdk/models.go @@ -0,0 +1,35 @@ +package cacheflysdk + +type BaseResponse interface { + GetMessage() *string +} + +type baseResponse struct { + Message *string `json:"message,omitempty"` +} + +func (r *baseResponse) GetMessage() *string { + return r.Message +} + +type CreateCertificateRequest struct { + Certificate string `json:"certificate"` + CertificateKey string `json:"certificateKey"` + Password *string `json:"password"` +} + +type CreateCertificateResponse struct { + baseResponse + Id string `json:"_id"` + SubjectCommonName string `json:"subjectCommonName"` + SubjectNames []string `json:"subjectNames"` + Expired bool `json:"expired"` + Expiring bool `json:"expiring"` + InUse bool `json:"inUse"` + Managed bool `json:"managed"` + Services []string `json:"services"` + Domains []string `json:"domains"` + NotBefore string `json:"notBefore"` + NotAfter string `json:"notAfter"` + CreatedAt string `json:"createdAt"` +} diff --git a/internal/pkg/vendors/cdnfly-sdk/api.go b/internal/pkg/vendors/cdnfly-sdk/api.go new file mode 100644 index 00000000..211baa33 --- /dev/null +++ b/internal/pkg/vendors/cdnfly-sdk/api.go @@ -0,0 +1,42 @@ +package cdnflysdk + +import ( + "fmt" + "net/http" +) + +func (c *Client) GetSite(req *GetSiteRequest) (*GetSiteResponse, error) { + resp := GetSiteResponse{} + err := c.sendRequestWithResult(http.MethodGet, fmt.Sprintf("/v1/sites/%s", req.Id), req, &resp) + if err != nil { + return nil, err + } + return &resp, nil +} + +func (c *Client) UpdateSite(req *UpdateSiteRequest) (*UpdateSiteResponse, error) { + resp := UpdateSiteResponse{} + err := c.sendRequestWithResult(http.MethodPut, fmt.Sprintf("/v1/sites/%s", req.Id), req, &resp) + if err != nil { + return nil, err + } + return &resp, nil +} + +func (c *Client) CreateCertificate(req *CreateCertificateRequest) (*CreateCertificateResponse, error) { + resp := CreateCertificateResponse{} + err := c.sendRequestWithResult(http.MethodPost, "/v1/certs", req, &resp) + if err != nil { + return nil, err + } + return &resp, nil +} + +func (c *Client) UpdateCertificate(req *UpdateCertificateRequest) (*UpdateCertificateResponse, error) { + resp := UpdateCertificateResponse{} + err := c.sendRequestWithResult(http.MethodPut, fmt.Sprintf("/v1/certs/%s", req.Id), req, &resp) + if err != nil { + return nil, err + } + return &resp, nil +} diff --git a/internal/pkg/vendors/cdnfly-sdk/client.go b/internal/pkg/vendors/cdnfly-sdk/client.go new file mode 100644 index 00000000..7e2e93f4 --- /dev/null +++ b/internal/pkg/vendors/cdnfly-sdk/client.go @@ -0,0 +1,87 @@ +package cdnflysdk + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + "time" + + "github.com/go-resty/resty/v2" +) + +type Client struct { + apiHost string + apiKey string + apiSecret string + + client *resty.Client +} + +func NewClient(apiHost, apiKey, apiSecret string) *Client { + client := resty.New() + + return &Client{ + apiHost: strings.TrimRight(apiHost, "/"), + apiKey: apiKey, + apiSecret: apiSecret, + client: client, + } +} + +func (c *Client) WithTimeout(timeout time.Duration) *Client { + c.client.SetTimeout(timeout) + return c +} + +func (c *Client) sendRequest(method string, path string, params interface{}) (*resty.Response, error) { + req := c.client.R() + req.Method = method + req.URL = c.apiHost + path + req = req. + SetHeader("api-key", c.apiKey). + SetHeader("api-secret", c.apiSecret) + if strings.EqualFold(method, http.MethodGet) { + qs := make(map[string]string) + if params != nil { + temp := make(map[string]any) + jsonb, _ := json.Marshal(params) + json.Unmarshal(jsonb, &temp) + for k, v := range temp { + if v != nil { + qs[k] = fmt.Sprintf("%v", v) + } + } + } + + req = req.SetQueryParams(qs) + } else { + req = req. + SetHeader("Content-Type", "application/json"). + SetBody(params) + } + + resp, err := req.Send() + if err != nil { + return nil, fmt.Errorf("cdnfly api error: failed to send request: %w", err) + } else if resp.IsError() { + return nil, fmt.Errorf("cdnfly api error: unexpected status code: %d, %s", resp.StatusCode(), resp.Body()) + } + + return resp, nil +} + +func (c *Client) sendRequestWithResult(method string, path string, params interface{}, result BaseResponse) error { + resp, err := c.sendRequest(method, path, params) + if err != nil { + return err + } + + if err := json.Unmarshal(resp.Body(), &result); err != nil { + return fmt.Errorf("cdnfly api error: failed to parse response: %w", err) + } else if errcode := result.GetCode(); errcode != "" && errcode != "0" { + return fmt.Errorf("cdnfly api error: %s - %s", errcode, result.GetMessage()) + } + + return nil +} diff --git a/internal/pkg/vendors/cdnfly-sdk/models.go b/internal/pkg/vendors/cdnfly-sdk/models.go new file mode 100644 index 00000000..873b80b0 --- /dev/null +++ b/internal/pkg/vendors/cdnfly-sdk/models.go @@ -0,0 +1,70 @@ +package cdnflysdk + +type BaseResponse interface { + GetCode() string + GetMessage() string +} + +type baseResponse struct { + Code string `json:"code"` + Message string `json:"msg"` +} + +func (r *baseResponse) GetCode() string { + return r.Code +} + +func (r *baseResponse) GetMessage() string { + return r.Message +} + +type GetSiteRequest struct { + Id string `json:"-"` +} + +type GetSiteResponse struct { + baseResponse + Data *struct { + Id string `json:"id"` + Name string `json:"name"` + Domain string `json:"domain"` + HttpsListen string `json:"https_listen"` + } `json:"data"` +} + +type UpdateSiteRequest struct { + Id string `json:"-"` + HttpsListen *string `json:"https_listen,omitempty"` + Enable *bool `json:"enable,omitempty"` +} + +type UpdateSiteResponse struct { + baseResponse +} + +type CreateCertificateRequest struct { + Name string `json:"name"` + Description *string `json:"des,omitempty"` + Type string `json:"type"` + Cert string `json:"cert"` + Key string `json:"key"` +} + +type CreateCertificateResponse struct { + baseResponse + Data string `json:"data"` +} + +type UpdateCertificateRequest struct { + Id string `json:"-"` + Name *string `json:"name,omitempty"` + Description *string `json:"des,omitempty"` + Type *string `json:"type,omitempty"` + Cert *string `json:"cert,omitempty"` + Key *string `json:"key,omitempty"` + Enable *bool `json:"enable,omitempty"` +} + +type UpdateCertificateResponse struct { + baseResponse +} diff --git a/internal/pkg/vendors/cmcc-sdk/README.md b/internal/pkg/vendors/cmcc-sdk/README.md new file mode 100644 index 00000000..c64eebe8 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/README.md @@ -0,0 +1,14 @@ +移动云 Go SDK 文档: [https://ecloud.10086.cn/op-help-center/doc/article/53799](https://ecloud.10086.cn/op-help-center/doc/article/53799) + +移动云 Go SDK 下载地址: [https://ecloud.10086.cn/api/query/developer/nexus/service/rest/repository/browse/go-sdk/gitlab.ecloud.com/ecloud/](https://ecloud.10086.cn/api/query/developer/nexus/service/rest/repository/browse/go-sdk/gitlab.ecloud.com/ecloud/) + +--- + +将其引入本地目录的原因是: + +1. 原始包必须通过移动云私有仓库获取, 为构建带来不便。 +2. 原始包存在部分内容错误, 需要自行修改, 如: + + - 存在一些编译错误; + - 返回错误的时候, 未返回错误信息; + - 解析响应体错误。 diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/client.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/client.go new file mode 100644 index 00000000..d2c2ccde --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/client.go @@ -0,0 +1,144 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package ecloudsdkclouddns + +import ( + "gitlab.ecloud.com/ecloud/ecloudsdkclouddns/model" + "gitlab.ecloud.com/ecloud/ecloudsdkcore" + "gitlab.ecloud.com/ecloud/ecloudsdkcore/config" +) + +type Client struct { + APIClient *ecloudsdkcore.APIClient + config *config.Config + httpRequest *ecloudsdkcore.HttpRequest +} + +func NewClient(config *config.Config) *Client { + client := &Client{} + client.config = config + apiClient := ecloudsdkcore.NewAPIClient() + httpRequest := ecloudsdkcore.NewDefaultHttpRequest() + httpRequest.Product = product + httpRequest.Version = version + httpRequest.SdkVersion = sdkVersion + client.httpRequest = httpRequest + client.APIClient = apiClient + return client +} + +func NewClientByCustomized(config *config.Config, httpRequest *ecloudsdkcore.HttpRequest) *Client { + client := &Client{} + client.config = config + apiClient := ecloudsdkcore.NewAPIClient() + httpRequest.Product = product + httpRequest.Version = version + httpRequest.SdkVersion = sdkVersion + client.httpRequest = httpRequest + client.APIClient = apiClient + return client +} + +const ( + product string = "clouddns" + version string = "v1" + sdkVersion string = "1.0.1" +) + +// CreateRecord 新增解析记录 +func (c *Client) CreateRecord(request *model.CreateRecordRequest) (*model.CreateRecordResponse, error) { + c.httpRequest.Action = "createRecord" + c.httpRequest.Body = request + returnValue := &model.CreateRecordResponse{} + if _, err := c.APIClient.Excute(c.httpRequest, c.config, returnValue); err != nil { + return nil, err + } else { + return returnValue, nil + } +} + +// CreateRecordOpenapi 新增解析记录Openapi +func (c *Client) CreateRecordOpenapi(request *model.CreateRecordOpenapiRequest) (*model.CreateRecordOpenapiResponse, error) { + c.httpRequest.Action = "createRecordOpenapi" + c.httpRequest.Body = request + returnValue := &model.CreateRecordOpenapiResponse{} + if _, err := c.APIClient.Excute(c.httpRequest, c.config, returnValue); err != nil { + return nil, err + } else { + return returnValue, nil + } +} + +// DeleteRecord 删除解析记录 +func (c *Client) DeleteRecord(request *model.DeleteRecordRequest) (*model.DeleteRecordResponse, error) { + c.httpRequest.Action = "deleteRecord" + c.httpRequest.Body = request + returnValue := &model.DeleteRecordResponse{} + if _, err := c.APIClient.Excute(c.httpRequest, c.config, returnValue); err != nil { + return nil, err + } else { + return returnValue, nil + } +} + +// DeleteRecordOpenapi 删除解析记录Openapi +func (c *Client) DeleteRecordOpenapi(request *model.DeleteRecordOpenapiRequest) (*model.DeleteRecordOpenapiResponse, error) { + c.httpRequest.Action = "deleteRecordOpenapi" + c.httpRequest.Body = request + returnValue := &model.DeleteRecordOpenapiResponse{} + if _, err := c.APIClient.Excute(c.httpRequest, c.config, returnValue); err != nil { + return nil, err + } else { + return returnValue, nil + } +} + +// ListRecord 查询解析记录 +func (c *Client) ListRecord(request *model.ListRecordRequest) (*model.ListRecordResponse, error) { + c.httpRequest.Action = "listRecord" + c.httpRequest.Body = request + returnValue := &model.ListRecordResponse{} + if _, err := c.APIClient.Excute(c.httpRequest, c.config, returnValue); err != nil { + return nil, err + } else { + return returnValue, nil + } +} + +// ListRecordOpenapi 查询解析记录Openapi +func (c *Client) ListRecordOpenapi(request *model.ListRecordOpenapiRequest) (*model.ListRecordOpenapiResponse, error) { + c.httpRequest.Action = "listRecordOpenapi" + c.httpRequest.Body = request + returnValue := &model.ListRecordOpenapiResponse{} + if _, err := c.APIClient.Excute(c.httpRequest, c.config, returnValue); err != nil { + return nil, err + } else { + return returnValue, nil + } +} + +// ModifyRecord 修改解析记录 +func (c *Client) ModifyRecord(request *model.ModifyRecordRequest) (*model.ModifyRecordResponse, error) { + c.httpRequest.Action = "modifyRecord" + c.httpRequest.Body = request + returnValue := &model.ModifyRecordResponse{} + if _, err := c.APIClient.Excute(c.httpRequest, c.config, returnValue); err != nil { + return nil, err + } else { + return returnValue, nil + } +} + +// ModifyRecordOpenapi 修改解析记录Openapi +func (c *Client) ModifyRecordOpenapi(request *model.ModifyRecordOpenapiRequest) (*model.ModifyRecordOpenapiResponse, error) { + c.httpRequest.Action = "modifyRecordOpenapi" + c.httpRequest.Body = request + returnValue := &model.ModifyRecordOpenapiResponse{} + if _, err := c.APIClient.Excute(c.httpRequest, c.config, returnValue); err != nil { + return nil, err + } else { + return returnValue, nil + } +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/go.mod b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/go.mod new file mode 100644 index 00000000..39812459 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/go.mod @@ -0,0 +1,7 @@ +module gitlab.ecloud.com/ecloud/ecloudsdkclouddns + +go 1.23.0 + +require gitlab.ecloud.com/ecloud/ecloudsdkcore v1.0.0 + +replace gitlab.ecloud.com/ecloud/ecloudsdkcore v1.0.0 => ../ecloudsdkcore@v1.0.0 diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_body.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_body.go new file mode 100644 index 00000000..1175cde9 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_body.go @@ -0,0 +1,54 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + +import ( + "gitlab.ecloud.com/ecloud/ecloudsdkcore/position" +) +type CreateRecordBodyTypeEnum string + +// List of Type +const ( + CreateRecordBodyTypeEnumA CreateRecordBodyTypeEnum = "A" + CreateRecordBodyTypeEnumAaaa CreateRecordBodyTypeEnum = "AAAA" + CreateRecordBodyTypeEnumCaa CreateRecordBodyTypeEnum = "CAA" + CreateRecordBodyTypeEnumCmauth CreateRecordBodyTypeEnum = "CMAUTH" + CreateRecordBodyTypeEnumCname CreateRecordBodyTypeEnum = "CNAME" + CreateRecordBodyTypeEnumMx CreateRecordBodyTypeEnum = "MX" + CreateRecordBodyTypeEnumNs CreateRecordBodyTypeEnum = "NS" + CreateRecordBodyTypeEnumPtr CreateRecordBodyTypeEnum = "PTR" + CreateRecordBodyTypeEnumRp CreateRecordBodyTypeEnum = "RP" + CreateRecordBodyTypeEnumSpf CreateRecordBodyTypeEnum = "SPF" + CreateRecordBodyTypeEnumSrv CreateRecordBodyTypeEnum = "SRV" + CreateRecordBodyTypeEnumTxt CreateRecordBodyTypeEnum = "TXT" + CreateRecordBodyTypeEnumUrl CreateRecordBodyTypeEnum = "URL" +) + +type CreateRecordBody struct { + position.Body + // 主机头 + Rr string `json:"rr"` + + // 域名名称 + DomainName string `json:"domainName"` + + // 备注 + Description string `json:"description,omitempty"` + + // 线路ID + LineId string `json:"lineId"` + + // MX优先级,若“记录类型”选择”MX”,则需要配置该参数,默认是5 + MxPri *int32 `json:"mxPri,omitempty"` + + // 记录类型 + Type CreateRecordBodyTypeEnum `json:"type"` + + // 缓存的生命周期,默认可配置600s + Ttl *int32 `json:"ttl,omitempty"` + + // 记录值 + Value string `json:"value"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_openapi_body.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_openapi_body.go new file mode 100644 index 00000000..3db9f0f7 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_openapi_body.go @@ -0,0 +1,51 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + +import ( + "gitlab.ecloud.com/ecloud/ecloudsdkcore/position" +) +type CreateRecordOpenapiBodyTypeEnum string + +// List of Type +const ( + CreateRecordOpenapiBodyTypeEnumA CreateRecordOpenapiBodyTypeEnum = "A" + CreateRecordOpenapiBodyTypeEnumAaaa CreateRecordOpenapiBodyTypeEnum = "AAAA" + CreateRecordOpenapiBodyTypeEnumCname CreateRecordOpenapiBodyTypeEnum = "CNAME" + CreateRecordOpenapiBodyTypeEnumMx CreateRecordOpenapiBodyTypeEnum = "MX" + CreateRecordOpenapiBodyTypeEnumTxt CreateRecordOpenapiBodyTypeEnum = "TXT" + CreateRecordOpenapiBodyTypeEnumNs CreateRecordOpenapiBodyTypeEnum = "NS" + CreateRecordOpenapiBodyTypeEnumSpf CreateRecordOpenapiBodyTypeEnum = "SPF" + CreateRecordOpenapiBodyTypeEnumSrv CreateRecordOpenapiBodyTypeEnum = "SRV" + CreateRecordOpenapiBodyTypeEnumCaa CreateRecordOpenapiBodyTypeEnum = "CAA" + CreateRecordOpenapiBodyTypeEnumCmauth CreateRecordOpenapiBodyTypeEnum = "CMAUTH" +) + +type CreateRecordOpenapiBody struct { + position.Body + // 主机头 + Rr string `json:"rr"` + + // 域名名称 + DomainName string `json:"domainName"` + + // 备注 + Description string `json:"description,omitempty"` + + // 线路ID + LineId string `json:"lineId"` + + // MX优先级,若“记录类型”选择”MX”,则需要配置该参数,默认是5 + MxPri *int32 `json:"mxPri,omitempty"` + + // 记录类型 + Type CreateRecordOpenapiBodyTypeEnum `json:"type"` + + // 缓存的生命周期,默认可配置600s + Ttl *int32 `json:"ttl,omitempty"` + + // 记录值 + Value string `json:"value"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_openapi_request.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_openapi_request.go new file mode 100644 index 00000000..d43fded1 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_openapi_request.go @@ -0,0 +1,12 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + + +type CreateRecordOpenapiRequest struct { + + CreateRecordOpenapiBody *CreateRecordOpenapiBody `json:"createRecordOpenapiBody,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_openapi_response.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_openapi_response.go new file mode 100644 index 00000000..a33b47c7 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_openapi_response.go @@ -0,0 +1,29 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + +type CreateRecordOpenapiResponseStateEnum string + +// List of State +const ( + CreateRecordOpenapiResponseStateEnumError CreateRecordOpenapiResponseStateEnum = "ERROR" + CreateRecordOpenapiResponseStateEnumException CreateRecordOpenapiResponseStateEnum = "EXCEPTION" + CreateRecordOpenapiResponseStateEnumForbidden CreateRecordOpenapiResponseStateEnum = "FORBIDDEN" + CreateRecordOpenapiResponseStateEnumOk CreateRecordOpenapiResponseStateEnum = "OK" +) + +type CreateRecordOpenapiResponse struct { + + RequestId string `json:"requestId,omitempty"` + + ErrorMessage string `json:"errorMessage,omitempty"` + + ErrorCode string `json:"errorCode,omitempty"` + + State CreateRecordOpenapiResponseStateEnum `json:"state,omitempty"` + + Body *CreateRecordOpenapiResponseBody `json:"body,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_openapi_response_body.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_openapi_response_body.go new file mode 100644 index 00000000..e7c62769 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_openapi_response_body.go @@ -0,0 +1,80 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + +type CreateRecordOpenapiResponseBodyTypeEnum string + +// List of Type +const ( + CreateRecordOpenapiResponseBodyTypeEnumA CreateRecordOpenapiResponseBodyTypeEnum = "A" + CreateRecordOpenapiResponseBodyTypeEnumAaaa CreateRecordOpenapiResponseBodyTypeEnum = "AAAA" + CreateRecordOpenapiResponseBodyTypeEnumCname CreateRecordOpenapiResponseBodyTypeEnum = "CNAME" + CreateRecordOpenapiResponseBodyTypeEnumMx CreateRecordOpenapiResponseBodyTypeEnum = "MX" + CreateRecordOpenapiResponseBodyTypeEnumTxt CreateRecordOpenapiResponseBodyTypeEnum = "TXT" + CreateRecordOpenapiResponseBodyTypeEnumNs CreateRecordOpenapiResponseBodyTypeEnum = "NS" + CreateRecordOpenapiResponseBodyTypeEnumSpf CreateRecordOpenapiResponseBodyTypeEnum = "SPF" + CreateRecordOpenapiResponseBodyTypeEnumSrv CreateRecordOpenapiResponseBodyTypeEnum = "SRV" + CreateRecordOpenapiResponseBodyTypeEnumCaa CreateRecordOpenapiResponseBodyTypeEnum = "CAA" + CreateRecordOpenapiResponseBodyTypeEnumCmauth CreateRecordOpenapiResponseBodyTypeEnum = "CMAUTH" +) +type CreateRecordOpenapiResponseBodyStateEnum string + +// List of State +const ( + CreateRecordOpenapiResponseBodyStateEnumDisabled CreateRecordOpenapiResponseBodyStateEnum = "DISABLED" + CreateRecordOpenapiResponseBodyStateEnumEnabled CreateRecordOpenapiResponseBodyStateEnum = "ENABLED" +) + +type CreateRecordOpenapiResponseBody struct { + + // 主机头 + Rr string `json:"rr,omitempty"` + + // 修改时间 + ModifiedTime string `json:"modifiedTime,omitempty"` + + // 线路中文名 + LineZh string `json:"lineZh,omitempty"` + + // 备注 + Description string `json:"description,omitempty"` + + // 线路ID + LineId string `json:"lineId,omitempty"` + + // 权重值 + Weight *int32 `json:"weight,omitempty"` + + // MX优先级 + MxPri *int32 `json:"mxPri,omitempty"` + + // 记录类型 + Type CreateRecordOpenapiResponseBodyTypeEnum `json:"type,omitempty"` + + // 缓存的生命周期 + Ttl *int32 `json:"ttl,omitempty"` + + // 标签 + Tags *[]CreateRecordOpenapiResponseTags `json:"tags,omitempty"` + + // 解析记录ID + RecordId string `json:"recordId,omitempty"` + + // 域名名称 + DomainName string `json:"domainName,omitempty"` + + // 线路英文名 + LineEn string `json:"lineEn,omitempty"` + + // 状态 + State CreateRecordOpenapiResponseBodyStateEnum `json:"state,omitempty"` + + // 记录值 + Value string `json:"value,omitempty"` + + // 定时发布时间 + Pubdate string `json:"pubdate,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_openapi_response_tags.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_openapi_response_tags.go new file mode 100644 index 00000000..a4bda62c --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_openapi_response_tags.go @@ -0,0 +1,16 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + + +type CreateRecordOpenapiResponseTags struct { + + // 标签ID + TagId string `json:"tagId,omitempty"` + + // 标签名称 + Value string `json:"value,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_request.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_request.go new file mode 100644 index 00000000..715f03ff --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_request.go @@ -0,0 +1,12 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + + +type CreateRecordRequest struct { + + CreateRecordBody *CreateRecordBody `json:"createRecordBody,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_response.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_response.go new file mode 100644 index 00000000..bd277c0c --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_response.go @@ -0,0 +1,29 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + +type CreateRecordResponseStateEnum string + +// List of State +const ( + CreateRecordResponseStateEnumError CreateRecordResponseStateEnum = "ERROR" + CreateRecordResponseStateEnumException CreateRecordResponseStateEnum = "EXCEPTION" + CreateRecordResponseStateEnumForbidden CreateRecordResponseStateEnum = "FORBIDDEN" + CreateRecordResponseStateEnumOk CreateRecordResponseStateEnum = "OK" +) + +type CreateRecordResponse struct { + + RequestId string `json:"requestId,omitempty"` + + ErrorMessage string `json:"errorMessage,omitempty"` + + ErrorCode string `json:"errorCode,omitempty"` + + State CreateRecordResponseStateEnum `json:"state,omitempty"` + + Body *CreateRecordResponseBody `json:"body,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_response_body.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_response_body.go new file mode 100644 index 00000000..64660b91 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_response_body.go @@ -0,0 +1,94 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + +type CreateRecordResponseBodyTypeEnum string + +// List of Type +const ( + CreateRecordResponseBodyTypeEnumA CreateRecordResponseBodyTypeEnum = "A" + CreateRecordResponseBodyTypeEnumAaaa CreateRecordResponseBodyTypeEnum = "AAAA" + CreateRecordResponseBodyTypeEnumCaa CreateRecordResponseBodyTypeEnum = "CAA" + CreateRecordResponseBodyTypeEnumCmauth CreateRecordResponseBodyTypeEnum = "CMAUTH" + CreateRecordResponseBodyTypeEnumCname CreateRecordResponseBodyTypeEnum = "CNAME" + CreateRecordResponseBodyTypeEnumMx CreateRecordResponseBodyTypeEnum = "MX" + CreateRecordResponseBodyTypeEnumNs CreateRecordResponseBodyTypeEnum = "NS" + CreateRecordResponseBodyTypeEnumPtr CreateRecordResponseBodyTypeEnum = "PTR" + CreateRecordResponseBodyTypeEnumRp CreateRecordResponseBodyTypeEnum = "RP" + CreateRecordResponseBodyTypeEnumSpf CreateRecordResponseBodyTypeEnum = "SPF" + CreateRecordResponseBodyTypeEnumSrv CreateRecordResponseBodyTypeEnum = "SRV" + CreateRecordResponseBodyTypeEnumTxt CreateRecordResponseBodyTypeEnum = "TXT" + CreateRecordResponseBodyTypeEnumUrl CreateRecordResponseBodyTypeEnum = "URL" +) +type CreateRecordResponseBodyTimedStatusEnum string + +// List of TimedStatus +const ( + CreateRecordResponseBodyTimedStatusEnumDisabled CreateRecordResponseBodyTimedStatusEnum = "DISABLED" + CreateRecordResponseBodyTimedStatusEnumEnabled CreateRecordResponseBodyTimedStatusEnum = "ENABLED" + CreateRecordResponseBodyTimedStatusEnumTimed CreateRecordResponseBodyTimedStatusEnum = "TIMED" +) +type CreateRecordResponseBodyStateEnum string + +// List of State +const ( + CreateRecordResponseBodyStateEnumDisabled CreateRecordResponseBodyStateEnum = "DISABLED" + CreateRecordResponseBodyStateEnumEnabled CreateRecordResponseBodyStateEnum = "ENABLED" +) + +type CreateRecordResponseBody struct { + + // 主机头 + Rr string `json:"rr,omitempty"` + + // 修改时间 + ModifiedTime string `json:"modifiedTime,omitempty"` + + // 线路中文名 + LineZh string `json:"lineZh,omitempty"` + + // 备注 + Description string `json:"description,omitempty"` + + // 线路ID + LineId string `json:"lineId,omitempty"` + + // 权重值 + Weight *int32 `json:"weight,omitempty"` + + // MX优先级 + MxPri *int32 `json:"mxPri,omitempty"` + + // 记录类型 + Type CreateRecordResponseBodyTypeEnum `json:"type,omitempty"` + + // 缓存的生命周期 + Ttl *int32 `json:"ttl,omitempty"` + + // 标签 + Tags *[]CreateRecordResponseTags `json:"tags,omitempty"` + + // 解析记录ID + RecordId string `json:"recordId,omitempty"` + + // 定时状态 + TimedStatus CreateRecordResponseBodyTimedStatusEnum `json:"timedStatus,omitempty"` + + // 域名名称 + DomainName string `json:"domainName,omitempty"` + + // 线路英文名 + LineEn string `json:"lineEn,omitempty"` + + // 状态 + State CreateRecordResponseBodyStateEnum `json:"state,omitempty"` + + // 记录值 + Value string `json:"value,omitempty"` + + // 定时发布时间 + Pubdate string `json:"pubdate,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_response_tags.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_response_tags.go new file mode 100644 index 00000000..003680d5 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/create_record_response_tags.go @@ -0,0 +1,16 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + + +type CreateRecordResponseTags struct { + + // 标签ID + TagId string `json:"tagId,omitempty"` + + // 标签名称 + Value string `json:"value,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/delete_record_body.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/delete_record_body.go new file mode 100644 index 00000000..326b9abb --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/delete_record_body.go @@ -0,0 +1,15 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + +import ( + "gitlab.ecloud.com/ecloud/ecloudsdkcore/position" +) + +type DeleteRecordBody struct { + position.Body + // 解析记录ID列表 + RecordIdList []string `json:"recordIdList"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/delete_record_openapi_body.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/delete_record_openapi_body.go new file mode 100644 index 00000000..e5614ac5 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/delete_record_openapi_body.go @@ -0,0 +1,15 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + +import ( + "gitlab.ecloud.com/ecloud/ecloudsdkcore/position" +) + +type DeleteRecordOpenapiBody struct { + position.Body + // 待删除的解析记录ID请求体 + RecordIdList []string `json:"recordIdList"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/delete_record_openapi_request.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/delete_record_openapi_request.go new file mode 100644 index 00000000..1cb684d6 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/delete_record_openapi_request.go @@ -0,0 +1,12 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + + +type DeleteRecordOpenapiRequest struct { + + DeleteRecordOpenapiBody *DeleteRecordOpenapiBody `json:"deleteRecordOpenapiBody,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/delete_record_openapi_response.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/delete_record_openapi_response.go new file mode 100644 index 00000000..ca528148 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/delete_record_openapi_response.go @@ -0,0 +1,29 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + +type DeleteRecordOpenapiResponseStateEnum string + +// List of State +const ( + DeleteRecordOpenapiResponseStateEnumError DeleteRecordOpenapiResponseStateEnum = "ERROR" + DeleteRecordOpenapiResponseStateEnumException DeleteRecordOpenapiResponseStateEnum = "EXCEPTION" + DeleteRecordOpenapiResponseStateEnumForbidden DeleteRecordOpenapiResponseStateEnum = "FORBIDDEN" + DeleteRecordOpenapiResponseStateEnumOk DeleteRecordOpenapiResponseStateEnum = "OK" +) + +type DeleteRecordOpenapiResponse struct { + + RequestId string `json:"requestId,omitempty"` + + ErrorMessage string `json:"errorMessage,omitempty"` + + ErrorCode string `json:"errorCode,omitempty"` + + State DeleteRecordOpenapiResponseStateEnum `json:"state,omitempty"` + + Body *[]DeleteRecordOpenapiResponseBody `json:"body,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/delete_record_openapi_response_body.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/delete_record_openapi_response_body.go new file mode 100644 index 00000000..67da3ab7 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/delete_record_openapi_response_body.go @@ -0,0 +1,29 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + +type DeleteRecordOpenapiResponseBodyCodeEnum string + +// List of Code +const ( + DeleteRecordOpenapiResponseBodyCodeEnumError DeleteRecordOpenapiResponseBodyCodeEnum = "ERROR" + DeleteRecordOpenapiResponseBodyCodeEnumSuccess DeleteRecordOpenapiResponseBodyCodeEnum = "SUCCESS" +) + +type DeleteRecordOpenapiResponseBody struct { + + // 结果说明 + Msg string `json:"msg,omitempty"` + + // 解析记录ID + RecordId string `json:"recordId,omitempty"` + + // 结果码 + Code DeleteRecordOpenapiResponseBodyCodeEnum `json:"code,omitempty"` + + // 域名 + DomainName string `json:"domainName,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/delete_record_request.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/delete_record_request.go new file mode 100644 index 00000000..678fd8ef --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/delete_record_request.go @@ -0,0 +1,12 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + + +type DeleteRecordRequest struct { + + DeleteRecordBody *DeleteRecordBody `json:"deleteRecordBody,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/delete_record_response.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/delete_record_response.go new file mode 100644 index 00000000..051d7105 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/delete_record_response.go @@ -0,0 +1,29 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + +type DeleteRecordResponseStateEnum string + +// List of State +const ( + DeleteRecordResponseStateEnumError DeleteRecordResponseStateEnum = "ERROR" + DeleteRecordResponseStateEnumException DeleteRecordResponseStateEnum = "EXCEPTION" + DeleteRecordResponseStateEnumForbidden DeleteRecordResponseStateEnum = "FORBIDDEN" + DeleteRecordResponseStateEnumOk DeleteRecordResponseStateEnum = "OK" +) + +type DeleteRecordResponse struct { + + RequestId string `json:"requestId,omitempty"` + + ErrorMessage string `json:"errorMessage,omitempty"` + + ErrorCode string `json:"errorCode,omitempty"` + + State DeleteRecordResponseStateEnum `json:"state,omitempty"` + + Body *[]DeleteRecordResponseBody `json:"body,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/delete_record_response_body.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/delete_record_response_body.go new file mode 100644 index 00000000..45320290 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/delete_record_response_body.go @@ -0,0 +1,29 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + +type DeleteRecordResponseBodyCodeEnum string + +// List of Code +const ( + DeleteRecordResponseBodyCodeEnumError DeleteRecordResponseBodyCodeEnum = "ERROR" + DeleteRecordResponseBodyCodeEnumSuccess DeleteRecordResponseBodyCodeEnum = "SUCCESS" +) + +type DeleteRecordResponseBody struct { + + // 结果说明 + Msg string `json:"msg,omitempty"` + + // 解析记录ID + RecordId string `json:"recordId,omitempty"` + + // 结果码 + Code DeleteRecordResponseBodyCodeEnum `json:"code,omitempty"` + + // 域名 + DomainName string `json:"domainName,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_body.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_body.go new file mode 100644 index 00000000..5eadce7a --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_body.go @@ -0,0 +1,18 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + +import ( + "gitlab.ecloud.com/ecloud/ecloudsdkcore/position" +) + +type ListRecordBody struct { + position.Body + // 域名 + DomainName string `json:"domainName"` + + // 可以匹配主机头rr、记录值value、备注description,并且是模糊搜索 + DataLike string `json:"dataLike,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_openapi_body.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_openapi_body.go new file mode 100644 index 00000000..63f5e13a --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_openapi_body.go @@ -0,0 +1,15 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + +import ( + "gitlab.ecloud.com/ecloud/ecloudsdkcore/position" +) + +type ListRecordOpenapiBody struct { + position.Body + // 域名 + DomainName string `json:"domainName"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_openapi_query.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_openapi_query.go new file mode 100644 index 00000000..ee89a7f5 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_openapi_query.go @@ -0,0 +1,18 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + +import ( + "gitlab.ecloud.com/ecloud/ecloudsdkcore/position" +) + +type ListRecordOpenapiQuery struct { + position.Query + // 页大小 + PageSize *int32 `json:"pageSize,omitempty"` + + // 当前页 + Page *int32 `json:"page,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_openapi_request.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_openapi_request.go new file mode 100644 index 00000000..34540481 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_openapi_request.go @@ -0,0 +1,14 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + + +type ListRecordOpenapiRequest struct { + + ListRecordOpenapiQuery *ListRecordOpenapiQuery `json:"listRecordOpenapiQuery,omitempty"` + + ListRecordOpenapiBody *ListRecordOpenapiBody `json:"listRecordOpenapiBody,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_openapi_response.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_openapi_response.go new file mode 100644 index 00000000..36646938 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_openapi_response.go @@ -0,0 +1,29 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + +type ListRecordOpenapiResponseStateEnum string + +// List of State +const ( + ListRecordOpenapiResponseStateEnumError ListRecordOpenapiResponseStateEnum = "ERROR" + ListRecordOpenapiResponseStateEnumException ListRecordOpenapiResponseStateEnum = "EXCEPTION" + ListRecordOpenapiResponseStateEnumForbidden ListRecordOpenapiResponseStateEnum = "FORBIDDEN" + ListRecordOpenapiResponseStateEnumOk ListRecordOpenapiResponseStateEnum = "OK" +) + +type ListRecordOpenapiResponse struct { + + RequestId string `json:"requestId,omitempty"` + + ErrorMessage string `json:"errorMessage,omitempty"` + + ErrorCode string `json:"errorCode,omitempty"` + + State ListRecordOpenapiResponseStateEnum `json:"state,omitempty"` + + Body *ListRecordOpenapiResponseBody `json:"body,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_openapi_response_body.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_openapi_response_body.go new file mode 100644 index 00000000..8c6f7302 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_openapi_response_body.go @@ -0,0 +1,25 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + + +type ListRecordOpenapiResponseBody struct { + + // 当前页的具体数据列表 + Data *[]ListRecordOpenapiResponseData `json:"data,omitempty"` + + // 总数据量 + TotalNum *int32 `json:"totalNum,omitempty"` + + // 总页数 + TotalPages *int32 `json:"totalPages,omitempty"` + + // 页大小 + PageSize *int32 `json:"pageSize,omitempty"` + + // 当前页码,从0开始,0表示第一页 + Page *int32 `json:"page,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_openapi_response_data.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_openapi_response_data.go new file mode 100644 index 00000000..19981aa9 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_openapi_response_data.go @@ -0,0 +1,91 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + +type ListRecordOpenapiResponseDataTypeEnum string + +// List of Type +const ( + ListRecordOpenapiResponseDataTypeEnumA ListRecordOpenapiResponseDataTypeEnum = "A" + ListRecordOpenapiResponseDataTypeEnumAaaa ListRecordOpenapiResponseDataTypeEnum = "AAAA" + ListRecordOpenapiResponseDataTypeEnumCname ListRecordOpenapiResponseDataTypeEnum = "CNAME" + ListRecordOpenapiResponseDataTypeEnumMx ListRecordOpenapiResponseDataTypeEnum = "MX" + ListRecordOpenapiResponseDataTypeEnumTxt ListRecordOpenapiResponseDataTypeEnum = "TXT" + ListRecordOpenapiResponseDataTypeEnumNs ListRecordOpenapiResponseDataTypeEnum = "NS" + ListRecordOpenapiResponseDataTypeEnumSpf ListRecordOpenapiResponseDataTypeEnum = "SPF" + ListRecordOpenapiResponseDataTypeEnumSrv ListRecordOpenapiResponseDataTypeEnum = "SRV" + ListRecordOpenapiResponseDataTypeEnumCaa ListRecordOpenapiResponseDataTypeEnum = "CAA" + ListRecordOpenapiResponseDataTypeEnumCmauth ListRecordOpenapiResponseDataTypeEnum = "CMAUTH" +) +type ListRecordOpenapiResponseDataTimedStatusEnum string + +// List of TimedStatus +const ( + ListRecordOpenapiResponseDataTimedStatusEnumDisabled ListRecordOpenapiResponseDataTimedStatusEnum = "DISABLED" + ListRecordOpenapiResponseDataTimedStatusEnumEnabled ListRecordOpenapiResponseDataTimedStatusEnum = "ENABLED" + ListRecordOpenapiResponseDataTimedStatusEnumTimed ListRecordOpenapiResponseDataTimedStatusEnum = "TIMED" +) +type ListRecordOpenapiResponseDataStateEnum string + +// List of State +const ( + ListRecordOpenapiResponseDataStateEnumDisabled ListRecordOpenapiResponseDataStateEnum = "DISABLED" + ListRecordOpenapiResponseDataStateEnumEnabled ListRecordOpenapiResponseDataStateEnum = "ENABLED" +) + +type ListRecordOpenapiResponseData struct { + + // 主机头 + Rr string `json:"rr,omitempty"` + + // 修改时间 + ModifiedTime string `json:"modifiedTime,omitempty"` + + // 线路中文名 + LineZh string `json:"lineZh,omitempty"` + + // 备注 + Description string `json:"description,omitempty"` + + // 线路ID + LineId string `json:"lineId,omitempty"` + + // 权重值 + Weight *int32 `json:"weight,omitempty"` + + // MX优先级 + MxPri *int32 `json:"mxPri,omitempty"` + + // 记录类型 + Type ListRecordOpenapiResponseDataTypeEnum `json:"type,omitempty"` + + // 缓存的生命周期 + Ttl *int32 `json:"ttl,omitempty"` + + // 标签 + Tags *[]ListRecordOpenapiResponseTags `json:"tags,omitempty"` + + // 解析记录ID + RecordId string `json:"recordId,omitempty"` + + // 定时状态 + TimedStatus ListRecordOpenapiResponseDataTimedStatusEnum `json:"timedStatus,omitempty"` + + // 域名名称 + DomainName string `json:"domainName,omitempty"` + + // 线路英文名 + LineEn string `json:"lineEn,omitempty"` + + // 状态 + State ListRecordOpenapiResponseDataStateEnum `json:"state,omitempty"` + + // 记录值 + Value string `json:"value,omitempty"` + + // 定时发布时间 + Pubdate string `json:"pubdate,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_openapi_response_tags.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_openapi_response_tags.go new file mode 100644 index 00000000..867f667f --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_openapi_response_tags.go @@ -0,0 +1,16 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + + +type ListRecordOpenapiResponseTags struct { + + // 标签ID + TagId string `json:"tagId,omitempty"` + + // 标签名称 + Value string `json:"value,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_query.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_query.go new file mode 100644 index 00000000..df871a76 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_query.go @@ -0,0 +1,18 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + +import ( + "gitlab.ecloud.com/ecloud/ecloudsdkcore/position" +) + +type ListRecordQuery struct { + position.Query + // 页大小 + PageSize *int32 `json:"pageSize,omitempty"` + + // 当前页 + CurrentPage *int32 `json:"currentPage,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_request.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_request.go new file mode 100644 index 00000000..5ff9df08 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_request.go @@ -0,0 +1,14 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + + +type ListRecordRequest struct { + + ListRecordBody *ListRecordBody `json:"listRecordBody,omitempty"` + + ListRecordQuery *ListRecordQuery `json:"listRecordQuery,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_response.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_response.go new file mode 100644 index 00000000..b11f3d21 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_response.go @@ -0,0 +1,29 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + +type ListRecordResponseStateEnum string + +// List of State +const ( + ListRecordResponseStateEnumError ListRecordResponseStateEnum = "ERROR" + ListRecordResponseStateEnumException ListRecordResponseStateEnum = "EXCEPTION" + ListRecordResponseStateEnumForbidden ListRecordResponseStateEnum = "FORBIDDEN" + ListRecordResponseStateEnumOk ListRecordResponseStateEnum = "OK" +) + +type ListRecordResponse struct { + + RequestId string `json:"requestId,omitempty"` + + ErrorMessage string `json:"errorMessage,omitempty"` + + ErrorCode string `json:"errorCode,omitempty"` + + State ListRecordResponseStateEnum `json:"state,omitempty"` + + Body *ListRecordResponseBody `json:"body,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_response_body.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_response_body.go new file mode 100644 index 00000000..0acf543d --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_response_body.go @@ -0,0 +1,22 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + + +type ListRecordResponseBody struct { + + // 总页数 + TotalPages *int32 `json:"totalPages,omitempty"` + + // 当前页码,从0开始,0表示第一页 + CurrentPage *int32 `json:"currentPage,omitempty"` + + // 当前页的具体数据列表 + Results *[]ListRecordResponseResults `json:"results,omitempty"` + + // 总数据量 + TotalElements *int64 `json:"totalElements,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_response_results.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_response_results.go new file mode 100644 index 00000000..7498fca3 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/list_record_response_results.go @@ -0,0 +1,91 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + +type ListRecordResponseResultsTypeEnum string + +// List of Type +const ( + ListRecordResponseResultsTypeEnumA ListRecordResponseResultsTypeEnum = "A" + ListRecordResponseResultsTypeEnumAaaa ListRecordResponseResultsTypeEnum = "AAAA" + ListRecordResponseResultsTypeEnumCaa ListRecordResponseResultsTypeEnum = "CAA" + ListRecordResponseResultsTypeEnumCmauth ListRecordResponseResultsTypeEnum = "CMAUTH" + ListRecordResponseResultsTypeEnumCname ListRecordResponseResultsTypeEnum = "CNAME" + ListRecordResponseResultsTypeEnumMx ListRecordResponseResultsTypeEnum = "MX" + ListRecordResponseResultsTypeEnumNs ListRecordResponseResultsTypeEnum = "NS" + ListRecordResponseResultsTypeEnumPtr ListRecordResponseResultsTypeEnum = "PTR" + ListRecordResponseResultsTypeEnumRp ListRecordResponseResultsTypeEnum = "RP" + ListRecordResponseResultsTypeEnumSpf ListRecordResponseResultsTypeEnum = "SPF" + ListRecordResponseResultsTypeEnumSrv ListRecordResponseResultsTypeEnum = "SRV" + ListRecordResponseResultsTypeEnumTxt ListRecordResponseResultsTypeEnum = "TXT" + ListRecordResponseResultsTypeEnumUrl ListRecordResponseResultsTypeEnum = "URL" +) +type ListRecordResponseResultsTimedStatusEnum string + +// List of TimedStatus +const ( + ListRecordResponseResultsTimedStatusEnumDisabled ListRecordResponseResultsTimedStatusEnum = "DISABLED" + ListRecordResponseResultsTimedStatusEnumEnabled ListRecordResponseResultsTimedStatusEnum = "ENABLED" + ListRecordResponseResultsTimedStatusEnumTimed ListRecordResponseResultsTimedStatusEnum = "TIMED" +) +type ListRecordResponseResultsStateEnum string + +// List of State +const ( + ListRecordResponseResultsStateEnumDisabled ListRecordResponseResultsStateEnum = "DISABLED" + ListRecordResponseResultsStateEnumEnabled ListRecordResponseResultsStateEnum = "ENABLED" +) + +type ListRecordResponseResults struct { + + // 主机头 + Rr string `json:"rr,omitempty"` + + // 修改时间 + ModifiedTime string `json:"modifiedTime,omitempty"` + + // 线路中文名 + LineZh string `json:"lineZh,omitempty"` + + // 备注 + Description string `json:"description,omitempty"` + + // 线路ID + LineId string `json:"lineId,omitempty"` + + // 权重值 + Weight *int32 `json:"weight,omitempty"` + + // MX优先级 + MxPri *int32 `json:"mxPri,omitempty"` + + // 记录类型 + Type ListRecordResponseResultsTypeEnum `json:"type,omitempty"` + + // 缓存的生命周期 + Ttl *int32 `json:"ttl,omitempty"` + + // 解析记录ID + RecordId string `json:"recordId,omitempty"` + + // 定时状态 + TimedStatus ListRecordResponseResultsTimedStatusEnum `json:"timedStatus,omitempty"` + + // 域名名称 + DomainName string `json:"domainName,omitempty"` + + // 线路英文名 + LineEn string `json:"lineEn,omitempty"` + + // 状态 + State ListRecordResponseResultsStateEnum `json:"state,omitempty"` + + // 记录值 + Value string `json:"value,omitempty"` + + // 定时发布时间 + Pubdate string `json:"pubdate,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_body.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_body.go new file mode 100644 index 00000000..ab772c09 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_body.go @@ -0,0 +1,57 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + +import ( + "gitlab.ecloud.com/ecloud/ecloudsdkcore/position" +) +type ModifyRecordBodyTypeEnum string + +// List of Type +const ( + ModifyRecordBodyTypeEnumA ModifyRecordBodyTypeEnum = "A" + ModifyRecordBodyTypeEnumAaaa ModifyRecordBodyTypeEnum = "AAAA" + ModifyRecordBodyTypeEnumCaa ModifyRecordBodyTypeEnum = "CAA" + ModifyRecordBodyTypeEnumCmauth ModifyRecordBodyTypeEnum = "CMAUTH" + ModifyRecordBodyTypeEnumCname ModifyRecordBodyTypeEnum = "CNAME" + ModifyRecordBodyTypeEnumMx ModifyRecordBodyTypeEnum = "MX" + ModifyRecordBodyTypeEnumNs ModifyRecordBodyTypeEnum = "NS" + ModifyRecordBodyTypeEnumPtr ModifyRecordBodyTypeEnum = "PTR" + ModifyRecordBodyTypeEnumRp ModifyRecordBodyTypeEnum = "RP" + ModifyRecordBodyTypeEnumSpf ModifyRecordBodyTypeEnum = "SPF" + ModifyRecordBodyTypeEnumSrv ModifyRecordBodyTypeEnum = "SRV" + ModifyRecordBodyTypeEnumTxt ModifyRecordBodyTypeEnum = "TXT" + ModifyRecordBodyTypeEnumUrl ModifyRecordBodyTypeEnum = "URL" +) + +type ModifyRecordBody struct { + position.Body + // 解析记录ID + RecordId string `json:"recordId"` + + // 主机头 + Rr string `json:"rr,omitempty"` + + // 域名名称 + DomainName string `json:"domainName"` + + // 备注 + Description string `json:"description,omitempty"` + + // 线路ID + LineId string `json:"lineId,omitempty"` + + // MX优先级 + MxPri *int32 `json:"mxPri,omitempty"` + + // 记录类型 + Type ModifyRecordBodyTypeEnum `json:"type,omitempty"` + + // 缓存的生命周期 + Ttl *int32 `json:"ttl,omitempty"` + + // 记录值 + Value string `json:"value,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_openapi_body.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_openapi_body.go new file mode 100644 index 00000000..3bde8919 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_openapi_body.go @@ -0,0 +1,54 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + +import ( + "gitlab.ecloud.com/ecloud/ecloudsdkcore/position" +) +type ModifyRecordOpenapiBodyTypeEnum string + +// List of Type +const ( + ModifyRecordOpenapiBodyTypeEnumA ModifyRecordOpenapiBodyTypeEnum = "A" + ModifyRecordOpenapiBodyTypeEnumAaaa ModifyRecordOpenapiBodyTypeEnum = "AAAA" + ModifyRecordOpenapiBodyTypeEnumCname ModifyRecordOpenapiBodyTypeEnum = "CNAME" + ModifyRecordOpenapiBodyTypeEnumMx ModifyRecordOpenapiBodyTypeEnum = "MX" + ModifyRecordOpenapiBodyTypeEnumTxt ModifyRecordOpenapiBodyTypeEnum = "TXT" + ModifyRecordOpenapiBodyTypeEnumNs ModifyRecordOpenapiBodyTypeEnum = "NS" + ModifyRecordOpenapiBodyTypeEnumSpf ModifyRecordOpenapiBodyTypeEnum = "SPF" + ModifyRecordOpenapiBodyTypeEnumSrv ModifyRecordOpenapiBodyTypeEnum = "SRV" + ModifyRecordOpenapiBodyTypeEnumCaa ModifyRecordOpenapiBodyTypeEnum = "CAA" + ModifyRecordOpenapiBodyTypeEnumCmauth ModifyRecordOpenapiBodyTypeEnum = "CMAUTH" +) + +type ModifyRecordOpenapiBody struct { + position.Body + // 解析记录ID + RecordId string `json:"recordId"` + + // 主机头 + Rr string `json:"rr,omitempty"` + + // 域名名称 + DomainName string `json:"domainName"` + + // 备注 + Description string `json:"description,omitempty"` + + // 线路ID + LineId string `json:"lineId,omitempty"` + + // MX优先级 + MxPri *int32 `json:"mxPri,omitempty"` + + // 记录类型 + Type ModifyRecordOpenapiBodyTypeEnum `json:"type,omitempty"` + + // 缓存的生命周期 + Ttl *int32 `json:"ttl,omitempty"` + + // 记录值 + Value string `json:"value,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_openapi_request.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_openapi_request.go new file mode 100644 index 00000000..fd1ffe00 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_openapi_request.go @@ -0,0 +1,12 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + + +type ModifyRecordOpenapiRequest struct { + + ModifyRecordOpenapiBody *ModifyRecordOpenapiBody `json:"modifyRecordOpenapiBody,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_openapi_response.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_openapi_response.go new file mode 100644 index 00000000..97d7552f --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_openapi_response.go @@ -0,0 +1,29 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + +type ModifyRecordOpenapiResponseStateEnum string + +// List of State +const ( + ModifyRecordOpenapiResponseStateEnumError ModifyRecordOpenapiResponseStateEnum = "ERROR" + ModifyRecordOpenapiResponseStateEnumException ModifyRecordOpenapiResponseStateEnum = "EXCEPTION" + ModifyRecordOpenapiResponseStateEnumForbidden ModifyRecordOpenapiResponseStateEnum = "FORBIDDEN" + ModifyRecordOpenapiResponseStateEnumOk ModifyRecordOpenapiResponseStateEnum = "OK" +) + +type ModifyRecordOpenapiResponse struct { + + RequestId string `json:"requestId,omitempty"` + + ErrorMessage string `json:"errorMessage,omitempty"` + + ErrorCode string `json:"errorCode,omitempty"` + + State ModifyRecordOpenapiResponseStateEnum `json:"state,omitempty"` + + Body *ModifyRecordOpenapiResponseBody `json:"body,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_openapi_response_body.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_openapi_response_body.go new file mode 100644 index 00000000..6dfcec71 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_openapi_response_body.go @@ -0,0 +1,91 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + +type ModifyRecordOpenapiResponseBodyTypeEnum string + +// List of Type +const ( + ModifyRecordOpenapiResponseBodyTypeEnumA ModifyRecordOpenapiResponseBodyTypeEnum = "A" + ModifyRecordOpenapiResponseBodyTypeEnumAaaa ModifyRecordOpenapiResponseBodyTypeEnum = "AAAA" + ModifyRecordOpenapiResponseBodyTypeEnumCname ModifyRecordOpenapiResponseBodyTypeEnum = "CNAME" + ModifyRecordOpenapiResponseBodyTypeEnumMx ModifyRecordOpenapiResponseBodyTypeEnum = "MX" + ModifyRecordOpenapiResponseBodyTypeEnumTxt ModifyRecordOpenapiResponseBodyTypeEnum = "TXT" + ModifyRecordOpenapiResponseBodyTypeEnumNs ModifyRecordOpenapiResponseBodyTypeEnum = "NS" + ModifyRecordOpenapiResponseBodyTypeEnumSpf ModifyRecordOpenapiResponseBodyTypeEnum = "SPF" + ModifyRecordOpenapiResponseBodyTypeEnumSrv ModifyRecordOpenapiResponseBodyTypeEnum = "SRV" + ModifyRecordOpenapiResponseBodyTypeEnumCaa ModifyRecordOpenapiResponseBodyTypeEnum = "CAA" + ModifyRecordOpenapiResponseBodyTypeEnumCmauth ModifyRecordOpenapiResponseBodyTypeEnum = "CMAUTH" +) +type ModifyRecordOpenapiResponseBodyTimedStatusEnum string + +// List of TimedStatus +const ( + ModifyRecordOpenapiResponseBodyTimedStatusEnumDisabled ModifyRecordOpenapiResponseBodyTimedStatusEnum = "DISABLED" + ModifyRecordOpenapiResponseBodyTimedStatusEnumEnabled ModifyRecordOpenapiResponseBodyTimedStatusEnum = "ENABLED" + ModifyRecordOpenapiResponseBodyTimedStatusEnumTimed ModifyRecordOpenapiResponseBodyTimedStatusEnum = "TIMED" +) +type ModifyRecordOpenapiResponseBodyStateEnum string + +// List of State +const ( + ModifyRecordOpenapiResponseBodyStateEnumDisabled ModifyRecordOpenapiResponseBodyStateEnum = "DISABLED" + ModifyRecordOpenapiResponseBodyStateEnumEnabled ModifyRecordOpenapiResponseBodyStateEnum = "ENABLED" +) + +type ModifyRecordOpenapiResponseBody struct { + + // 主机头 + Rr string `json:"rr,omitempty"` + + // 修改时间 + ModifiedTime string `json:"modifiedTime,omitempty"` + + // 线路中文名 + LineZh string `json:"lineZh,omitempty"` + + // 备注 + Description string `json:"description,omitempty"` + + // 线路ID + LineId string `json:"lineId,omitempty"` + + // 权重值 + Weight *int32 `json:"weight,omitempty"` + + // MX优先级 + MxPri *int32 `json:"mxPri,omitempty"` + + // 记录类型 + Type ModifyRecordOpenapiResponseBodyTypeEnum `json:"type,omitempty"` + + // 缓存的生命周期 + Ttl *int32 `json:"ttl,omitempty"` + + // 标签 + Tags *[]ModifyRecordOpenapiResponseTags `json:"tags,omitempty"` + + // 解析记录ID + RecordId string `json:"recordId,omitempty"` + + // 定时状态 + TimedStatus ModifyRecordOpenapiResponseBodyTimedStatusEnum `json:"timedStatus,omitempty"` + + // 域名名称 + DomainName string `json:"domainName,omitempty"` + + // 线路英文名 + LineEn string `json:"lineEn,omitempty"` + + // 状态 + State ModifyRecordOpenapiResponseBodyStateEnum `json:"state,omitempty"` + + // 记录值 + Value string `json:"value,omitempty"` + + // 定时发布时间 + Pubdate string `json:"pubdate,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_openapi_response_tags.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_openapi_response_tags.go new file mode 100644 index 00000000..62c2e780 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_openapi_response_tags.go @@ -0,0 +1,16 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + + +type ModifyRecordOpenapiResponseTags struct { + + // 标签ID + TagId string `json:"tagId,omitempty"` + + // 标签名称 + Value string `json:"value,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_request.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_request.go new file mode 100644 index 00000000..d92abb44 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_request.go @@ -0,0 +1,12 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + + +type ModifyRecordRequest struct { + + ModifyRecordBody *ModifyRecordBody `json:"modifyRecordBody,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_response.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_response.go new file mode 100644 index 00000000..45b1ae0f --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_response.go @@ -0,0 +1,29 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + +type ModifyRecordResponseStateEnum string + +// List of State +const ( + ModifyRecordResponseStateEnumError ModifyRecordResponseStateEnum = "ERROR" + ModifyRecordResponseStateEnumException ModifyRecordResponseStateEnum = "EXCEPTION" + ModifyRecordResponseStateEnumForbidden ModifyRecordResponseStateEnum = "FORBIDDEN" + ModifyRecordResponseStateEnumOk ModifyRecordResponseStateEnum = "OK" +) + +type ModifyRecordResponse struct { + + RequestId string `json:"requestId,omitempty"` + + ErrorMessage string `json:"errorMessage,omitempty"` + + ErrorCode string `json:"errorCode,omitempty"` + + State ModifyRecordResponseStateEnum `json:"state,omitempty"` + + Body *ModifyRecordResponseBody `json:"body,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_response_body.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_response_body.go new file mode 100644 index 00000000..3df09342 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkclouddns@v1.0.1/model/modify_record_response_body.go @@ -0,0 +1,77 @@ +// @Title Golang SDK Client +// @Description This code is auto generated +// @Author Ecloud SDK + +package model + + +type ModifyRecordResponseBodyTypeEnum string + +// List of Type +const ( + ModifyRecordResponseBodyTypeEnumA ModifyRecordResponseBodyTypeEnum = "A" + ModifyRecordResponseBodyTypeEnumAaaa ModifyRecordResponseBodyTypeEnum = "AAAA" + ModifyRecordResponseBodyTypeEnumCaa ModifyRecordResponseBodyTypeEnum = "CAA" + ModifyRecordResponseBodyTypeEnumCmauth ModifyRecordResponseBodyTypeEnum = "CMAUTH" + ModifyRecordResponseBodyTypeEnumCname ModifyRecordResponseBodyTypeEnum = "CNAME" + ModifyRecordResponseBodyTypeEnumMx ModifyRecordResponseBodyTypeEnum = "MX" + ModifyRecordResponseBodyTypeEnumNs ModifyRecordResponseBodyTypeEnum = "NS" + ModifyRecordResponseBodyTypeEnumPtr ModifyRecordResponseBodyTypeEnum = "PTR" + ModifyRecordResponseBodyTypeEnumRp ModifyRecordResponseBodyTypeEnum = "RP" + ModifyRecordResponseBodyTypeEnumSpf ModifyRecordResponseBodyTypeEnum = "SPF" + ModifyRecordResponseBodyTypeEnumSrv ModifyRecordResponseBodyTypeEnum = "SRV" + ModifyRecordResponseBodyTypeEnumTxt ModifyRecordResponseBodyTypeEnum = "TXT" + ModifyRecordResponseBodyTypeEnumUrl ModifyRecordResponseBodyTypeEnum = "URL" +) +type ModifyRecordResponseBodyStateEnum string + +// List of State +const ( + ModifyRecordResponseBodyStateEnumDisabled ModifyRecordResponseBodyStateEnum = "DISABLED" + ModifyRecordResponseBodyStateEnumEnabled ModifyRecordResponseBodyStateEnum = "ENABLED" +) + +type ModifyRecordResponseBody struct { + + // 主机头 + Rr string `json:"rr,omitempty"` + + // 修改时间 + ModifiedTime string `json:"modifiedTime,omitempty"` + + // 线路中文名 + LineZh string `json:"lineZh,omitempty"` + + // 备注 + Description string `json:"description,omitempty"` + + // 线路ID + LineId string `json:"lineId,omitempty"` + + // 权重值 + Weight *int32 `json:"weight,omitempty"` + + // MX优先级 + MxPri *int32 `json:"mxPri,omitempty"` + + // 记录类型 + Type ModifyRecordResponseBodyTypeEnum `json:"type,omitempty"` + + // 缓存的生命周期 + Ttl *int32 `json:"ttl,omitempty"` + + // 解析记录ID + RecordId string `json:"recordId,omitempty"` + + // 域名名称 + DomainName string `json:"domainName,omitempty"` + + // 线路英文名 + LineEn string `json:"lineEn,omitempty"` + + // 状态 + State ModifyRecordResponseBodyStateEnum `json:"state,omitempty"` + + // 记录值 + Value string `json:"value,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0/api_client.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0/api_client.go new file mode 100644 index 00000000..8f73b499 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0/api_client.go @@ -0,0 +1,507 @@ +package ecloudsdkcore + +import ( + "bytes" + "encoding/json" + "encoding/xml" + "errors" + "fmt" + "gitlab.ecloud.com/ecloud/ecloudsdkcore/config" + "io" + "io/ioutil" + "mime/multipart" + "net/http" + "net/url" + "os" + "path/filepath" + "reflect" + "regexp" + "strconv" + "strings" + "time" + "unicode/utf8" +) + +var ( + jsonCheck = regexp.MustCompile("(?i:(?:application|text)/json)") + xmlCheck = regexp.MustCompile("(?i:(?:application|text)/xml)") +) + +// APIClient manages communication +// In most cases there should be only one, shared, APIClient. +type APIClient struct { + cfg *Configuration + common service +} + +type service struct { + client *APIClient +} + +type HttpRequestPosition string + +const ( + BODY HttpRequestPosition = "Body" + QUERY HttpRequestPosition = "Query" + PATH HttpRequestPosition = "Path" + HEADER HttpRequestPosition = "Header" +) + +const SdkPortalUrl = "/op-apim-portal/apim/request/sdk" +const SdkPortalGatewayUrl = "/api/query/openapi/apim/request/sdk" + +// NewAPIClient creates a new API client. +func NewAPIClient() *APIClient { + cfg := NewConfiguration() + if cfg.HTTPClient == nil { + cfg.HTTPClient = http.DefaultClient + } + c := &APIClient{} + c.cfg = cfg + c.common.client = c + return c +} + +// atoi string to int +func atoi(in string) (int, error) { + return strconv.Atoi(in) +} + +// selectHeaderContentType select a content type from the available list. +func selectHeaderContentType(contentTypes []string) string { + if len(contentTypes) == 0 { + return "" + } + if contains(contentTypes, "application/json") { + return "application/json" + } + return contentTypes[0] +} + +// selectHeaderAccept join all accept types and return +func selectHeaderAccept(accepts []string) string { + if len(accepts) == 0 { + return "" + } + + if contains(accepts, "application/json") { + return "application/json" + } + + return strings.Join(accepts, ",") +} + +// contains is a case insenstive match, finding needle in a haystack +func contains(haystack []string, needle string) bool { + for _, a := range haystack { + if strings.ToLower(a) == strings.ToLower(needle) { + return true + } + } + return false +} + +// Verify optional parameters are of the correct type. +func typeCheckParameter(obj interface{}, expected string, name string) error { + if obj == nil { + return nil + } + if reflect.TypeOf(obj).String() != expected { + return fmt.Errorf("Expected %s to be of type %s but received %s.", name, expected, reflect.TypeOf(obj).String()) + } + return nil +} + +// parameterToString convert interface{} parameters to string, using a delimiter if format is provided. +func parameterToString(obj interface{}, collectionFormat string, request HttpRequest) (*http.Request, string) { + var delimiter string + + switch collectionFormat { + case "pipes": + delimiter = "|" + case "ssv": + delimiter = " " + case "tsv": + delimiter = "\t" + case "csv": + delimiter = "," + } + + if reflect.TypeOf(obj).Kind() == reflect.Slice { + return nil, strings.Trim(strings.Replace(fmt.Sprint(obj), " ", delimiter, -1), "[]") + } + + return nil, fmt.Sprintf("%v", obj) +} + +// Excute entry for http call +func (c *APIClient) Excute(httpRequest *HttpRequest, config *config.Config, returnType interface{}) (*http.Response, error) { + httpRequest = buildHttpRequest(httpRequest, config) + request := buildCall(httpRequest) + httpResponse, err := c.callAPI(request) + if err != nil || httpResponse == nil { + return nil, err + } + + responseBody, err := ioutil.ReadAll(httpResponse.Body) + httpResponse.Body.Close() + if err != nil { + return httpResponse, err + } + + if httpResponse.StatusCode < 300 { + // If we succeed, return the data, otherwise pass on to decode error. + err = c.decode(&returnType, responseBody, httpResponse.Header.Get("Content-Type")) + if err != nil { + return httpResponse, fmt.Errorf("%w, response body is: %s", err, string(responseBody)) + } + return httpResponse, nil + } + + if httpResponse.StatusCode >= 300 { + newErr := GenericResponseError{ + body: responseBody, + error: httpResponse.Status, + } + return httpResponse, newErr + } + return httpResponse, err +} + +// callAPI do the request. +func (c *APIClient) callAPI(request *http.Request) (*http.Response, error) { + return c.cfg.HTTPClient.Do(request) +} + +// ChangeBasePath Change base path to allow switching to mocks +func (c *APIClient) ChangeBasePath(path string) { + c.cfg.BasePath = path +} + +// buildHttpRequest build the request +func buildHttpRequest(httpRequest *HttpRequest, config *config.Config) *HttpRequest { + openApiRequest := &OpenApiRequest{ + AccessKey: config.AccessKey, + SecretKey: config.SecretKey, + PoolId: config.PoolId, + Api: httpRequest.Action, + Product: httpRequest.Product, + Version: httpRequest.Version, + SdkVersion: httpRequest.SdkVersion, + Language: "Golang", + } + if httpRequest.Body != nil { + reqType := reflect.TypeOf(httpRequest.Body) + if reqType.Kind() == reflect.Ptr { + reqType = reqType.Elem() + } + v := reflect.ValueOf(httpRequest.Body) + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + var flag = false + for i := 0; i < reqType.NumField(); i++ { + fieldType := reqType.Field(i) + value := v.FieldByName(fieldType.Name) + if value.Kind() == reflect.Ptr { + if value.IsNil() { + continue + } + value = value.Elem() + + } + propertyType := fieldType.Type + if propertyType.Kind() == reflect.Ptr { + propertyType = propertyType.Elem() + } + + _, flag = propertyType.FieldByName(string(BODY)) + if flag { + openApiRequest.BodyParameter = value.Interface() + continue + } + _, flag = propertyType.FieldByName(string(HEADER)) + if flag { + openApiRequest.HeaderParameter = structToMap(value.Interface()) + continue + } + _, flag = propertyType.FieldByName(string(QUERY)) + if flag { + openApiRequest.QueryParameter = structToMap(value.Interface()) + continue + } + _, flag = propertyType.FieldByName(string(PATH)) + if flag { + openApiRequest.PathParameter = structToMap(value.Interface()) + continue + } + } + } + headers := make(map[string]interface{}) + if httpRequest.HeaderParams != nil { + if openApiRequest.HeaderParameter == nil { + headers = httpRequest.HeaderParams + } else { + headers = mergeMap(openApiRequest.HeaderParameter, httpRequest.HeaderParams) + } + openApiRequest.HeaderParameter = headers + } + httpRequest.Body = openApiRequest + return httpRequest +} + +// mergeMap merge the two map results +func mergeMap(mObj ...map[string]interface{}) map[string]interface{} { + newMap := map[string]interface{}{} + for _, m := range mObj { + for k, v := range m { + newMap[k] = v + } + } + return newMap +} + +// structToMap struct convert to map +func structToMap(value interface{}) map[string]interface{} { + data, _ := json.Marshal(value) + result := make(map[string]interface{}) + json.Unmarshal(data, &result) + return result +} + +func buildCall(httpRequest *HttpRequest) (request *http.Request) { + var url = "" + if len(httpRequest.Url) > 0 { + url = httpRequest.Url + SdkPortalUrl + } else { + url = httpRequest.DefaultUrl + SdkPortalGatewayUrl + } + request, _ = prepareRequest(url, "POST", httpRequest.Body) + return request +} + +// prepareRequest build the request +func prepareRequest(path string, method string, + postBody interface{}, +) (httpRequest *http.Request, err error) { + + var body *bytes.Buffer + + // Detect postBody type and post. + if postBody != nil { + var contentType = detectContentType(postBody) + body, err = setBody(postBody, contentType) + if err != nil { + return nil, err + } + } + + // Setup path and query parameters + url, err := url.Parse(path) + if err != nil { + return nil, err + } + + // Generate a new request + if body != nil { + httpRequest, err = http.NewRequest(method, url.String(), body) + } else { + httpRequest, err = http.NewRequest(method, url.String(), nil) + } + if err != nil { + return nil, err + } + + // add default header parameters + httpRequest.Header.Add("Content-Type", "application/json") + return httpRequest, nil +} + +func (c *APIClient) decode(v interface{}, b []byte, contentType string) (err error) { + if strings.Contains(contentType, "application/xml") { + if err = xml.Unmarshal(b, v); err != nil { + return err + } + return nil + } else if strings.Contains(contentType, "application/json") { + platformResponse := &APIPlatformResponse{} + if err = json.Unmarshal(b, platformResponse); err != nil { + newErr := GenericResponseError{ + body: b, + error: err.Error(), + } + return newErr + } + platformResponseBodyBytes, _ := json.Marshal(platformResponse.Body) + platformResponseBody := &APIPlatformResponseBody{} + if err = json.Unmarshal(platformResponseBodyBytes, platformResponseBody); err != nil { + return err + } + /* + 找到两层指针指向的元素 + */ + value := reflect.ValueOf(v).Elem().Elem() + + if !value.IsNil() { + structValue := value.Elem() + if structValue.NumField() == 1 && structValue.Field(0).Kind() == reflect.String { + n := len(platformResponseBody.ResponseBody) + structValue.Field(0).SetString(platformResponseBody.ResponseBody[1 : n-1]) + return nil + } + } + + if err = json.Unmarshal([]byte(platformResponseBody.ResponseBody), v); err != nil { + return err + } + return nil + } + return errors.New("undefined response type") +} + +// Add a file to the multipart request +func addFile(w *multipart.Writer, fieldName, path string) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + + part, err := w.CreateFormFile(fieldName, filepath.Base(path)) + if err != nil { + return err + } + _, err = io.Copy(part, file) + + return err +} + +// Prevent trying to import "fmt" +func reportError(format string, a ...interface{}) error { + return fmt.Errorf(format, a...) +} + +// Set request body from an interface{} +func setBody(body interface{}, contentType string) (bodyBuf *bytes.Buffer, err error) { + if bodyBuf == nil { + bodyBuf = &bytes.Buffer{} + } + if reader, ok := body.(io.Reader); ok { + _, err = bodyBuf.ReadFrom(reader) + } else if b, ok := body.([]byte); ok { + _, err = bodyBuf.Write(b) + } else if s, ok := body.(string); ok { + _, err = bodyBuf.WriteString(s) + } else if s, ok := body.(*string); ok { + _, err = bodyBuf.WriteString(*s) + } else if jsonCheck.MatchString(contentType) { + err = json.NewEncoder(bodyBuf).Encode(body) + } else if xmlCheck.MatchString(contentType) { + xml.NewEncoder(bodyBuf).Encode(body) + } + + if err != nil { + return nil, err + } + + if bodyBuf.Len() == 0 { + err = fmt.Errorf("Invalid body type %s\n", contentType) + return nil, err + } + return bodyBuf, nil +} + +// detectContentType method is used to figure out `Request.Body` content type for request header +func detectContentType(body interface{}) string { + contentType := "text/plain; charset=utf-8" + kind := reflect.TypeOf(body).Kind() + + switch kind { + case reflect.Struct, reflect.Map, reflect.Ptr: + contentType = "application/json; charset=utf-8" + case reflect.String: + contentType = "text/plain; charset=utf-8" + default: + if b, ok := body.([]byte); ok { + contentType = http.DetectContentType(b) + } else if kind == reflect.Slice { + contentType = "application/json; charset=utf-8" + } + } + + return contentType +} + +type cacheControl map[string]string + +func parseCacheControl(headers http.Header) cacheControl { + cc := cacheControl{} + ccHeader := headers.Get("Cache-Control") + for _, part := range strings.Split(ccHeader, ",") { + part = strings.Trim(part, " ") + if part == "" { + continue + } + if strings.ContainsRune(part, '=') { + keyval := strings.Split(part, "=") + cc[strings.Trim(keyval[0], " ")] = strings.Trim(keyval[1], ",") + } else { + cc[part] = "" + } + } + return cc +} + +// CacheExpires helper function to determine remaining time before repeating a request. +func CacheExpires(r *http.Response) time.Time { + // Figure out when the cache expires. + var expires time.Time + now, err := time.Parse(time.RFC1123, r.Header.Get("date")) + if err != nil { + return time.Now() + } + respCacheControl := parseCacheControl(r.Header) + + if maxAge, ok := respCacheControl["max-age"]; ok { + lifetime, err := time.ParseDuration(maxAge + "s") + if err != nil { + expires = now + } + expires = now.Add(lifetime) + } else { + expiresHeader := r.Header.Get("Expires") + if expiresHeader != "" { + expires, err = time.Parse(time.RFC1123, expiresHeader) + if err != nil { + expires = now + } + } + } + return expires +} + +func strlen(s string) int { + return utf8.RuneCountInString(s) +} + +// GenericResponseError Provides access to the body, error and model on returned errors. +type GenericResponseError struct { + body []byte + error string + model interface{} +} + +// Error returns non-empty string if there was an error. +func (e GenericResponseError) Error() string { + return e.error +} + +// Body returns the raw bytes of the response +func (e GenericResponseError) Body() []byte { + return e.body +} + +// Model returns the unpacked model of the error +func (e GenericResponseError) Model() interface{} { + return e.model +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0/api_response.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0/api_response.go new file mode 100644 index 00000000..89110877 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0/api_response.go @@ -0,0 +1,64 @@ +package ecloudsdkcore + +import ( + "net/http" +) + +type ReturnState string + +const ( + OK ReturnState = "OK" + ERROR ReturnState = "ERROR" + EXCEPTION ReturnState = "EXCEPTION" + ALARM ReturnState = "ALARM" + FORBIDDEN ReturnState = "FORBIDDEN" +) + +type APIResponse struct { + *http.Response `json:"-"` + Message string `json:"message,omitempty"` + // Operation is the name of the swagger operation. + Operation string `json:"operation,omitempty"` + // RequestURL is the request URL. This value is always available, even if the + // embedded *http.Response is nil. + RequestURL string `json:"url,omitempty"` + // Method is the HTTP method used for the request. This value is always + // available, even if the embedded *http.Response is nil. + Method string `json:"method,omitempty"` + // Payload holds the contents of the response body (which may be nil or empty). + // This is provided here as the raw response.Body() reader will have already + // been drained. + Payload []byte `json:"-"` +} + +type APIPlatformResponse struct { + RequestId string `json:"requestId,omitempty"` + State ReturnState `json:"state,omitempty"` + Body interface{} `json:"body,omitempty"` + ErrorCode string `json:"errorCode,omitempty"` + ErrorParams []string `json:"errorParams,omitempty"` + ErrorMessage string `json:"errorMessage,omitempty"` +} + +type APIPlatformResponseBody struct { + // TimeConsuming int64 `json:"timeConsuming,omitempty"` + ResponseBody string `json:"responseBody,omitempty"` + RequestHeader map[string]interface{} `json:"requestHeader,omitempty"` + ResponseHeader map[string]interface{} `json:"responseHeader,omitempty"` + ResponseMessage string `json:"responseMessage,omitempty"` + StatusCode int `json:"statusCode,omitempty"` + HttpMethod string `json:"httpMethod,omitempty"` + RequestUrl string `json:"requestUrl,omitempty"` +} + +func NewAPIResponse(r *http.Response) *APIResponse { + + response := &APIResponse{Response: r} + return response +} + +func NewAPIResponseWithError(errorMessage string) *APIResponse { + + response := &APIResponse{Message: errorMessage} + return response +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0/config/config.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0/config/config.go new file mode 100644 index 00000000..08ba59e3 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0/config/config.go @@ -0,0 +1,9 @@ +package config + +type Config struct { + AccessKey string `json:"accessKey,string"` + SecretKey string `json:"secretKey,string"` + PoolId string `json:"poolId,string"` + ReadTimeOut int `json:"readTimeOut,int"` + ConnectTimeout int `json:"connectTimeout,int"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0/configuration.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0/configuration.go new file mode 100644 index 00000000..8eeb5df0 --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0/configuration.go @@ -0,0 +1,32 @@ +package ecloudsdkcore + +import ( + "net/http" +) + +type APIKey struct { + Key string + Prefix string +} + +type Configuration struct { + BasePath string `json:"basePath,omitempty"` + Host string `json:"host,omitempty"` + Scheme string `json:"scheme,omitempty"` + DefaultHeader map[string]string `json:"defaultHeader,omitempty"` + UserAgent string `json:"userAgent,omitempty"` + HTTPClient *http.Client +} + +func NewConfiguration() *Configuration { + cfg := &Configuration{ + BasePath: "https://ecloud.10086.cn/", + DefaultHeader: make(map[string]string), + UserAgent: "Ecloud-SDK/1.0.0/go", + } + return cfg +} + +func (c *Configuration) AddDefaultHeader(key string, value string) { + c.DefaultHeader[key] = value +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0/go.mod b/internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0/go.mod new file mode 100644 index 00000000..141fa34e --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0/go.mod @@ -0,0 +1,3 @@ +module gitlab.ecloud.com/ecloud/ecloudsdkcore + +go 1.23.0 diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0/http_request.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0/http_request.go new file mode 100644 index 00000000..e498463d --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0/http_request.go @@ -0,0 +1,22 @@ +package ecloudsdkcore + +type HttpRequest struct { + Url string `json:"url,omitempty"` + DefaultUrl string `json:"defaultUrl,omitempty"` + Method string `json:"method,omitempty"` + Action string `json:"action,omitempty"` + Product string `json:"product,omitempty"` + Version string `json:"version,omitempty"` + SdkVersion string `json:"sdkVersion,omitempty"` + Body interface{} `json:"body,omitempty"` + PathParams map[string]interface{} `json:"pathParams,omitempty"` + QueryParams map[string]interface{} `json:"queryParams,omitempty"` + HeaderParams map[string]interface{} `json:"headerParams,omitempty"` +} + +func NewDefaultHttpRequest() *HttpRequest { + return &HttpRequest{ + DefaultUrl: "https://ecloud.10086.cn", + Method: "POST", + } +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0/open_api_request.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0/open_api_request.go new file mode 100644 index 00000000..a7cb4c0b --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0/open_api_request.go @@ -0,0 +1,16 @@ +package ecloudsdkcore + +type OpenApiRequest struct { + Product string `json:"product,omitempty"` + Version string `json:"version,omitempty"` + SdkVersion string `json:"sdkVersion,omitempty"` + Language string `json:"language,omitempty"` + Api string `json:"api,omitempty"` + PoolId string `json:"poolId,omitempty"` + HeaderParameter map[string]interface{} `json:"headerParameter,omitempty"` + PathParameter map[string]interface{} `json:"pathParameter,omitempty"` + QueryParameter map[string]interface{} `json:"queryParameter,omitempty"` + BodyParameter interface{} `json:"bodyParameter,omitempty"` + AccessKey string `json:"accessKey,omitempty"` + SecretKey string `json:"secretKey,omitempty"` +} diff --git a/internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0/position/http_position.go b/internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0/position/http_position.go new file mode 100644 index 00000000..7c2eec1c --- /dev/null +++ b/internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0/position/http_position.go @@ -0,0 +1,13 @@ +package position + +type Body struct { +} + +type Query struct { +} + +type Path struct { +} + +type Header struct { +} diff --git a/internal/pkg/vendors/dnsla-sdk/api.go b/internal/pkg/vendors/dnsla-sdk/api.go new file mode 100644 index 00000000..df8e6026 --- /dev/null +++ b/internal/pkg/vendors/dnsla-sdk/api.go @@ -0,0 +1,52 @@ +package dnslasdk + +import ( + "fmt" + "net/http" + "net/url" +) + +func (c *Client) ListDomains(req *ListDomainsRequest) (*ListDomainsResponse, error) { + resp := ListDomainsResponse{} + err := c.sendRequestWithResult(http.MethodGet, "/domainList", req, &resp) + if err != nil { + return nil, err + } + return &resp, nil +} + +func (c *Client) ListRecords(req *ListRecordsRequest) (*ListRecordsResponse, error) { + resp := ListRecordsResponse{} + err := c.sendRequestWithResult(http.MethodGet, "/recordList", req, &resp) + if err != nil { + return nil, err + } + return &resp, nil +} + +func (c *Client) CreateRecord(req *CreateRecordRequest) (*CreateRecordResponse, error) { + resp := CreateRecordResponse{} + err := c.sendRequestWithResult(http.MethodPost, "/record", req, &resp) + if err != nil { + return nil, err + } + return &resp, nil +} + +func (c *Client) UpdateRecord(req *UpdateRecordRequest) (*UpdateRecordResponse, error) { + resp := UpdateRecordResponse{} + err := c.sendRequestWithResult(http.MethodPut, "/record", req, &resp) + if err != nil { + return nil, err + } + return &resp, nil +} + +func (c *Client) DeleteRecord(req *DeleteRecordRequest) (*DeleteRecordResponse, error) { + resp := DeleteRecordResponse{} + err := c.sendRequestWithResult(http.MethodDelete, fmt.Sprintf("/record?id=%s", url.QueryEscape(req.Id)), req, &resp) + if err != nil { + return nil, err + } + return &resp, nil +} diff --git a/internal/pkg/vendors/dnsla-sdk/client.go b/internal/pkg/vendors/dnsla-sdk/client.go new file mode 100644 index 00000000..60430fa1 --- /dev/null +++ b/internal/pkg/vendors/dnsla-sdk/client.go @@ -0,0 +1,82 @@ +package dnslasdk + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + "time" + + "github.com/go-resty/resty/v2" +) + +type Client struct { + apiId string + apiSecret string + + client *resty.Client +} + +func NewClient(apiId, apiSecret string) *Client { + client := resty.New() + + return &Client{ + apiId: apiId, + apiSecret: apiSecret, + client: client, + } +} + +func (c *Client) WithTimeout(timeout time.Duration) *Client { + c.client.SetTimeout(timeout) + return c +} + +func (c *Client) sendRequest(method string, path string, params interface{}) (*resty.Response, error) { + req := c.client.R().SetBasicAuth(c.apiId, c.apiSecret) + req.Method = method + req.URL = "https://api.dns.la/api" + path + if strings.EqualFold(method, http.MethodGet) { + qs := make(map[string]string) + if params != nil { + temp := make(map[string]any) + jsonb, _ := json.Marshal(params) + json.Unmarshal(jsonb, &temp) + for k, v := range temp { + if v != nil { + qs[k] = fmt.Sprintf("%v", v) + } + } + } + + req = req.SetQueryParams(qs) + } else { + req = req. + SetHeader("Content-Type", "application/json"). + SetBody(params) + } + + resp, err := req.Send() + if err != nil { + return nil, fmt.Errorf("dnsla api error: failed to send request: %w", err) + } else if resp.IsError() { + return nil, fmt.Errorf("dnsla api error: unexpected status code: %d, %s", resp.StatusCode(), resp.Body()) + } + + return resp, nil +} + +func (c *Client) sendRequestWithResult(method string, path string, params interface{}, result BaseResponse) error { + resp, err := c.sendRequest(method, path, params) + if err != nil { + return err + } + + if err := json.Unmarshal(resp.Body(), &result); err != nil { + return fmt.Errorf("dnsla api error: failed to parse response: %w", err) + } else if errcode := result.GetCode(); errcode/100 != 2 { + return fmt.Errorf("dnsla api error: %d - %s", errcode, result.GetMessage()) + } + + return nil +} diff --git a/internal/pkg/vendors/dnsla-sdk/models.go b/internal/pkg/vendors/dnsla-sdk/models.go new file mode 100644 index 00000000..85fe7978 --- /dev/null +++ b/internal/pkg/vendors/dnsla-sdk/models.go @@ -0,0 +1,125 @@ +package dnslasdk + +type BaseResponse interface { + GetCode() int + GetMessage() string +} + +type baseResponse struct { + Code int `json:"code"` + Message string `json:"message"` +} + +func (r *baseResponse) GetCode() int { + return r.Code +} + +func (r *baseResponse) GetMessage() string { + return r.Message +} + +type DomainInfo struct { + Id string `json:"id"` + GroupId string `json:"groupId"` + GroupName string `json:"groupName"` + Domain string `json:"domain"` + DisplayDomain string `json:"displayDomain"` + CreatedAt int64 `json:"createdAt"` + UpdatedAt int64 `json:"updatedAt"` +} + +type RecordInfo struct { + Id string `json:"id"` + DomainId string `json:"domainId"` + GroupId string `json:"groupId"` + GroupName string `json:"groupName"` + LineId string `json:"lineId"` + LineCode string `json:"lineCode"` + LineName string `json:"lineName"` + Type int32 `json:"type"` + Host string `json:"host"` + DisplayHost string `json:"displayHost"` + Data string `json:"data"` + DisplayData string `json:"displayData"` + Ttl int32 `json:"ttl"` + Weight int32 `json:"weight"` + Preference int32 `json:"preference"` + CreatedAt int64 `json:"createdAt"` + UpdatedAt int64 `json:"updatedAt"` +} + +type ListDomainsRequest struct { + PageIndex int32 `json:"pageIndex"` + PageSize int32 `json:"pageSize"` + GroupId *string `json:"groupId,omitempty"` +} + +type ListDomainsResponse struct { + baseResponse + Data *struct { + Total int32 `json:"total"` + Results []*DomainInfo `json:"results"` + } `json:"data,omitempty"` +} + +type ListRecordsRequest struct { + PageIndex int32 `json:"pageIndex"` + PageSize int32 `json:"pageSize"` + DomainId string `json:"domainId"` + GroupId *string `json:"groupId,omitempty"` + LineId *string `json:"lineId,omitempty"` + Type *int32 `json:"type,omitempty"` + Host *string `json:"host,omitempty"` + Data *string `json:"data,omitempty"` +} + +type ListRecordsResponse struct { + baseResponse + Data *struct { + Total int32 `json:"total"` + Results []*RecordInfo `json:"results"` + } `json:"data,omitempty"` +} + +type CreateRecordRequest struct { + DomainId string `json:"domainId"` + GroupId *string `json:"groupId,omitempty"` + LineId *string `json:"lineId,omitempty"` + Type int32 `json:"type"` + Host string `json:"host"` + Data string `json:"data"` + Ttl int32 `json:"ttl"` + Weight *int32 `json:"weight,omitempty"` + Preference *int32 `json:"preference,omitempty"` +} + +type CreateRecordResponse struct { + baseResponse + Data *struct { + Id string `json:"id"` + } `json:"data,omitempty"` +} + +type UpdateRecordRequest struct { + Id string `json:"id"` + GroupId *string `json:"groupId,omitempty"` + LineId *string `json:"lineId,omitempty"` + Type *int32 `json:"type,omitempty"` + Host *string `json:"host,omitempty"` + Data *string `json:"data,omitempty"` + Ttl *int32 `json:"ttl,omitempty"` + Weight *int32 `json:"weight,omitempty"` + Preference *int32 `json:"preference,omitempty"` +} + +type UpdateRecordResponse struct { + baseResponse +} + +type DeleteRecordRequest struct { + Id string `json:"-"` +} + +type DeleteRecordResponse struct { + baseResponse +} diff --git a/internal/pkg/vendors/edgio-sdk/applications/README.md b/internal/pkg/vendors/edgio-sdk/applications/README.md new file mode 100644 index 00000000..703b245a --- /dev/null +++ b/internal/pkg/vendors/edgio-sdk/applications/README.md @@ -0,0 +1 @@ +From https://github.com/Edgio/terraform-provider-edgio.git diff --git a/internal/pkg/vendors/edgio-sdk/applications/v7/README.md b/internal/pkg/vendors/edgio-sdk/applications/v7/README.md deleted file mode 100644 index fae60236..00000000 --- a/internal/pkg/vendors/edgio-sdk/applications/v7/README.md +++ /dev/null @@ -1,3 +0,0 @@ -```shell -git clone https://github.com/Edgio/terraform-provider-edgio.git -``` diff --git a/internal/pkg/vendors/gcore-sdk/common/endpoint.go b/internal/pkg/vendors/gcore-sdk/common/endpoint.go new file mode 100644 index 00000000..d4032da3 --- /dev/null +++ b/internal/pkg/vendors/gcore-sdk/common/endpoint.go @@ -0,0 +1,3 @@ +package common + +const BASE_URL = "https://api.gcore.com" diff --git a/internal/pkg/vendors/gcore-sdk/common/signer.go b/internal/pkg/vendors/gcore-sdk/common/signer.go new file mode 100644 index 00000000..bc66ee09 --- /dev/null +++ b/internal/pkg/vendors/gcore-sdk/common/signer.go @@ -0,0 +1,24 @@ +package common + +import ( + "net/http" + + "github.com/G-Core/gcorelabscdn-go/gcore" +) + +type AuthRequestSigner struct { + apiToken string +} + +var _ gcore.RequestSigner = (*AuthRequestSigner)(nil) + +func NewAuthRequestSigner(apiToken string) *AuthRequestSigner { + return &AuthRequestSigner{ + apiToken: apiToken, + } +} + +func (s *AuthRequestSigner) Sign(req *http.Request) error { + req.Header.Set("Authorization", "APIKey "+s.apiToken) + return nil +} diff --git a/internal/pkg/vendors/gname-sdk/api.go b/internal/pkg/vendors/gname-sdk/api.go index 33972adc..d01574c7 100644 --- a/internal/pkg/vendors/gname-sdk/api.go +++ b/internal/pkg/vendors/gname-sdk/api.go @@ -1,102 +1,37 @@ package gnamesdk -type BaseResponse interface { - GetCode() int - GetMsg() string +func (c *Client) AddDomainResolution(req *AddDomainResolutionRequest) (*AddDomainResolutionResponse, error) { + result := AddDomainResolutionResponse{} + err := c.sendRequestWithResult("/api/resolution/add", req, &result) + if err != nil { + return nil, err + } + return &result, nil } -type AddDomainResolutionRequest struct { - ZoneName string `json:"ym"` - RecordType string `json:"lx"` - RecordName string `json:"zj"` - RecordValue string `json:"jlz"` - MX int `json:"mx"` - TTL int `json:"ttl"` +func (c *Client) ModifyDomainResolution(req *ModifyDomainResolutionRequest) (*ModifyDomainResolutionResponse, error) { + resp := ModifyDomainResolutionResponse{} + err := c.sendRequestWithResult("/api/resolution/edit", req, &resp) + if err != nil { + return nil, err + } + return &resp, nil } -type AddDomainResolutionResponse struct { - Code int `json:"code"` - Msg string `json:"msg"` - Data int `json:"data"` +func (c *Client) DeleteDomainResolution(req *DeleteDomainResolutionRequest) (*DeleteDomainResolutionResponse, error) { + resp := DeleteDomainResolutionResponse{} + err := c.sendRequestWithResult("/api/resolution/delete", req, &resp) + if err != nil { + return nil, err + } + return &resp, nil } -func (r *AddDomainResolutionResponse) GetCode() int { - return r.Code -} - -func (r *AddDomainResolutionResponse) GetMsg() string { - return r.Msg -} - -type ModifyDomainResolutionRequest struct { - ID string `json:"jxid"` - ZoneName string `json:"ym"` - RecordType string `json:"lx"` - RecordName string `json:"zj"` - RecordValue string `json:"jlz"` - MX int `json:"mx"` - TTL int `json:"ttl"` -} - -type ModifyDomainResolutionResponse struct { - Code int `json:"code"` - Msg string `json:"msg"` -} - -func (r *ModifyDomainResolutionResponse) GetCode() int { - return r.Code -} - -func (r *ModifyDomainResolutionResponse) GetMsg() string { - return r.Msg -} - -type DeleteDomainResolutionRequest struct { - ZoneName string `json:"ym"` - RecordID string `json:"jxid"` -} - -type DeleteDomainResolutionResponse struct { - Code int `json:"code"` - Msg string `json:"msg"` -} - -func (r *DeleteDomainResolutionResponse) GetCode() int { - return r.Code -} - -func (r *DeleteDomainResolutionResponse) GetMsg() string { - return r.Msg -} - -type ListDomainResolutionRequest struct { - ZoneName string `json:"ym"` - Page *int `json:"page,omitempty"` - PageSize *int `json:"limit,omitempty"` -} - -type ListDomainResolutionResponse struct { - Code int `json:"code"` - Msg string `json:"msg"` - Count int `json:"count"` - Data []*ResolutionRecord `json:"data"` - Page int `json:"page"` - PageSize int `json:"pagesize"` -} - -type ResolutionRecord struct { - ID string `json:"id"` - ZoneName string `json:"ym"` - RecordType string `json:"lx"` - RecordName string `json:"zjt"` - RecordValue string `json:"jxz"` - MX int `json:"mx"` -} - -func (r *ListDomainResolutionResponse) GetCode() int { - return r.Code -} - -func (r *ListDomainResolutionResponse) GetMsg() string { - return r.Msg +func (c *Client) ListDomainResolution(req *ListDomainResolutionRequest) (*ListDomainResolutionResponse, error) { + resp := ListDomainResolutionResponse{} + err := c.sendRequestWithResult("/api/resolution/list", req, &resp) + if err != nil { + return nil, err + } + return &resp, nil } diff --git a/internal/pkg/vendors/gname-sdk/client.go b/internal/pkg/vendors/gname-sdk/client.go index 64baab95..8e2a2ba9 100644 --- a/internal/pkg/vendors/gname-sdk/client.go +++ b/internal/pkg/vendors/gname-sdk/client.go @@ -10,84 +10,31 @@ import ( "time" "github.com/go-resty/resty/v2" - - "github.com/usual2970/certimate/internal/pkg/utils/maps" ) -type GnameClient struct { +type Client struct { appId string appKey string + client *resty.Client } -func NewGnameClient(appId, appKey string) *GnameClient { +func NewClient(appId, appKey string) *Client { client := resty.New() - return &GnameClient{ + return &Client{ appId: appId, appKey: appKey, client: client, } } -func (c *GnameClient) WithTimeout(timeout time.Duration) *GnameClient { +func (c *Client) WithTimeout(timeout time.Duration) *Client { c.client.SetTimeout(timeout) return c } -func (c *GnameClient) AddDomainResolution(req *AddDomainResolutionRequest) (*AddDomainResolutionResponse, error) { - params := make(map[string]any) - jsonData, _ := json.Marshal(req) - json.Unmarshal(jsonData, ¶ms) - - result := AddDomainResolutionResponse{} - err := c.sendRequestWithResult("/api/resolution/add", params, &result) - if err != nil { - return nil, err - } - return &result, nil -} - -func (c *GnameClient) ModifyDomainResolution(req *ModifyDomainResolutionRequest) (*ModifyDomainResolutionResponse, error) { - params := make(map[string]any) - jsonData, _ := json.Marshal(req) - json.Unmarshal(jsonData, ¶ms) - - result := ModifyDomainResolutionResponse{} - err := c.sendRequestWithResult("/api/resolution/edit", params, &result) - if err != nil { - return nil, err - } - return &result, nil -} - -func (c *GnameClient) DeleteDomainResolution(req *DeleteDomainResolutionRequest) (*DeleteDomainResolutionResponse, error) { - params := make(map[string]any) - jsonData, _ := json.Marshal(req) - json.Unmarshal(jsonData, ¶ms) - - result := DeleteDomainResolutionResponse{} - err := c.sendRequestWithResult("/api/resolution/delete", params, &result) - if err != nil { - return nil, err - } - return &result, nil -} - -func (c *GnameClient) ListDomainResolution(req *ListDomainResolutionRequest) (*ListDomainResolutionResponse, error) { - params := make(map[string]any) - jsonData, _ := json.Marshal(req) - json.Unmarshal(jsonData, ¶ms) - - result := ListDomainResolutionResponse{} - err := c.sendRequestWithResult("/api/resolution/list", params, &result) - if err != nil { - return nil, err - } - return &result, nil -} - -func (c *GnameClient) generateSignature(params map[string]string) string { +func (c *Client) generateSignature(params map[string]string) string { // Step 1: Sort parameters by ASCII order var keys []string for k := range params { @@ -111,14 +58,17 @@ func (c *GnameClient) generateSignature(params map[string]string) string { return strings.ToUpper(fmt.Sprintf("%x", hash)) } -func (c *GnameClient) sendRequest(path string, params map[string]any) (*resty.Response, error) { - if params == nil { - params = make(map[string]any) - } - +func (c *Client) sendRequest(path string, params interface{}) (*resty.Response, error) { data := make(map[string]string) - for k, v := range params { - data[k] = fmt.Sprintf("%v", v) + if params != nil { + temp := make(map[string]any) + jsonb, _ := json.Marshal(params) + json.Unmarshal(jsonb, &temp) + for k, v := range temp { + if v != nil { + data[k] = fmt.Sprintf("%v", v) + } + } } data["appid"] = c.appId data["gntime"] = fmt.Sprintf("%d", time.Now().Unix()) @@ -130,32 +80,24 @@ func (c *GnameClient) sendRequest(path string, params map[string]any) (*resty.Re SetFormData(data) resp, err := req.Post(url) if err != nil { - return nil, fmt.Errorf("gname: failed to send request: %w", err) - } - - if resp.IsError() { - return nil, fmt.Errorf("gname: unexpected status code: %d, %s", resp.StatusCode(), resp.Body()) + return nil, fmt.Errorf("gname api error: failed to send request: %w", err) + } else if resp.IsError() { + return nil, fmt.Errorf("gname api error: unexpected status code: %d, %s", resp.StatusCode(), resp.Body()) } return resp, nil } -func (c *GnameClient) sendRequestWithResult(path string, params map[string]any, result BaseResponse) error { +func (c *Client) sendRequestWithResult(path string, params interface{}, result BaseResponse) error { resp, err := c.sendRequest(path, params) if err != nil { return err } - jsonResp := make(map[string]any) - if err := json.Unmarshal(resp.Body(), &jsonResp); err != nil { - return fmt.Errorf("gname: failed to parse response: %w", err) - } - if err := maps.Populate(jsonResp, &result); err != nil { - return fmt.Errorf("gname: failed to parse response: %w", err) - } - - if result.GetCode() != 1 { - return fmt.Errorf("gname api error: %s", result.GetMsg()) + if err := json.Unmarshal(resp.Body(), &result); err != nil { + return fmt.Errorf("gname api error: failed to parse response: %w", err) + } else if errcode := result.GetCode(); errcode != 1 { + return fmt.Errorf("gname api error: %d - %s", errcode, result.GetMessage()) } return nil diff --git a/internal/pkg/vendors/gname-sdk/models.go b/internal/pkg/vendors/gname-sdk/models.go new file mode 100644 index 00000000..997fb2c4 --- /dev/null +++ b/internal/pkg/vendors/gname-sdk/models.go @@ -0,0 +1,79 @@ +package gnamesdk + +type BaseResponse interface { + GetCode() int + GetMessage() string +} + +type baseResponse struct { + Code int `json:"code"` + Message string `json:"msg"` +} + +func (r *baseResponse) GetCode() int { + return r.Code +} + +func (r *baseResponse) GetMessage() string { + return r.Message +} + +type AddDomainResolutionRequest struct { + ZoneName string `json:"ym"` + RecordType string `json:"lx"` + RecordName string `json:"zj"` + RecordValue string `json:"jlz"` + MX int `json:"mx"` + TTL int `json:"ttl"` +} + +type AddDomainResolutionResponse struct { + baseResponse + Data string `json:"data"` +} + +type ModifyDomainResolutionRequest struct { + ID string `json:"jxid"` + ZoneName string `json:"ym"` + RecordType string `json:"lx"` + RecordName string `json:"zj"` + RecordValue string `json:"jlz"` + MX int `json:"mx"` + TTL int `json:"ttl"` +} + +type ModifyDomainResolutionResponse struct { + baseResponse +} + +type DeleteDomainResolutionRequest struct { + ZoneName string `json:"ym"` + RecordID string `json:"jxid"` +} + +type DeleteDomainResolutionResponse struct { + baseResponse +} + +type ListDomainResolutionRequest struct { + ZoneName string `json:"ym"` + Page *int `json:"page,omitempty"` + PageSize *int `json:"limit,omitempty"` +} + +type ListDomainResolutionResponse struct { + baseResponse + Count int `json:"count"` + Data []*ResolutionRecord `json:"data"` + Page int `json:"page"` + PageSize int `json:"pagesize"` +} + +type ResolutionRecord struct { + ID string `json:"id"` + ZoneName string `json:"ym"` + RecordType string `json:"lx"` + RecordName string `json:"zjt"` + RecordValue string `json:"jxz"` + MX int `json:"mx"` +} diff --git a/internal/pkg/vendors/safeline-sdk/api.go b/internal/pkg/vendors/safeline-sdk/api.go new file mode 100644 index 00000000..17af6c83 --- /dev/null +++ b/internal/pkg/vendors/safeline-sdk/api.go @@ -0,0 +1,10 @@ +package safelinesdk + +func (c *Client) UpdateCertificate(req *UpdateCertificateRequest) (*UpdateCertificateResponse, error) { + resp := UpdateCertificateResponse{} + err := c.sendRequestWithResult("/api/open/cert", req, &resp) + if err != nil { + return nil, err + } + return &resp, nil +} diff --git a/internal/pkg/vendors/safeline-sdk/client.go b/internal/pkg/vendors/safeline-sdk/client.go new file mode 100644 index 00000000..c6e6caf1 --- /dev/null +++ b/internal/pkg/vendors/safeline-sdk/client.go @@ -0,0 +1,67 @@ +package safelinesdk + +import ( + "encoding/json" + "fmt" + "strings" + "time" + + "github.com/go-resty/resty/v2" +) + +type Client struct { + apiHost string + apiToken string + + client *resty.Client +} + +func NewClient(apiHost, apiToken string) *Client { + client := resty.New() + + return &Client{ + apiHost: strings.TrimRight(apiHost, "/"), + apiToken: apiToken, + client: client, + } +} + +func (c *Client) WithTimeout(timeout time.Duration) *Client { + c.client.SetTimeout(timeout) + return c +} + +func (c *Client) sendRequest(path string, params interface{}) (*resty.Response, error) { + url := c.apiHost + path + req := c.client.R(). + SetHeader("Content-Type", "application/json"). + SetHeader("X-SLCE-API-TOKEN", c.apiToken). + SetBody(params) + resp, err := req.Post(url) + if err != nil { + return nil, fmt.Errorf("safeline api error: failed to send request: %w", err) + } else if resp.IsError() { + return nil, fmt.Errorf("safeline api error: unexpected status code: %d, %s", resp.StatusCode(), resp.Body()) + } + + return resp, nil +} + +func (c *Client) sendRequestWithResult(path string, params interface{}, result BaseResponse) error { + resp, err := c.sendRequest(path, params) + if err != nil { + return err + } + + if err := json.Unmarshal(resp.Body(), &result); err != nil { + return fmt.Errorf("safeline api error: failed to parse response: %w", err) + } else if errcode := result.GetErrCode(); errcode != nil && *errcode != "" { + if result.GetErrMsg() == nil { + return fmt.Errorf("safeline api error: %s", *errcode) + } else { + return fmt.Errorf("safeline api error: %s - %s", *errcode, *result.GetErrMsg()) + } + } + + return nil +} diff --git a/internal/pkg/vendors/safeline-sdk/models.go b/internal/pkg/vendors/safeline-sdk/models.go new file mode 100644 index 00000000..9fbfb7c9 --- /dev/null +++ b/internal/pkg/vendors/safeline-sdk/models.go @@ -0,0 +1,34 @@ +package safelinesdk + +type BaseResponse interface { + GetErrCode() *string + GetErrMsg() *string +} + +type baseResponse struct { + ErrCode *string `json:"err,omitempty"` + ErrMsg *string `json:"msg,omitempty"` +} + +func (r *baseResponse) GetErrCode() *string { + return r.ErrCode +} + +func (r *baseResponse) GetErrMsg() *string { + return r.ErrMsg +} + +type UpdateCertificateRequest struct { + Id int32 `json:"id"` + Type int32 `json:"type"` + Manual *UpdateCertificateRequestBodyManul `json:"manual"` +} + +type UpdateCertificateRequestBodyManul struct { + Crt string `json:"crt"` + Key string `json:"key"` +} + +type UpdateCertificateResponse struct { + baseResponse +} diff --git a/main.go b/main.go index 73d1a2a9..76f7f1c0 100644 --- a/main.go +++ b/main.go @@ -29,6 +29,11 @@ func main() { var flagDir string flag.StringVar(&flagHttp, "http", "127.0.0.1:8090", "HTTP server address") flag.StringVar(&flagDir, "dir", "/pb_data/database", "Pocketbase data directory") + if len(os.Args) < 2 { + slog.Error("[CERTIMATE] missing exec args") + os.Exit(1) + return + } _ = flag.CommandLine.Parse(os.Args[2:]) // skip the first two arguments: "main.go serve" migratecmd.MustRegister(app, app.RootCmd, migratecmd.Config{ diff --git a/migrations/1739462400_collections_snapshot.go b/migrations/1739462400_collections_snapshot.go index 523792c7..67453954 100644 --- a/migrations/1739462400_collections_snapshot.go +++ b/migrations/1739462400_collections_snapshot.go @@ -65,6 +65,7 @@ func init() { "cmcccloud", "ctcccloud", "cucccloud", + "dnsla", "dogecloud", "edgio", "fastly", @@ -73,13 +74,16 @@ func init() { "godaddy", "goedge", "huaweicloud", + "jdcloud", "k8s", "local", + "namecheap", "namedotcom", "namesilo", "ns1", "powerdns", "qiniu", + "qingcloud", "rainyun", "safeline", "ssh", @@ -171,6 +175,7 @@ func init() { "cmcccloud", "ctcccloud", "cucccloud", + "dnsla", "dogecloud", "edgio", "fastly", @@ -179,13 +184,16 @@ func init() { "godaddy", "goedge", "huaweicloud", + "jdcloud", "k8s", "local", + "namecheap", "namedotcom", "namesilo", "ns1", "powerdns", "qiniu", + "qingcloud", "rainyun", "safeline", "ssh", diff --git a/ui/public/imgs/acme/letsencrypt.svg b/ui/public/imgs/acme/letsencrypt.svg index 3a6c2312..b13df853 100644 --- a/ui/public/imgs/acme/letsencrypt.svg +++ b/ui/public/imgs/acme/letsencrypt.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/acmehttpreq.svg b/ui/public/imgs/providers/acmehttpreq.svg index 88f2d6b2..936ca077 100644 --- a/ui/public/imgs/providers/acmehttpreq.svg +++ b/ui/public/imgs/providers/acmehttpreq.svg @@ -1,2 +1,2 @@ - + diff --git a/ui/public/imgs/providers/aliyun.svg b/ui/public/imgs/providers/aliyun.svg index 7d0b70e0..05bfc6fe 100644 --- a/ui/public/imgs/providers/aliyun.svg +++ b/ui/public/imgs/providers/aliyun.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/aws.svg b/ui/public/imgs/providers/aws.svg index 9f211f19..3b771872 100644 --- a/ui/public/imgs/providers/aws.svg +++ b/ui/public/imgs/providers/aws.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/azure.svg b/ui/public/imgs/providers/azure.svg index 01b62bc9..014647a3 100644 --- a/ui/public/imgs/providers/azure.svg +++ b/ui/public/imgs/providers/azure.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/baiducloud.svg b/ui/public/imgs/providers/baiducloud.svg index 25ab747a..e448fd3e 100644 --- a/ui/public/imgs/providers/baiducloud.svg +++ b/ui/public/imgs/providers/baiducloud.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/baishan.png b/ui/public/imgs/providers/baishan.png new file mode 100644 index 00000000..af1e555d Binary files /dev/null and b/ui/public/imgs/providers/baishan.png differ diff --git a/ui/public/imgs/providers/cachefly.png b/ui/public/imgs/providers/cachefly.png new file mode 100644 index 00000000..86a13db5 Binary files /dev/null and b/ui/public/imgs/providers/cachefly.png differ diff --git a/ui/public/imgs/providers/cdnfly.png b/ui/public/imgs/providers/cdnfly.png new file mode 100644 index 00000000..3a8d9843 Binary files /dev/null and b/ui/public/imgs/providers/cdnfly.png differ diff --git a/ui/public/imgs/providers/cloudflare.svg b/ui/public/imgs/providers/cloudflare.svg index b6f07b50..5a6d858b 100644 --- a/ui/public/imgs/providers/cloudflare.svg +++ b/ui/public/imgs/providers/cloudflare.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/cloudns.png b/ui/public/imgs/providers/cloudns.png new file mode 100644 index 00000000..1ad3068d Binary files /dev/null and b/ui/public/imgs/providers/cloudns.png differ diff --git a/ui/public/imgs/providers/cloudns.svg b/ui/public/imgs/providers/cloudns.svg deleted file mode 100644 index 44cf1ed2..00000000 --- a/ui/public/imgs/providers/cloudns.svg +++ /dev/null @@ -1,99 +0,0 @@ - - diff --git a/ui/public/imgs/providers/cmcccloud.svg b/ui/public/imgs/providers/cmcccloud.svg new file mode 100644 index 00000000..0a44fcfa --- /dev/null +++ b/ui/public/imgs/providers/cmcccloud.svg @@ -0,0 +1 @@ + diff --git a/ui/public/imgs/providers/dnsla.svg b/ui/public/imgs/providers/dnsla.svg new file mode 100644 index 00000000..7908049e --- /dev/null +++ b/ui/public/imgs/providers/dnsla.svg @@ -0,0 +1 @@ + diff --git a/ui/public/imgs/providers/dogecloud.png b/ui/public/imgs/providers/dogecloud.png new file mode 100644 index 00000000..1897bc88 Binary files /dev/null and b/ui/public/imgs/providers/dogecloud.png differ diff --git a/ui/public/imgs/providers/dogecloud.svg b/ui/public/imgs/providers/dogecloud.svg deleted file mode 100644 index 253f9ae7..00000000 --- a/ui/public/imgs/providers/dogecloud.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/ui/public/imgs/providers/gcore.png b/ui/public/imgs/providers/gcore.png new file mode 100644 index 00000000..3808329a Binary files /dev/null and b/ui/public/imgs/providers/gcore.png differ diff --git a/ui/public/imgs/providers/gname.png b/ui/public/imgs/providers/gname.png new file mode 100644 index 00000000..ef3772f5 Binary files /dev/null and b/ui/public/imgs/providers/gname.png differ diff --git a/ui/public/imgs/providers/gname.svg b/ui/public/imgs/providers/gname.svg deleted file mode 100644 index ec409ca5..00000000 --- a/ui/public/imgs/providers/gname.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/ui/public/imgs/providers/godaddy.svg b/ui/public/imgs/providers/godaddy.svg index a859a7ae..f9471283 100644 --- a/ui/public/imgs/providers/godaddy.svg +++ b/ui/public/imgs/providers/godaddy.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/huaweicloud.svg b/ui/public/imgs/providers/huaweicloud.svg index 552e59e7..45a42dd2 100644 --- a/ui/public/imgs/providers/huaweicloud.svg +++ b/ui/public/imgs/providers/huaweicloud.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/jdcloud.svg b/ui/public/imgs/providers/jdcloud.svg new file mode 100644 index 00000000..720dbf4d --- /dev/null +++ b/ui/public/imgs/providers/jdcloud.svg @@ -0,0 +1 @@ + diff --git a/ui/public/imgs/providers/kubernetes.svg b/ui/public/imgs/providers/kubernetes.svg index b7f555f7..88125935 100644 --- a/ui/public/imgs/providers/kubernetes.svg +++ b/ui/public/imgs/providers/kubernetes.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/local.svg b/ui/public/imgs/providers/local.svg index 2f59af07..46974fa7 100644 --- a/ui/public/imgs/providers/local.svg +++ b/ui/public/imgs/providers/local.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/namecheap.svg b/ui/public/imgs/providers/namecheap.svg new file mode 100644 index 00000000..e90dbfe9 --- /dev/null +++ b/ui/public/imgs/providers/namecheap.svg @@ -0,0 +1 @@ + diff --git a/ui/public/imgs/providers/namesilo.svg b/ui/public/imgs/providers/namesilo.svg index e0cc8da4..4284796d 100644 --- a/ui/public/imgs/providers/namesilo.svg +++ b/ui/public/imgs/providers/namesilo.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/powerdns.svg b/ui/public/imgs/providers/powerdns.svg index 192466ed..768bbacf 100644 --- a/ui/public/imgs/providers/powerdns.svg +++ b/ui/public/imgs/providers/powerdns.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/qiniu.svg b/ui/public/imgs/providers/qiniu.svg index d3b98877..20a88367 100644 --- a/ui/public/imgs/providers/qiniu.svg +++ b/ui/public/imgs/providers/qiniu.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/safeline.svg b/ui/public/imgs/providers/safeline.svg new file mode 100644 index 00000000..9a0db247 --- /dev/null +++ b/ui/public/imgs/providers/safeline.svg @@ -0,0 +1 @@ + diff --git a/ui/public/imgs/providers/ssh.svg b/ui/public/imgs/providers/ssh.svg index 8dea9e89..d673cafa 100644 --- a/ui/public/imgs/providers/ssh.svg +++ b/ui/public/imgs/providers/ssh.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/tencentcloud.svg b/ui/public/imgs/providers/tencentcloud.svg index 76e54dbb..1fb8f4b6 100644 --- a/ui/public/imgs/providers/tencentcloud.svg +++ b/ui/public/imgs/providers/tencentcloud.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/ucloud.svg b/ui/public/imgs/providers/ucloud.svg index 9e246c65..3000023f 100644 --- a/ui/public/imgs/providers/ucloud.svg +++ b/ui/public/imgs/providers/ucloud.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/webhook.svg b/ui/public/imgs/providers/webhook.svg index 2ca5bff3..6c5eaee1 100644 --- a/ui/public/imgs/providers/webhook.svg +++ b/ui/public/imgs/providers/webhook.svg @@ -1 +1 @@ - + diff --git a/ui/public/imgs/providers/westcn.svg b/ui/public/imgs/providers/westcn.svg index 9ea5a83c..2ad4fa58 100644 --- a/ui/public/imgs/providers/westcn.svg +++ b/ui/public/imgs/providers/westcn.svg @@ -1 +1 @@ - + diff --git a/ui/src/components/Version.tsx b/ui/src/components/Version.tsx index 4832cce8..e9245b1c 100644 --- a/ui/src/components/Version.tsx +++ b/ui/src/components/Version.tsx @@ -1,8 +1,10 @@ +import { memo } from "react"; import { useTranslation } from "react-i18next"; import { ReadOutlined as ReadOutlinedIcon } from "@ant-design/icons"; -import { Divider, Space, Typography } from "antd"; +import { Badge, Divider, Space, Typography } from "antd"; import { version } from "@/domain/version"; +import { useVersionChecker } from "@/hooks"; export type VersionProps = { className?: string; @@ -12,6 +14,8 @@ export type VersionProps = { const Version = ({ className, style }: VersionProps) => { const { t } = useTranslation(); + const { hasNewVersion } = useVersionChecker(); + return ( @@ -20,12 +24,16 @@ const Version = ({ className, style }: VersionProps) => { {t("common.menu.document")} + - - {version} - + + + + {version} + + ); }; -export default Version; +export default memo(Version); diff --git a/ui/src/components/access/AccessForm.tsx b/ui/src/components/access/AccessForm.tsx index d9632f28..47c6d8c6 100644 --- a/ui/src/components/access/AccessForm.tsx +++ b/ui/src/components/access/AccessForm.tsx @@ -14,23 +14,32 @@ import AccessFormAliyunConfig from "./AccessFormAliyunConfig"; import AccessFormAWSConfig from "./AccessFormAWSConfig"; import AccessFormAzureConfig from "./AccessFormAzureConfig"; import AccessFormBaiduCloudConfig from "./AccessFormBaiduCloudConfig"; +import AccessFormBaishanConfig from "./AccessFormBaishanConfig"; import AccessFormBaotaPanelConfig from "./AccessFormBaotaPanelConfig"; import AccessFormBytePlusConfig from "./AccessFormBytePlusConfig"; +import AccessFormCacheFlyConfig from "./AccessFormCacheFlyConfig"; +import AccessFormCdnflyConfig from "./AccessFormCdnflyConfig"; import AccessFormCloudflareConfig from "./AccessFormCloudflareConfig"; import AccessFormClouDNSConfig from "./AccessFormClouDNSConfig"; +import AccessFormCMCCCloudConfig from "./AccessFormCMCCCloudConfig"; +import AccessFormDNSLAConfig from "./AccessFormDNSLAConfig"; import AccessFormDogeCloudConfig from "./AccessFormDogeCloudConfig"; import AccessFormEdgioConfig from "./AccessFormEdgioConfig"; +import AccessFormGcoreConfig from "./AccessFormGcoreConfig"; import AccessFormGnameConfig from "./AccessFormGnameConfig"; import AccessFormGoDaddyConfig from "./AccessFormGoDaddyConfig"; import AccessFormHuaweiCloudConfig from "./AccessFormHuaweiCloudConfig"; +import AccessFormJDCloudConfig from "./AccessFormJDCloudConfig"; import AccessFormKubernetesConfig from "./AccessFormKubernetesConfig"; import AccessFormLocalConfig from "./AccessFormLocalConfig"; +import AccessFormNamecheapConfig from "./AccessFormNamecheapConfig"; import AccessFormNameDotComConfig from "./AccessFormNameDotComConfig"; import AccessFormNameSiloConfig from "./AccessFormNameSiloConfig"; import AccessFormNS1Config from "./AccessFormNS1Config"; import AccessFormPowerDNSConfig from "./AccessFormPowerDNSConfig"; import AccessFormQiniuConfig from "./AccessFormQiniuConfig"; import AccessFormRainYunConfig from "./AccessFormRainYunConfig"; +import AccessFormSafeLineConfig from "./AccessFormSafeLineConfig"; import AccessFormSSHConfig from "./AccessFormSSHConfig"; import AccessFormTencentCloudConfig from "./AccessFormTencentCloudConfig"; import AccessFormUCloudConfig from "./AccessFormUCloudConfig"; @@ -100,16 +109,28 @@ const AccessForm = forwardRef(({ className, return ; case ACCESS_PROVIDERS.BAIDUCLOUD: return ; + case ACCESS_PROVIDERS.BAISHAN: + return ; case ACCESS_PROVIDERS.BAOTAPANEL: return ; case ACCESS_PROVIDERS.BYTEPLUS: return ; + case ACCESS_PROVIDERS.CACHEFLY: + return ; + case ACCESS_PROVIDERS.CDNFLY: + return ; case ACCESS_PROVIDERS.CLOUDFLARE: return ; case ACCESS_PROVIDERS.CLOUDNS: return ; + case ACCESS_PROVIDERS.CMCCCLOUD: + return ; + case ACCESS_PROVIDERS.DNSLA: + return ; case ACCESS_PROVIDERS.DOGECLOUD: return ; + case ACCESS_PROVIDERS.GCORE: + return ; case ACCESS_PROVIDERS.GNAME: return ; case ACCESS_PROVIDERS.GODADDY: @@ -118,10 +139,14 @@ const AccessForm = forwardRef(({ className, return ; case ACCESS_PROVIDERS.HUAWEICLOUD: return ; + case ACCESS_PROVIDERS.JDCLOUD: + return ; case ACCESS_PROVIDERS.KUBERNETES: return ; case ACCESS_PROVIDERS.LOCAL: return ; + case ACCESS_PROVIDERS.NAMECHEAP: + return ; case ACCESS_PROVIDERS.NAMEDOTCOM: return ; case ACCESS_PROVIDERS.NAMESILO: @@ -134,6 +159,8 @@ const AccessForm = forwardRef(({ className, return ; case ACCESS_PROVIDERS.RAINYUN: return ; + case ACCESS_PROVIDERS.SAFELINE: + return ; case ACCESS_PROVIDERS.SSH: return ; case ACCESS_PROVIDERS.TENCENTCLOUD: diff --git a/ui/src/components/access/AccessFormBaishanConfig.tsx b/ui/src/components/access/AccessFormBaishanConfig.tsx new file mode 100644 index 00000000..0450d9cd --- /dev/null +++ b/ui/src/components/access/AccessFormBaishanConfig.tsx @@ -0,0 +1,56 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import { type AccessConfigForBaishan } from "@/domain/access"; + +type AccessFormBaishanConfigFieldValues = Nullish; + +export type AccessFormBaishanConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: AccessFormBaishanConfigFieldValues; + onValuesChange?: (values: AccessFormBaishanConfigFieldValues) => void; +}; + +const initFormModel = (): AccessFormBaishanConfigFieldValues => { + return { + apiToken: "", + }; +}; + +const AccessFormBaishanConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormBaishanConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + apiToken: z + .string() + .min(1, t("access.form.baishan_api_token.placeholder")) + .max(64, t("common.errmsg.string_max", { max: 64 })) + .trim(), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ + + +
+ ); +}; + +export default AccessFormBaishanConfig; diff --git a/ui/src/components/access/AccessFormBaotaPanelConfig.tsx b/ui/src/components/access/AccessFormBaotaPanelConfig.tsx index 4f619c1c..accd80d0 100644 --- a/ui/src/components/access/AccessFormBaotaPanelConfig.tsx +++ b/ui/src/components/access/AccessFormBaotaPanelConfig.tsx @@ -17,7 +17,7 @@ export type AccessFormBaotaPanelConfigProps = { const initFormModel = (): AccessFormBaotaPanelConfigFieldValues => { return { - apiUrl: "", + apiUrl: "http://:8888/", apiKey: "", }; }; diff --git a/ui/src/components/access/AccessFormCMCCCloudConfig.tsx b/ui/src/components/access/AccessFormCMCCCloudConfig.tsx new file mode 100644 index 00000000..9bc6e615 --- /dev/null +++ b/ui/src/components/access/AccessFormCMCCCloudConfig.tsx @@ -0,0 +1,75 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; +import { type AccessConfigForCMCCCloud } from "@/domain/access"; + +type AccessFormCMCCCloudConfigFieldValues = Nullish; + +export type AccessFormCMCCCloudConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: AccessFormCMCCCloudConfigFieldValues; + onValuesChange?: (values: AccessFormCMCCCloudConfigFieldValues) => void; +}; + +const initFormModel = (): AccessFormCMCCCloudConfigFieldValues => { + return { + accessKeyId: "", + accessKeySecret: "", + }; +}; + +const AccessFormCMCCCloudConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange: onValuesChange }: AccessFormCMCCCloudConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + accessKeyId: z + .string() + .min(1, t("access.form.cmcccloud_access_key_id.placeholder")) + .max(64, t("common.errmsg.string_max", { max: 64 })) + .trim(), + accessKeySecret: z + .string() + .min(1, t("access.form.cmcccloud_access_key_secret.placeholder")) + .max(64, t("common.errmsg.string_max", { max: 64 })) + .trim(), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + + + } + > + + +
+ ); +}; + +export default AccessFormCMCCCloudConfig; diff --git a/ui/src/components/access/AccessFormCacheFlyConfig.tsx b/ui/src/components/access/AccessFormCacheFlyConfig.tsx new file mode 100644 index 00000000..b3172785 --- /dev/null +++ b/ui/src/components/access/AccessFormCacheFlyConfig.tsx @@ -0,0 +1,56 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import { type AccessConfigForCacheFly } from "@/domain/access"; + +type AccessFormCacheFlyConfigFieldValues = Nullish; + +export type AccessFormCacheFlyConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: AccessFormCacheFlyConfigFieldValues; + onValuesChange?: (values: AccessFormCacheFlyConfigFieldValues) => void; +}; + +const initFormModel = (): AccessFormCacheFlyConfigFieldValues => { + return { + apiToken: "", + }; +}; + +const AccessFormCacheFlyConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormCacheFlyConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + apiToken: z + .string() + .min(1, t("access.form.cachefly_api_token.placeholder")) + .max(64, t("common.errmsg.string_max", { max: 64 })) + .trim(), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ + + +
+ ); +}; + +export default AccessFormCacheFlyConfig; diff --git a/ui/src/components/access/AccessFormCdnflyConfig.tsx b/ui/src/components/access/AccessFormCdnflyConfig.tsx new file mode 100644 index 00000000..a9dd1139 --- /dev/null +++ b/ui/src/components/access/AccessFormCdnflyConfig.tsx @@ -0,0 +1,87 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import { type AccessConfigForCdnfly } from "@/domain/access"; + +type AccessFormCdnflyConfigFieldValues = Nullish; + +export type AccessFormCdnflyConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: AccessFormCdnflyConfigFieldValues; + onValuesChange?: (values: AccessFormCdnflyConfigFieldValues) => void; +}; + +const initFormModel = (): AccessFormCdnflyConfigFieldValues => { + return { + apiUrl: "http://:88/", + apiKey: "", + apiSecret: "", + }; +}; + +const AccessFormCdnflyConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormCdnflyConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + apiUrl: z.string().url(t("common.errmsg.url_invalid")), + apiKey: z + .string() + .min(1, t("access.form.cdnfly_api_key.placeholder")) + .max(64, t("common.errmsg.string_max", { max: 64 })) + .trim(), + apiSecret: z + .string() + .min(1, t("access.form.cdnfly_api_secret.placeholder")) + .max(64, t("common.errmsg.string_max", { max: 64 })) + .trim(), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + + + } + > + + + + } + > + + +
+ ); +}; + +export default AccessFormCdnflyConfig; diff --git a/ui/src/components/access/AccessFormDNSLAConfig.tsx b/ui/src/components/access/AccessFormDNSLAConfig.tsx new file mode 100644 index 00000000..df8403ea --- /dev/null +++ b/ui/src/components/access/AccessFormDNSLAConfig.tsx @@ -0,0 +1,76 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import { type AccessConfigForDNSLA } from "@/domain/access"; + +type AccessFormDNSLAConfigFieldValues = Nullish; + +export type AccessFormDNSLAConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: AccessFormDNSLAConfigFieldValues; + onValuesChange?: (values: AccessFormDNSLAConfigFieldValues) => void; +}; + +const initFormModel = (): AccessFormDNSLAConfigFieldValues => { + return { + apiId: "", + apiSecret: "", + }; +}; + +const AccessFormDNSLAConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange: onValuesChange }: AccessFormDNSLAConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + apiId: z + .string() + .min(1, t("access.form.dnsla_api_id.placeholder")) + .max(64, t("common.errmsg.string_max", { max: 64 })) + .trim(), + apiSecret: z + .string() + .min(1, t("access.form.dnsla_api_secret.placeholder")) + .max(64, t("common.errmsg.string_max", { max: 64 })) + .trim(), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + + + } + > + + +
+ ); +}; + +export default AccessFormDNSLAConfig; diff --git a/ui/src/components/access/AccessFormGcoreConfig.tsx b/ui/src/components/access/AccessFormGcoreConfig.tsx new file mode 100644 index 00000000..8619f7fe --- /dev/null +++ b/ui/src/components/access/AccessFormGcoreConfig.tsx @@ -0,0 +1,61 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import { type AccessConfigForGcore } from "@/domain/access"; + +type AccessFormGcoreConfigFieldValues = Nullish; + +export type AccessFormGcoreConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: AccessFormGcoreConfigFieldValues; + onValuesChange?: (values: AccessFormGcoreConfigFieldValues) => void; +}; + +const initFormModel = (): AccessFormGcoreConfigFieldValues => { + return { + apiToken: "", + }; +}; + +const AccessFormGcoreConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormGcoreConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + apiToken: z + .string() + .min(1, t("access.form.gcore_api_token.placeholder")) + .max(64, t("common.errmsg.string_max", { max: 64 })) + .trim(), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + +
+ ); +}; + +export default AccessFormGcoreConfig; diff --git a/ui/src/components/access/AccessFormJDCloudConfig.tsx b/ui/src/components/access/AccessFormJDCloudConfig.tsx new file mode 100644 index 00000000..7ab6b167 --- /dev/null +++ b/ui/src/components/access/AccessFormJDCloudConfig.tsx @@ -0,0 +1,76 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import { type AccessConfigForJDCloud } from "@/domain/access"; + +type AccessFormJDCloudConfigFieldValues = Nullish; + +export type AccessFormJDCloudConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: AccessFormJDCloudConfigFieldValues; + onValuesChange?: (values: AccessFormJDCloudConfigFieldValues) => void; +}; + +const initFormModel = (): AccessFormJDCloudConfigFieldValues => { + return { + accessKeyId: "", + accessKeySecret: "", + }; +}; + +const AccessFormJDCloudConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange: onValuesChange }: AccessFormJDCloudConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + accessKeyId: z + .string() + .min(1, t("access.form.jdcloud_access_key_id.placeholder")) + .max(64, t("common.errmsg.string_max", { max: 64 })) + .trim(), + accessKeySecret: z + .string() + .min(1, t("access.form.jdcloud_access_key_secret.placeholder")) + .max(64, t("common.errmsg.string_max", { max: 64 })) + .trim(), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + + + } + > + + +
+ ); +}; + +export default AccessFormJDCloudConfig; diff --git a/ui/src/components/access/AccessFormNamecheapConfig.tsx b/ui/src/components/access/AccessFormNamecheapConfig.tsx new file mode 100644 index 00000000..d6a79f2a --- /dev/null +++ b/ui/src/components/access/AccessFormNamecheapConfig.tsx @@ -0,0 +1,76 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import { type AccessConfigForNamecheap } from "@/domain/access"; + +type AccessFormNamecheapConfigFieldValues = Nullish; + +export type AccessFormNamecheapConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: AccessFormNamecheapConfigFieldValues; + onValuesChange?: (values: AccessFormNamecheapConfigFieldValues) => void; +}; + +const initFormModel = (): AccessFormNamecheapConfigFieldValues => { + return { + username: "", + apiKey: "", + }; +}; + +const AccessFormNamecheapConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormNamecheapConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + username: z + .string() + .min(1, t("access.form.namecheap_username.placeholder")) + .max(64, t("common.errmsg.string_max", { max: 64 })) + .trim(), + apiKey: z + .string() + .min(1, t("access.form.namecheap_api_key.placeholder")) + .max(64, t("common.errmsg.string_max", { max: 64 })) + .trim(), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + + + } + > + + +
+ ); +}; + +export default AccessFormNamecheapConfig; diff --git a/ui/src/components/access/AccessFormPowerDNSConfig.tsx b/ui/src/components/access/AccessFormPowerDNSConfig.tsx index 83a22b9b..e93980c7 100644 --- a/ui/src/components/access/AccessFormPowerDNSConfig.tsx +++ b/ui/src/components/access/AccessFormPowerDNSConfig.tsx @@ -17,7 +17,7 @@ export type AccessFormPowerDNSConfigProps = { const initFormModel = (): AccessFormPowerDNSConfigFieldValues => { return { - apiUrl: "", + apiUrl: "http://:8082/", apiKey: "", }; }; diff --git a/ui/src/components/access/AccessFormSafeLineConfig.tsx b/ui/src/components/access/AccessFormSafeLineConfig.tsx new file mode 100644 index 00000000..b9de115c --- /dev/null +++ b/ui/src/components/access/AccessFormSafeLineConfig.tsx @@ -0,0 +1,72 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import { type AccessConfigForSafeLine } from "@/domain/access"; + +type AccessFormSafeLineConfigFieldValues = Nullish; + +export type AccessFormSafeLineConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: AccessFormSafeLineConfigFieldValues; + onValuesChange?: (values: AccessFormSafeLineConfigFieldValues) => void; +}; + +const initFormModel = (): AccessFormSafeLineConfigFieldValues => { + return { + apiUrl: "http://:9443/", + apiToken: "", + }; +}; + +const AccessFormSafeLineConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormSafeLineConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + apiUrl: z.string().url(t("common.errmsg.url_invalid")), + apiToken: z + .string() + .min(1, t("access.form.safeline_api_token.placeholder")) + .max(64, t("common.errmsg.string_max", { max: 64 })) + .trim(), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + + + } + > + + +
+ ); +}; + +export default AccessFormSafeLineConfig; diff --git a/ui/src/components/provider/AccessProviderSelect.tsx b/ui/src/components/provider/AccessProviderSelect.tsx index 04b859ac..97cd35fd 100644 --- a/ui/src/components/provider/AccessProviderSelect.tsx +++ b/ui/src/components/provider/AccessProviderSelect.tsx @@ -47,12 +47,18 @@ const AccessProviderSelect = (props: AccessProviderSelectProps) => { return ( { + if (!option) return false; + + const value = inputValue.toLowerCase(); + return option.value.toLowerCase().includes(value) || option.label.toLowerCase().includes(value); + }} labelRender={({ label, value }) => { - if (label) { - return renderOption(value as string); + if (!label) { + return {props.placeholder}; } - return {props.placeholder}; + return renderOption(value as string); }} options={options} optionFilterProp={undefined} diff --git a/ui/src/components/provider/DeployProviderPicker.tsx b/ui/src/components/provider/DeployProviderPicker.tsx index af373255..57ba39a6 100644 --- a/ui/src/components/provider/DeployProviderPicker.tsx +++ b/ui/src/components/provider/DeployProviderPicker.tsx @@ -63,7 +63,7 @@ const DeployProviderPicker = ({ className, style, autoFocus, placeholder, onSele DEPLOY_CATEGORIES.STORAGE, DEPLOY_CATEGORIES.LOADBALANCE, DEPLOY_CATEGORIES.FIREWALL, - DEPLOY_CATEGORIES.LIVE, + DEPLOY_CATEGORIES.AV, DEPLOY_CATEGORIES.WEBSITE, DEPLOY_CATEGORIES.OTHER, ].map((key) => ({ diff --git a/ui/src/components/provider/DeployProviderSelect.tsx b/ui/src/components/provider/DeployProviderSelect.tsx index 54e3643b..cc2b13ea 100644 --- a/ui/src/components/provider/DeployProviderSelect.tsx +++ b/ui/src/components/provider/DeployProviderSelect.tsx @@ -33,12 +33,18 @@ const DeployProviderSelect = (props: DeployProviderSelectProps) => { return ( + + + ); +}; + +export default ApplyNodeConfigFormJDCloudDNSConfig; diff --git a/ui/src/components/workflow/node/DeployNodeConfigForm.tsx b/ui/src/components/workflow/node/DeployNodeConfigForm.tsx index 78d1b99d..b9f65b08 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigForm.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigForm.tsx @@ -24,19 +24,30 @@ import DeployNodeConfigFormAliyunESAConfig from "./DeployNodeConfigFormAliyunESA import DeployNodeConfigFormAliyunLiveConfig from "./DeployNodeConfigFormAliyunLiveConfig"; import DeployNodeConfigFormAliyunNLBConfig from "./DeployNodeConfigFormAliyunNLBConfig"; import DeployNodeConfigFormAliyunOSSConfig from "./DeployNodeConfigFormAliyunOSSConfig"; +import DeployNodeConfigFormAliyunVODConfig from "./DeployNodeConfigFormAliyunVODConfig"; import DeployNodeConfigFormAliyunWAFConfig from "./DeployNodeConfigFormAliyunWAFConfig"; import DeployNodeConfigFormAWSCloudFrontConfig from "./DeployNodeConfigFormAWSCloudFrontConfig"; import DeployNodeConfigFormBaiduCloudCDNConfig from "./DeployNodeConfigFormBaiduCloudCDNConfig"; +import DeployNodeConfigFormBaishanCDNConfig from "./DeployNodeConfigFormBaishanCDNConfig"; +import DeployNodeConfigFormBaotaPanelConsoleConfig from "./DeployNodeConfigFormBaotaPanelConsoleConfig"; import DeployNodeConfigFormBaotaPanelSiteConfig from "./DeployNodeConfigFormBaotaPanelSiteConfig"; import DeployNodeConfigFormBytePlusCDNConfig from "./DeployNodeConfigFormBytePlusCDNConfig"; +import DeployNodeConfigFormCdnflyConfig from "./DeployNodeConfigFormCdnflyConfig"; import DeployNodeConfigFormDogeCloudCDNConfig from "./DeployNodeConfigFormDogeCloudCDNConfig"; import DeployNodeConfigFormEdgioApplicationsConfig from "./DeployNodeConfigFormEdgioApplicationsConfig"; +import DeployNodeConfigFormGcoreCDNConfig from "./DeployNodeConfigFormGcoreCDNConfig"; import DeployNodeConfigFormHuaweiCloudCDNConfig from "./DeployNodeConfigFormHuaweiCloudCDNConfig"; import DeployNodeConfigFormHuaweiCloudELBConfig from "./DeployNodeConfigFormHuaweiCloudELBConfig"; +import DeployNodeConfigFormHuaweiCloudWAFConfig from "./DeployNodeConfigFormHuaweiCloudWAFConfig"; +import DeployNodeConfigFormJDCloudALBConfig from "./DeployNodeConfigFormJDCloudALBConfig"; +import DeployNodeConfigFormJDCloudCDNConfig from "./DeployNodeConfigFormJDCloudCDNConfig"; +import DeployNodeConfigFormJDCloudLiveConfig from "./DeployNodeConfigFormJDCloudLiveConfig"; +import DeployNodeConfigFormJDCloudVODConfig from "./DeployNodeConfigFormJDCloudVODConfig"; import DeployNodeConfigFormKubernetesSecretConfig from "./DeployNodeConfigFormKubernetesSecretConfig"; import DeployNodeConfigFormLocalConfig from "./DeployNodeConfigFormLocalConfig"; import DeployNodeConfigFormQiniuCDNConfig from "./DeployNodeConfigFormQiniuCDNConfig"; import DeployNodeConfigFormQiniuPiliConfig from "./DeployNodeConfigFormQiniuPiliConfig"; +import DeployNodeConfigFormSafeLineConfig from "./DeployNodeConfigFormSafeLineConfig"; import DeployNodeConfigFormSSHConfig from "./DeployNodeConfigFormSSHConfig.tsx"; import DeployNodeConfigFormTencentCloudCDNConfig from "./DeployNodeConfigFormTencentCloudCDNConfig.tsx"; import DeployNodeConfigFormTencentCloudCLBConfig from "./DeployNodeConfigFormTencentCloudCLBConfig.tsx"; @@ -45,11 +56,14 @@ import DeployNodeConfigFormTencentCloudCSSConfig from "./DeployNodeConfigFormTen import DeployNodeConfigFormTencentCloudECDNConfig from "./DeployNodeConfigFormTencentCloudECDNConfig.tsx"; import DeployNodeConfigFormTencentCloudEOConfig from "./DeployNodeConfigFormTencentCloudEOConfig.tsx"; import DeployNodeConfigFormTencentCloudSSLDeployConfig from "./DeployNodeConfigFormTencentCloudSSLDeployConfig"; +import DeployNodeConfigFormTencentCloudVODConfig from "./DeployNodeConfigFormTencentCloudVODConfig"; +import DeployNodeConfigFormTencentCloudWAFConfig from "./DeployNodeConfigFormTencentCloudWAFConfig"; import DeployNodeConfigFormUCloudUCDNConfig from "./DeployNodeConfigFormUCloudUCDNConfig.tsx"; import DeployNodeConfigFormUCloudUS3Config from "./DeployNodeConfigFormUCloudUS3Config.tsx"; import DeployNodeConfigFormVolcEngineCDNConfig from "./DeployNodeConfigFormVolcEngineCDNConfig.tsx"; import DeployNodeConfigFormVolcEngineCLBConfig from "./DeployNodeConfigFormVolcEngineCLBConfig.tsx"; import DeployNodeConfigFormVolcEngineDCDNConfig from "./DeployNodeConfigFormVolcEngineDCDNConfig.tsx"; +import DeployNodeConfigFormVolcEngineImageXConfig from "./DeployNodeConfigFormVolcEngineImageXConfig.tsx"; import DeployNodeConfigFormVolcEngineLiveConfig from "./DeployNodeConfigFormVolcEngineLiveConfig.tsx"; import DeployNodeConfigFormVolcEngineTOSConfig from "./DeployNodeConfigFormVolcEngineTOSConfig.tsx"; import DeployNodeConfigFormWebhookConfig from "./DeployNodeConfigFormWebhookConfig.tsx"; @@ -97,10 +111,9 @@ const DeployNodeConfigForm = forwardRef !!formInst.getFieldValue("provider"), t("workflow_node.deploy.form.provider.placeholder")), + .nonempty(t("workflow_node.deploy.form.provider_access.placeholder")), providerConfig: z.any(), - skipOnLastSucceeded: z.boolean(), + skipOnLastSucceeded: z.boolean().nullish(), }); const formRule = createSchemaFieldRule(formSchema); const { form: formInst, formProps } = useAntdForm({ @@ -143,24 +156,44 @@ const DeployNodeConfigForm = forwardRef; case DEPLOY_PROVIDERS.ALIYUN_OSS: return ; + case DEPLOY_PROVIDERS.ALIYUN_VOD: + return ; case DEPLOY_PROVIDERS.ALIYUN_WAF: return ; case DEPLOY_PROVIDERS.AWS_CLOUDFRONT: return ; case DEPLOY_PROVIDERS.BAIDUCLOUD_CDN: return ; + case DEPLOY_PROVIDERS.BAISHAN_CDN: + return ; + case DEPLOY_PROVIDERS.BAOTAPANEL_CONSOLE: + return ; case DEPLOY_PROVIDERS.BAOTAPANEL_SITE: return ; case DEPLOY_PROVIDERS.BYTEPLUS_CDN: return ; + case DEPLOY_PROVIDERS.CDNFLY: + return ; case DEPLOY_PROVIDERS.DOGECLOUD_CDN: return ; case DEPLOY_PROVIDERS.EDGIO_APPLICATIONS: return ; + case DEPLOY_PROVIDERS.GCORE_CDN: + return ; case DEPLOY_PROVIDERS.HUAWEICLOUD_CDN: return ; case DEPLOY_PROVIDERS.HUAWEICLOUD_ELB: return ; + case DEPLOY_PROVIDERS.HUAWEICLOUD_WAF: + return ; + case DEPLOY_PROVIDERS.JDCLOUD_ALB: + return ; + case DEPLOY_PROVIDERS.JDCLOUD_CDN: + return ; + case DEPLOY_PROVIDERS.JDCLOUD_LIVE: + return ; + case DEPLOY_PROVIDERS.JDCLOUD_VOD: + return ; case DEPLOY_PROVIDERS.KUBERNETES_SECRET: return ; case DEPLOY_PROVIDERS.LOCAL: @@ -169,6 +202,8 @@ const DeployNodeConfigForm = forwardRef; case DEPLOY_PROVIDERS.QINIU_PILI: return ; + case DEPLOY_PROVIDERS.SAFELINE: + return ; case DEPLOY_PROVIDERS.SSH: return ; case DEPLOY_PROVIDERS.TENCENTCLOUD_CDN: @@ -185,6 +220,10 @@ const DeployNodeConfigForm = forwardRef; case DEPLOY_PROVIDERS.TENCENTCLOUD_SSL_DEPLOY: return ; + case DEPLOY_PROVIDERS.TENCENTCLOUD_VOD: + return ; + case DEPLOY_PROVIDERS.TENCENTCLOUD_WAF: + return ; case DEPLOY_PROVIDERS.UCLOUD_UCDN: return ; case DEPLOY_PROVIDERS.UCLOUD_US3: @@ -195,6 +234,8 @@ const DeployNodeConfigForm = forwardRef; case DEPLOY_PROVIDERS.VOLCENGINE_DCDN: return ; + case DEPLOY_PROVIDERS.VOLCENGINE_IMAGEX: + return ; case DEPLOY_PROVIDERS.VOLCENGINE_LIVE: return ; case DEPLOY_PROVIDERS.VOLCENGINE_TOS: @@ -219,13 +260,13 @@ const DeployNodeConfigForm = forwardRef = {}; for (const key in oldValues) { - if (key === "provider" || key === "providerAccessId" || key === "certificate") { + if (key === "provider" || key === "providerAccessId" || key === "certificate" || key === "skipOnLastSucceeded") { newValues[key] = oldValues[key]; } else { newValues[key] = undefined; } } - (formInst as FormInstance).setFieldsValue(newValues); + formInst.setFieldsValue(newValues); if (deployProvidersMap.get(fieldProvider)?.provider !== deployProvidersMap.get(value)?.provider) { formInst.setFieldValue("providerAccessId", undefined); @@ -275,7 +316,13 @@ const DeployNodeConfigForm = forwardRef} > - + @@ -357,7 +404,7 @@ const DeployNodeConfigForm = forwardRef - + {t("workflow_node.deploy.form.params_config.label")} @@ -365,7 +412,9 @@ const DeployNodeConfigForm = forwardRef {nestedFormEl} + + {t("workflow_node.deploy.form.strategy_config.label")} diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunCASDeployConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunCASDeployConfig.tsx index 05bc632c..065f752c 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunCASDeployConfig.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunCASDeployConfig.tsx @@ -44,6 +44,7 @@ const DeployNodeConfigFormAliyunCASDeployConfig = ({ .nonempty(t("workflow_node.deploy.form.aliyun_cas_deploy_region.placeholder")) .trim(), resourceIds: z.string({ message: t("workflow_node.deploy.form.aliyun_cas_deploy_resource_ids.placeholder") }).refine((v) => { + if (!v) return false; return String(v) .split(MULTIPLE_INPUT_DELIMITER) .every((e) => /^[1-9]\d*$/.test(e)); diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunESAConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunESAConfig.tsx index 338c0f97..f61485e2 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunESAConfig.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunESAConfig.tsx @@ -5,7 +5,7 @@ import { z } from "zod"; type DeployNodeConfigFormAliyunESAConfigFieldValues = Nullish<{ region: string; - siteId: string; + siteId: string | number; }>; export type DeployNodeConfigFormAliyunESAConfigProps = { @@ -34,10 +34,9 @@ const DeployNodeConfigFormAliyunESAConfig = ({ .string({ message: t("workflow_node.deploy.form.aliyun_esa_region.placeholder") }) .nonempty(t("workflow_node.deploy.form.aliyun_esa_region.placeholder")) .trim(), - siteId: z - .string({ message: t("workflow_node.deploy.form.aliyun_esa_site_id.placeholder") }) - .regex(/^[1-9]\d*$/, t("workflow_node.deploy.form.aliyun_esa_site_id.placeholder")) - .trim(), + siteId: z.union([z.string(), z.number()]).refine((v) => { + return /^\d+$/.test(v + "") && +v > 0; + }, t("workflow_node.deploy.form.aliyun_esa_site_id.placeholder")), }); const formRule = createSchemaFieldRule(formSchema); @@ -69,7 +68,7 @@ const DeployNodeConfigFormAliyunESAConfig = ({ rules={[formRule]} tooltip={} > - + ); diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunVODConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunVODConfig.tsx new file mode 100644 index 00000000..d76e1193 --- /dev/null +++ b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunVODConfig.tsx @@ -0,0 +1,79 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import { validDomainName } from "@/utils/validators"; + +type DeployNodeConfigFormAliyunVODConfigFieldValues = Nullish<{ + region: string; + domain: string; +}>; + +export type DeployNodeConfigFormAliyunVODConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: DeployNodeConfigFormAliyunVODConfigFieldValues; + onValuesChange?: (values: DeployNodeConfigFormAliyunVODConfigFieldValues) => void; +}; + +const initFormModel = (): DeployNodeConfigFormAliyunVODConfigFieldValues => { + return {}; +}; + +const DeployNodeConfigFormAliyunVODConfig = ({ + form: formInst, + formName, + disabled, + initialValues, + onValuesChange, +}: DeployNodeConfigFormAliyunVODConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + region: z + .string({ message: t("workflow_node.deploy.form.aliyun_vod_region.placeholder") }) + .nonempty(t("workflow_node.deploy.form.aliyun_vod_region.placeholder")) + .trim(), + domain: z + .string({ message: t("workflow_node.deploy.form.aliyun_vod_domain.placeholder") }) + .refine((v) => validDomainName(v), t("common.errmsg.domain_invalid")), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + + + } + > + + +
+ ); +}; + +export default DeployNodeConfigFormAliyunVODConfig; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormBaishanCDNConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormBaishanCDNConfig.tsx new file mode 100644 index 00000000..828d5845 --- /dev/null +++ b/ui/src/components/workflow/node/DeployNodeConfigFormBaishanCDNConfig.tsx @@ -0,0 +1,65 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import { validDomainName } from "@/utils/validators"; + +type DeployNodeConfigFormBaishanCDNConfigFieldValues = Nullish<{ + domain: string; +}>; + +export type DeployNodeConfigFormBaishanCDNConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: DeployNodeConfigFormBaishanCDNConfigFieldValues; + onValuesChange?: (values: DeployNodeConfigFormBaishanCDNConfigFieldValues) => void; +}; + +const initFormModel = (): DeployNodeConfigFormBaishanCDNConfigFieldValues => { + return {}; +}; + +const DeployNodeConfigFormBaishanCDNConfig = ({ + form: formInst, + formName, + disabled, + initialValues, + onValuesChange, +}: DeployNodeConfigFormBaishanCDNConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + domain: z + .string({ message: t("workflow_node.deploy.form.baishan_cdn_domain.placeholder") }) + .refine((v) => validDomainName(v, { allowWildcard: true }), t("common.errmsg.domain_invalid")), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + +
+ ); +}; + +export default DeployNodeConfigFormBaishanCDNConfig; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormBaotaPanelConsoleConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormBaotaPanelConsoleConfig.tsx new file mode 100644 index 00000000..40d93b7f --- /dev/null +++ b/ui/src/components/workflow/node/DeployNodeConfigFormBaotaPanelConsoleConfig.tsx @@ -0,0 +1,56 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Switch } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +type DeployNodeConfigFormBaotaPanelConsoleConfigFieldValues = Nullish<{ + autoRestart?: boolean; +}>; + +export type DeployNodeConfigFormBaotaPanelConsoleConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: DeployNodeConfigFormBaotaPanelConsoleConfigFieldValues; + onValuesChange?: (values: DeployNodeConfigFormBaotaPanelConsoleConfigFieldValues) => void; +}; + +const initFormModel = (): DeployNodeConfigFormBaotaPanelConsoleConfigFieldValues => { + return {}; +}; + +const DeployNodeConfigFormBaotaPanelConsoleConfig = ({ + form: formInst, + formName, + disabled, + initialValues, + onValuesChange, +}: DeployNodeConfigFormBaotaPanelConsoleConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + autoRestart: z.boolean().nullish(), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ + + +
+ ); +}; + +export default DeployNodeConfigFormBaotaPanelConsoleConfig; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormBaotaPanelSiteConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormBaotaPanelSiteConfig.tsx index aa891245..f62379bb 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigFormBaotaPanelSiteConfig.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigFormBaotaPanelSiteConfig.tsx @@ -1,10 +1,19 @@ +import { memo } from "react"; import { useTranslation } from "react-i18next"; -import { Form, type FormInstance, Input } from "antd"; +import { FormOutlined as FormOutlinedIcon } from "@ant-design/icons"; +import { Button, Form, type FormInstance, Input, Select, Space } from "antd"; import { createSchemaFieldRule } from "antd-zod"; import { z } from "zod"; +import ModalForm from "@/components/ModalForm"; +import MultipleInput from "@/components/MultipleInput"; +import Show from "@/components/Show"; +import { useAntdForm } from "@/hooks"; + type DeployNodeConfigFormBaotaPanelSiteConfigFieldValues = Nullish<{ - siteName: string; + siteType: string; + siteName?: string; + siteNames?: string; }>; export type DeployNodeConfigFormBaotaPanelSiteConfigProps = { @@ -15,8 +24,17 @@ export type DeployNodeConfigFormBaotaPanelSiteConfigProps = { onValuesChange?: (values: DeployNodeConfigFormBaotaPanelSiteConfigFieldValues) => void; }; +const SITE_TYPE_PHP = "php"; +const SITE_TYPE_OTHER = "other"; + +const MULTIPLE_INPUT_DELIMITER = ";"; + const initFormModel = (): DeployNodeConfigFormBaotaPanelSiteConfigFieldValues => { - return {}; + return { + siteType: SITE_TYPE_OTHER, + siteName: "", + siteNames: "", + }; }; const DeployNodeConfigFormBaotaPanelSiteConfig = ({ @@ -29,13 +47,32 @@ const DeployNodeConfigFormBaotaPanelSiteConfig = ({ const { t } = useTranslation(); const formSchema = z.object({ + siteType: z.union([z.literal(SITE_TYPE_PHP), z.literal(SITE_TYPE_OTHER)], { + message: t("workflow_node.deploy.form.baotapanel_site_type.placeholder"), + }), siteName: z - .string({ message: t("workflow_node.deploy.form.baotapanel_site_name.placeholder") }) - .nonempty(t("workflow_node.deploy.form.baotapanel_site_name.placeholder")) - .trim(), + .string() + .nullish() + .refine((v) => { + if (fieldSiteType !== SITE_TYPE_PHP) return true; + return !!v?.trim(); + }, t("workflow_node.deploy.form.baotapanel_site_name.placeholder")), + siteNames: z + .string() + .nullish() + .refine((v) => { + if (fieldSiteType !== SITE_TYPE_OTHER) return true; + if (!v) return false; + return String(v) + .split(MULTIPLE_INPUT_DELIMITER) + .every((e) => !!e.trim()); + }, t("workflow_node.deploy.form.baotapanel_site_names.placeholder")), }); const formRule = createSchemaFieldRule(formSchema); + const fieldSiteType = Form.useWatch("siteType", formInst); + const fieldSiteNames = Form.useWatch("siteNames", formInst); + const handleFormChange = (_: unknown, values: z.infer) => { onValuesChange?.(values); }; @@ -49,16 +86,101 @@ const DeployNodeConfigFormBaotaPanelSiteConfig = ({ name={formName} onValuesChange={handleFormChange} > - } - > - + + + + + } + > + + + + + + } + > + + + { + formInst.setFieldValue("siteNames", e.target.value); + }} + /> + + + + + } + onChange={(value) => { + formInst.setFieldValue("siteNames", value); + }} + /> + + + ); }; +const SiteNamesModalInput = memo(({ value, trigger, onChange }: { value?: string; trigger?: React.ReactNode; onChange?: (value: string) => void }) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + siteNames: z.array(z.string()).refine((v) => { + return v.every((e) => !!e?.trim()); + }, t("workflow_node.deploy.form.baotapanel_site_names.errmsg.invalid")), + }); + const formRule = createSchemaFieldRule(formSchema); + const { form: formInst, formProps } = useAntdForm({ + name: "workflowNodeDeployConfigFormBaotaPanelSiteNamesModalInput", + initialValues: { siteNames: value?.split(MULTIPLE_INPUT_DELIMITER) }, + onSubmit: (values) => { + onChange?.( + values.siteNames + .map((e) => e.trim()) + .filter((e) => !!e) + .join(MULTIPLE_INPUT_DELIMITER) + ); + }, + }); + + return ( + + + + + + ); +}); + export default DeployNodeConfigFormBaotaPanelSiteConfig; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormCdnflyConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormCdnflyConfig.tsx new file mode 100644 index 00000000..c9f61e02 --- /dev/null +++ b/ui/src/components/workflow/node/DeployNodeConfigFormCdnflyConfig.tsx @@ -0,0 +1,89 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input, Select } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import Show from "@/components/Show"; + +type DeployNodeConfigFormCdnflyConfigFieldValues = Nullish<{ + resourceType: string; + certificateId?: string | number; +}>; + +export type DeployNodeConfigFormCdnflyConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: DeployNodeConfigFormCdnflyConfigFieldValues; + onValuesChange?: (values: DeployNodeConfigFormCdnflyConfigFieldValues) => void; +}; + +const RESOURCE_TYPE_SITE = "site" as const; +const RESOURCE_TYPE_CERTIFICATE = "certificate" as const; + +const initFormModel = (): DeployNodeConfigFormCdnflyConfigFieldValues => { + return { + resourceType: RESOURCE_TYPE_SITE, + }; +}; + +const DeployNodeConfigFormCdnflyConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: DeployNodeConfigFormCdnflyConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + resourceType: z.union([z.literal(RESOURCE_TYPE_SITE), z.literal(RESOURCE_TYPE_CERTIFICATE)], { + message: t("workflow_node.deploy.form.cdnfly_resource_type.placeholder"), + }), + siteId: z.union([z.string(), z.number().int()]).refine((v) => { + if (fieldResourceType !== RESOURCE_TYPE_SITE) return true; + return /^\d+$/.test(v + "") && +v > 0; + }, t("workflow_node.deploy.form.cdnfly_site_id.placeholder")), + certificateId: z.union([z.string(), z.number().int()]).refine((v) => { + if (fieldResourceType !== RESOURCE_TYPE_CERTIFICATE) return true; + return /^\d+$/.test(v + "") && +v > 0; + }, t("workflow_node.deploy.form.cdnfly_certificate_id.placeholder")), + }); + const formRule = createSchemaFieldRule(formSchema); + + const fieldResourceType = Form.useWatch("resourceType", formInst); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ + + + + + + + + + + + + + + +
+ ); +}; + +export default DeployNodeConfigFormCdnflyConfig; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormGcoreCDNConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormGcoreCDNConfig.tsx new file mode 100644 index 00000000..00dc48dd --- /dev/null +++ b/ui/src/components/workflow/node/DeployNodeConfigFormGcoreCDNConfig.tsx @@ -0,0 +1,59 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +type DeployNodeConfigFormGcoreCDNConfigFieldValues = Nullish<{ + resourceId?: string | number; +}>; + +export type DeployNodeConfigFormGcoreCDNConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: DeployNodeConfigFormGcoreCDNConfigFieldValues; + onValuesChange?: (values: DeployNodeConfigFormGcoreCDNConfigFieldValues) => void; +}; + +const initFormModel = (): DeployNodeConfigFormGcoreCDNConfigFieldValues => { + return { + resourceId: "", + }; +}; + +const DeployNodeConfigFormGcoreCDNConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: DeployNodeConfigFormGcoreCDNConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + resourceId: z.union([z.string(), z.number()]).refine((v) => { + return /^\d+$/.test(v + "") && +v > 0; + }, t("workflow_node.deploy.form.gcore_cdn_certificate_id.placeholder")), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + +
+ ); +}; + +export default DeployNodeConfigFormGcoreCDNConfig; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormHuaweiCloudWAFConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormHuaweiCloudWAFConfig.tsx new file mode 100644 index 00000000..cdcabef5 --- /dev/null +++ b/ui/src/components/workflow/node/DeployNodeConfigFormHuaweiCloudWAFConfig.tsx @@ -0,0 +1,132 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input, Select } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import Show from "@/components/Show"; +import { validDomainName } from "@/utils/validators"; + +type DeployNodeConfigFormHuaweiCloudWAFConfigFieldValues = Nullish<{ + resourceType: string; + region: string; + certificateId?: string; + domain?: string; + listenerId?: string; +}>; + +export type DeployNodeConfigFormHuaweiCloudWAFConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: DeployNodeConfigFormHuaweiCloudWAFConfigFieldValues; + onValuesChange?: (values: DeployNodeConfigFormHuaweiCloudWAFConfigFieldValues) => void; +}; + +const RESOURCE_TYPE_CERTIFICATE = "certificate" as const; +const RESOURCE_TYPE_CLOUDSERVER = "cloudserver" as const; +const RESOURCE_TYPE_PREMIUMHOST = "premiumhost" as const; + +const initFormModel = (): DeployNodeConfigFormHuaweiCloudWAFConfigFieldValues => { + return {}; +}; + +const DeployNodeConfigFormHuaweiCloudWAFConfig = ({ + form: formInst, + formName, + disabled, + initialValues, + onValuesChange, +}: DeployNodeConfigFormHuaweiCloudWAFConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + resourceType: z.union([z.literal(RESOURCE_TYPE_CERTIFICATE), z.literal(RESOURCE_TYPE_CLOUDSERVER), z.literal(RESOURCE_TYPE_PREMIUMHOST)], { + message: t("workflow_node.deploy.form.huaweicloud_waf_resource_type.placeholder"), + }), + region: z + .string({ message: t("workflow_node.deploy.form.huaweicloud_waf_region.placeholder") }) + .nonempty(t("workflow_node.deploy.form.huaweicloud_waf_region.placeholder")) + .trim(), + certificateId: z + .string() + .max(64, t("common.errmsg.string_max", { max: 64 })) + .trim() + .nullish() + .refine((v) => { + if (fieldResourceType !== RESOURCE_TYPE_CERTIFICATE) return true; + return !!v?.trim(); + }, t("workflow_node.deploy.form.huaweicloud_waf_certificate_id.placeholder")), + domain: z + .string() + .nullish() + .refine((v) => { + if (fieldResourceType !== RESOURCE_TYPE_CLOUDSERVER && fieldResourceType !== RESOURCE_TYPE_PREMIUMHOST) return true; + return validDomainName(v!, { allowWildcard: true }); + }, t("workflow_node.deploy.form.huaweicloud_waf_domain.placeholder")), + }); + const formRule = createSchemaFieldRule(formSchema); + + const fieldResourceType = Form.useWatch("resourceType", formInst); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ + + + + } + > + + + + + } + > + + + + + + } + > + + + +
+ ); +}; + +export default DeployNodeConfigFormHuaweiCloudWAFConfig; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormJDCloudALBConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormJDCloudALBConfig.tsx new file mode 100644 index 00000000..f54477ce --- /dev/null +++ b/ui/src/components/workflow/node/DeployNodeConfigFormJDCloudALBConfig.tsx @@ -0,0 +1,142 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input, Select } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import Show from "@/components/Show"; +import { validDomainName } from "@/utils/validators"; + +type DeployNodeConfigFormJDCloudALBConfigFieldValues = Nullish<{ + resourceType: string; + regionId: string; + loadbalancerId?: string; + listenerId?: string; + domain?: string; +}>; + +export type DeployNodeConfigFormJDCloudALBConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: DeployNodeConfigFormJDCloudALBConfigFieldValues; + onValuesChange?: (values: DeployNodeConfigFormJDCloudALBConfigFieldValues) => void; +}; + +const RESOURCE_TYPE_LOADBALANCER = "loadbalancer" as const; +const RESOURCE_TYPE_LISTENER = "listener" as const; + +const initFormModel = (): DeployNodeConfigFormJDCloudALBConfigFieldValues => { + return {}; +}; + +const DeployNodeConfigFormJDCloudALBConfig = ({ + form: formInst, + formName, + disabled, + initialValues, + onValuesChange, +}: DeployNodeConfigFormJDCloudALBConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + resourceType: z.union([z.literal(RESOURCE_TYPE_LOADBALANCER), z.literal(RESOURCE_TYPE_LISTENER)], { + message: t("workflow_node.deploy.form.jdcloud_alb_resource_type.placeholder"), + }), + regionId: z + .string({ message: t("workflow_node.deploy.form.jdcloud_alb_region_id.placeholder") }) + .nonempty(t("workflow_node.deploy.form.jdcloud_alb_region_id.placeholder")) + .trim(), + loadbalancerId: z + .string() + .max(64, t("common.errmsg.string_max", { max: 64 })) + .trim() + .nullish() + .refine((v) => fieldResourceType !== RESOURCE_TYPE_LOADBALANCER || !!v?.trim(), t("workflow_node.deploy.form.jdcloud_alb_loadbalancer_id.placeholder")), + listenerId: z + .string() + .max(64, t("common.errmsg.string_max", { max: 64 })) + .trim() + .nullish() + .refine((v) => fieldResourceType !== RESOURCE_TYPE_LISTENER || !!v?.trim(), t("workflow_node.deploy.form.jdcloud_alb_listener_id.placeholder")), + domain: z + .string() + .nullish() + .refine((v) => { + if (![RESOURCE_TYPE_LOADBALANCER, RESOURCE_TYPE_LISTENER].includes(fieldResourceType)) return true; + return !v || validDomainName(v!, { allowWildcard: true }); + }, t("common.errmsg.domain_invalid")), + }); + const formRule = createSchemaFieldRule(formSchema); + + const fieldResourceType = Form.useWatch("resourceType", formInst); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ + + + + } + > + + + + + } + > + + + + + + } + > + + + + + + } + > + + + +
+ ); +}; + +export default DeployNodeConfigFormJDCloudALBConfig; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormJDCloudCDNConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormJDCloudCDNConfig.tsx new file mode 100644 index 00000000..9d8af17e --- /dev/null +++ b/ui/src/components/workflow/node/DeployNodeConfigFormJDCloudCDNConfig.tsx @@ -0,0 +1,65 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import { validDomainName } from "@/utils/validators"; + +type DeployNodeConfigFormJDCloudCDNConfigFieldValues = Nullish<{ + domain: string; +}>; + +export type DeployNodeConfigFormJDCloudCDNConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: DeployNodeConfigFormJDCloudCDNConfigFieldValues; + onValuesChange?: (values: DeployNodeConfigFormJDCloudCDNConfigFieldValues) => void; +}; + +const initFormModel = (): DeployNodeConfigFormJDCloudCDNConfigFieldValues => { + return {}; +}; + +const DeployNodeConfigFormJDCloudCDNConfig = ({ + form: formInst, + formName, + disabled, + initialValues, + onValuesChange, +}: DeployNodeConfigFormJDCloudCDNConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + domain: z + .string({ message: t("workflow_node.deploy.form.jdcloud_cdn_domain.placeholder") }) + .refine((v) => validDomainName(v, { allowWildcard: true }), t("common.errmsg.domain_invalid")), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + +
+ ); +}; + +export default DeployNodeConfigFormJDCloudCDNConfig; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormJDCloudLiveConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormJDCloudLiveConfig.tsx new file mode 100644 index 00000000..5e13f5eb --- /dev/null +++ b/ui/src/components/workflow/node/DeployNodeConfigFormJDCloudLiveConfig.tsx @@ -0,0 +1,65 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import { validDomainName } from "@/utils/validators"; + +type DeployNodeConfigFormJDCloudLiveConfigFieldValues = Nullish<{ + domain: string; +}>; + +export type DeployNodeConfigFormJDCloudLiveConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: DeployNodeConfigFormJDCloudLiveConfigFieldValues; + onValuesChange?: (values: DeployNodeConfigFormJDCloudLiveConfigFieldValues) => void; +}; + +const initFormModel = (): DeployNodeConfigFormJDCloudLiveConfigFieldValues => { + return {}; +}; + +const DeployNodeConfigFormJDCloudLiveConfig = ({ + form: formInst, + formName, + disabled, + initialValues, + onValuesChange, +}: DeployNodeConfigFormJDCloudLiveConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + domain: z + .string({ message: t("workflow_node.deploy.form.jdcloud_live_domain.placeholder") }) + .refine((v) => validDomainName(v), t("common.errmsg.domain_invalid")), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + +
+ ); +}; + +export default DeployNodeConfigFormJDCloudLiveConfig; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormJDCloudVODConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormJDCloudVODConfig.tsx new file mode 100644 index 00000000..ad64a735 --- /dev/null +++ b/ui/src/components/workflow/node/DeployNodeConfigFormJDCloudVODConfig.tsx @@ -0,0 +1,65 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import { validDomainName } from "@/utils/validators"; + +type DeployNodeConfigFormJDCloudVODConfigFieldValues = Nullish<{ + domain: string; +}>; + +export type DeployNodeConfigFormJDCloudVODConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: DeployNodeConfigFormJDCloudVODConfigFieldValues; + onValuesChange?: (values: DeployNodeConfigFormJDCloudVODConfigFieldValues) => void; +}; + +const initFormModel = (): DeployNodeConfigFormJDCloudVODConfigFieldValues => { + return {}; +}; + +const DeployNodeConfigFormJDCloudVODConfig = ({ + form: formInst, + formName, + disabled, + initialValues, + onValuesChange, +}: DeployNodeConfigFormJDCloudVODConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + domain: z + .string({ message: t("workflow_node.deploy.form.jdcloud_vod_domain.placeholder") }) + .refine((v) => validDomainName(v), t("common.errmsg.domain_invalid")), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + +
+ ); +}; + +export default DeployNodeConfigFormJDCloudVODConfig; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormSafeLineConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormSafeLineConfig.tsx new file mode 100644 index 00000000..239a6c92 --- /dev/null +++ b/ui/src/components/workflow/node/DeployNodeConfigFormSafeLineConfig.tsx @@ -0,0 +1,76 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input, Select } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import Show from "@/components/Show"; + +type DeployNodeConfigFormSafeLineConfigFieldValues = Nullish<{ + resourceType: string; + certificateId?: string | number; +}>; + +export type DeployNodeConfigFormSafeLineConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: DeployNodeConfigFormSafeLineConfigFieldValues; + onValuesChange?: (values: DeployNodeConfigFormSafeLineConfigFieldValues) => void; +}; + +const RESOURCE_TYPE_CERTIFICATE = "certificate" as const; + +const initFormModel = (): DeployNodeConfigFormSafeLineConfigFieldValues => { + return { + resourceType: RESOURCE_TYPE_CERTIFICATE, + certificateId: "", + }; +}; + +const DeployNodeConfigFormSafeLineConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: DeployNodeConfigFormSafeLineConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + resourceType: z.literal(RESOURCE_TYPE_CERTIFICATE, { + message: t("workflow_node.deploy.form.safeline_resource_type.placeholder"), + }), + certificateId: z.union([z.string(), z.number().int()]).refine((v) => { + if (fieldResourceType !== RESOURCE_TYPE_CERTIFICATE) return true; + return /^\d+$/.test(v + "") && +v > 0; + }, t("workflow_node.deploy.form.safeline_certificate_id.placeholder")), + }); + const formRule = createSchemaFieldRule(formSchema); + + const fieldResourceType = Form.useWatch("resourceType", formInst); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ + + + + + + + + +
+ ); +}; + +export default DeployNodeConfigFormSafeLineConfig; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudSSLDeployConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudSSLDeployConfig.tsx index 14266151..67cdbf11 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudSSLDeployConfig.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudSSLDeployConfig.tsx @@ -48,6 +48,7 @@ const DeployNodeConfigFormTencentCloudSSLDeployConfig = ({ .nonempty(t("workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_type.placeholder")) .trim(), resourceIds: z.string({ message: t("workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_ids.placeholder") }).refine((v) => { + if (!v) return false; return String(v) .split(MULTIPLE_INPUT_DELIMITER) .every((e) => /^[A-Za-z0-9._-]+$/.test(e)); diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudVODConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudVODConfig.tsx new file mode 100644 index 00000000..2c5742eb --- /dev/null +++ b/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudVODConfig.tsx @@ -0,0 +1,82 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import { validDomainName } from "@/utils/validators"; + +type DeployNodeConfigFormTencentCloudVODConfigFieldValues = Nullish<{ + subAppId?: string | number; + domain: string; +}>; + +export type DeployNodeConfigFormTencentCloudVODConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: DeployNodeConfigFormTencentCloudVODConfigFieldValues; + onValuesChange?: (values: DeployNodeConfigFormTencentCloudVODConfigFieldValues) => void; +}; + +const initFormModel = (): DeployNodeConfigFormTencentCloudVODConfigFieldValues => { + return {}; +}; + +const DeployNodeConfigFormTencentCloudVODConfig = ({ + form: formInst, + formName, + disabled, + initialValues, + onValuesChange, +}: DeployNodeConfigFormTencentCloudVODConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + subAppId: z + .union([z.string(), z.number()]) + .nullish() + .refine((v) => { + if (v == null) return true; + return /^\d+$/.test(v + "") && +v > 0; + }, t("workflow_node.deploy.form.tencentcloud_vod_sub_app_id.placeholder")), + domain: z + .string({ message: t("workflow_node.deploy.form.tencentcloud_vod_domain.placeholder") }) + .refine((v) => validDomainName(v), t("common.errmsg.domain_invalid")), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + + + } + > + + +
+ ); +}; + +export default DeployNodeConfigFormTencentCloudVODConfig; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudWAFConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudWAFConfig.tsx new file mode 100644 index 00000000..347ebaa2 --- /dev/null +++ b/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudWAFConfig.tsx @@ -0,0 +1,107 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import { validDomainName } from "@/utils/validators"; + +type DeployNodeConfigFormTencentCloudWAFConfigFieldValues = Nullish<{ + region: string; + domain: string; + domainId: string; + instanceId: string; +}>; + +export type DeployNodeConfigFormTencentCloudWAFConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: DeployNodeConfigFormTencentCloudWAFConfigFieldValues; + onValuesChange?: (values: DeployNodeConfigFormTencentCloudWAFConfigFieldValues) => void; +}; + +const initFormModel = (): DeployNodeConfigFormTencentCloudWAFConfigFieldValues => { + return {}; +}; + +const DeployNodeConfigFormTencentCloudWAFConfig = ({ + form: formInst, + formName, + disabled, + initialValues, + onValuesChange, +}: DeployNodeConfigFormTencentCloudWAFConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + region: z + .string({ message: t("workflow_node.deploy.form.tencentcloud_waf_region.placeholder") }) + .nonempty(t("workflow_node.deploy.form.tencentcloud_waf_region.placeholder")) + .trim(), + domain: z + .string({ message: t("workflow_node.deploy.form.tencentcloud_waf_domain.placeholder") }) + .refine((v) => validDomainName(v), t("common.errmsg.domain_invalid")), + domainId: z + .string({ message: t("workflow_node.deploy.form.tencentcloud_waf_domain_id.placeholder") }) + .nonempty(t("workflow_node.deploy.form.tencentcloud_waf_domain_id.placeholder")) + .trim(), + instanceId: z + .string({ message: t("workflow_node.deploy.form.tencentcloud_waf_instance_id.placeholder") }) + .nonempty(t("workflow_node.deploy.form.tencentcloud_waf_instance_id.placeholder")) + .trim(), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + + + } + > + + + + } + > + + + + } + > + + +
+ ); +}; + +export default DeployNodeConfigFormTencentCloudWAFConfig; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormVolcEngineImageXConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormVolcEngineImageXConfig.tsx new file mode 100644 index 00000000..61f59e23 --- /dev/null +++ b/ui/src/components/workflow/node/DeployNodeConfigFormVolcEngineImageXConfig.tsx @@ -0,0 +1,91 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import { validDomainName } from "@/utils/validators"; + +type DeployNodeConfigFormVolcEngineImageXConfigFieldValues = Nullish<{ + domain: string; +}>; + +export type DeployNodeConfigFormVolcEngineImageXConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: DeployNodeConfigFormVolcEngineImageXConfigFieldValues; + onValuesChange?: (values: DeployNodeConfigFormVolcEngineImageXConfigFieldValues) => void; +}; + +const initFormModel = (): DeployNodeConfigFormVolcEngineImageXConfigFieldValues => { + return {}; +}; + +const DeployNodeConfigFormVolcEngineImageXConfig = ({ + form: formInst, + formName, + disabled, + initialValues, + onValuesChange, +}: DeployNodeConfigFormVolcEngineImageXConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + region: z + .string({ message: t("workflow_node.deploy.form.volcengine_imagex_region.placeholder") }) + .nonempty(t("workflow_node.deploy.form.volcengine_imagex_region.placeholder")) + .trim(), + serviceId: z + .string({ message: t("workflow_node.deploy.form.volcengine_imagex_service_id.placeholder") }) + .nonempty(t("workflow_node.deploy.form.volcengine_imagex_service_id.placeholder")) + .trim(), + domain: z + .string({ message: t("workflow_node.deploy.form.volcengine_imagex_domain.placeholder") }) + .refine((v) => validDomainName(v), t("common.errmsg.domain_invalid")), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + + + } + > + + + + } + > + + +
+ ); +}; + +export default DeployNodeConfigFormVolcEngineImageXConfig; diff --git a/ui/src/domain/access.ts b/ui/src/domain/access.ts index cf6b1055..d32960ca 100644 --- a/ui/src/domain/access.ts +++ b/ui/src/domain/access.ts @@ -11,22 +11,31 @@ export interface AccessModel extends BaseModel { | AccessConfigForAWS | AccessConfigForAzure | AccessConfigForBaiduCloud + | AccessConfigForBaishan | AccessConfigForBaotaPanel | AccessConfigForBytePlus + | AccessConfigForCacheFly + | AccessConfigForCdnfly | AccessConfigForCloudflare | AccessConfigForClouDNS + | AccessConfigForCMCCCloud + | AccessConfigForDNSLA | AccessConfigForDogeCloud | AccessConfigForEdgio + | AccessConfigForGcore | AccessConfigForGname | AccessConfigForGoDaddy | AccessConfigForHuaweiCloud + | AccessConfigForJDCloud | AccessConfigForKubernetes | AccessConfigForLocal + | AccessConfigForNamecheap | AccessConfigForNameDotCom | AccessConfigForNameSilo | AccessConfigForPowerDNS | AccessConfigForQiniu | AccessConfigForRainYun + | AccessConfigForSafeLine | AccessConfigForSSH | AccessConfigForTencentCloud | AccessConfigForUCloud @@ -66,6 +75,10 @@ export type AccessConfigForBaiduCloud = { secretAccessKey: string; }; +export type AccessConfigForBaishan = { + apiToken: string; +}; + export type AccessConfigForBaotaPanel = { apiUrl: string; apiKey: string; @@ -76,6 +89,16 @@ export type AccessConfigForBytePlus = { secretKey: string; }; +export type AccessConfigForCacheFly = { + apiToken: string; +}; + +export type AccessConfigForCdnfly = { + apiUrl: string; + apiKey: string; + apiSecret: string; +}; + export type AccessConfigForCloudflare = { dnsApiToken: string; }; @@ -85,6 +108,16 @@ export type AccessConfigForClouDNS = { authPassword: string; }; +export type AccessConfigForCMCCCloud = { + accessKeyId: string; + accessKeySecret: string; +}; + +export type AccessConfigForDNSLA = { + apiId: string; + apiSecret: string; +}; + export type AccessConfigForDogeCloud = { accessKey: string; secretKey: string; @@ -95,6 +128,10 @@ export type AccessConfigForEdgio = { clientSecret: string; }; +export type AccessConfigForGcore = { + apiToken: string; +}; + export type AccessConfigForGname = { appId: string; appKey: string; @@ -110,12 +147,22 @@ export type AccessConfigForHuaweiCloud = { secretAccessKey: string; }; +export type AccessConfigForJDCloud = { + accessKeyId: string; + accessKeySecret: string; +}; + export type AccessConfigForKubernetes = { kubeConfig?: string; }; export type AccessConfigForLocal = NonNullable; +export type AccessConfigForNamecheap = { + username: string; + apiKey: string; +}; + export type AccessConfigForNameDotCom = { username: string; apiToken: string; @@ -143,6 +190,11 @@ export type AccessConfigForRainYun = { apiKey: string; }; +export type AccessConfigForSafeLine = { + apiUrl: string; + apiToken: string; +}; + export type AccessConfigForSSH = { host: string; port: number; diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts index 1a3272cd..0841f39d 100644 --- a/ui/src/domain/provider.ts +++ b/ui/src/domain/provider.ts @@ -9,23 +9,32 @@ export const ACCESS_PROVIDERS = Object.freeze({ AWS: "aws", AZURE: "azure", BAIDUCLOUD: "baiducloud", + BAISHAN: "baishan", BAOTAPANEL: "baotapanel", BYTEPLUS: "byteplus", + CACHEFLY: "cachefly", + CDNFLY: "cdnfly", CLOUDFLARE: "cloudflare", CLOUDNS: "cloudns", + CMCCCLOUD: "cmcccloud", + DNSLA: "dnsla", DOGECLOUD: "dogecloud", + GCORE: "gcore", GNAME: "gname", GODADDY: "godaddy", EDGIO: "edgio", HUAWEICLOUD: "huaweicloud", + JDCLOUD: "jdcloud", KUBERNETES: "k8s", LOCAL: "local", + NAMECHEAP: "namecheap", NAMEDOTCOM: "namedotcom", NAMESILO: "namesilo", NS1: "ns1", POWERDNS: "powerdns", QINIU: "qiniu", RAINYUN: "rainyun", + SAFELINE: "safeline", SSH: "ssh", TENCENTCLOUD: "tencentcloud", UCLOUD: "ucloud", @@ -62,24 +71,35 @@ export const accessProvidersMap: Map [ type, { diff --git a/ui/src/hooks/index.ts b/ui/src/hooks/index.ts index 045c0aad..6f154701 100644 --- a/ui/src/hooks/index.ts +++ b/ui/src/hooks/index.ts @@ -2,6 +2,7 @@ import useAntdFormName from "./useAntdFormName"; import useBrowserTheme from "./useBrowserTheme"; import useTriggerElement from "./useTriggerElement"; +import useVersionChecker from "./useVersionChecker"; import useZustandShallowSelector from "./useZustandShallowSelector"; -export { useAntdForm, useAntdFormName, useBrowserTheme, useTriggerElement, useZustandShallowSelector }; +export { useAntdForm, useAntdFormName, useBrowserTheme, useTriggerElement, useVersionChecker, useZustandShallowSelector }; diff --git a/ui/src/hooks/useVersionChecker.ts b/ui/src/hooks/useVersionChecker.ts new file mode 100644 index 00000000..5dcc96f8 --- /dev/null +++ b/ui/src/hooks/useVersionChecker.ts @@ -0,0 +1,70 @@ +import { useRequest } from "ahooks"; + +import { version } from "@/domain/version"; + +export type UseVersionCheckerReturns = { + hasNewVersion: boolean; + check: () => void; +}; + +const extractSemver = (vers: string) => { + let semver = String(vers ?? ""); + semver = semver.replace(/^v/i, ""); + semver = semver.split("-")[0]; + return semver; +}; + +const compareVersions = (a: string, b: string) => { + const aSemver = extractSemver(a); + const bSemver = extractSemver(b); + const aSemverParts = aSemver.split("."); + const bSemverParts = bSemver.split("."); + + const len = Math.max(aSemverParts.length, bSemverParts.length); + for (let i = 0; i < len; i++) { + const aPart = parseInt(aSemverParts[i] ?? "0"); + const bPart = parseInt(bSemverParts[i] ?? "0"); + if (aPart > bPart) return 1; + if (bPart > aPart) return -1; + } + + return 0; +}; + +/** + * 获取版本检查器。 + * @returns {UseVersionCheckerReturns} + */ +const useVersionChecker = () => { + const { data, refresh } = useRequest( + async () => { + const releases = await fetch("https://api.github.com/repos/usual2970/certimate/releases") + .then((res) => res.json()) + .then((res) => Array.from(res)); + + const cIdx = releases.findIndex((e: any) => e.name === version); + if (cIdx === 0) { + return false; + } + + const nIdx = releases.findIndex((e: any) => compareVersions(e.name, version) !== -1); + if (cIdx >= nIdx) { + return false; + } + + return !!releases[nIdx]; + }, + { + pollingInterval: 6 * 60 * 60 * 1000, + refreshOnWindowFocus: true, + focusTimespan: 15 * 60 * 1000, + } + ); + + return { + hasNewVersion: !!data, + check: refresh, + }; +}; + +export default useVersionChecker; diff --git a/ui/src/i18n/locales/en/nls.access.json b/ui/src/i18n/locales/en/nls.access.json index af3676b3..dc468b92 100644 --- a/ui/src/i18n/locales/en/nls.access.json +++ b/ui/src/i18n/locales/en/nls.access.json @@ -38,8 +38,8 @@ "access.form.aliyun_access_key_id.label": "Aliyun AccessKeyId", "access.form.aliyun_access_key_id.placeholder": "Please enter Aliyun AccessKeyId", "access.form.aliyun_access_key_id.tooltip": "For more information, see https://www.alibabacloud.com/help/en/acr/create-and-obtain-an-accesskey-pair", - "access.form.aliyun_access_key_secret.label": "Aliyun AccessKey Secret", - "access.form.aliyun_access_key_secret.placeholder": "Please enter Aliyun AccessKey Secret", + "access.form.aliyun_access_key_secret.label": "Aliyun AccessKeySecret", + "access.form.aliyun_access_key_secret.placeholder": "Please enter Aliyun AccessKeySecret", "access.form.aliyun_access_key_secret.tooltip": "For more information, see https://www.alibabacloud.com/help/en/acr/create-and-obtain-an-accesskey-pair", "access.form.aws_access_key_id.label": "AWS AccessKeyId", "access.form.aws_access_key_id.placeholder": "Please enter AWS AccessKeyId", @@ -65,6 +65,8 @@ "access.form.baiducloud_secret_access_key.label": "Baidu Cloud SecretAccessKey", "access.form.baiducloud_secret_access_key.placeholder": "Please enter Baidu Cloud SecretAccessKey", "access.form.baiducloud_secret_access_key.tooltip": "For more information, see https://intl.cloud.baidu.com/doc/Reference/s/jjwvz2e3p-en", + "access.form.baishan_api_token.label": "Baishan Cloud API token", + "access.form.baishan_api_token.placeholder": "Please enter Baishan Cloud API token", "access.form.baotapanel_api_url.label": "BaoTa Panel URL", "access.form.baotapanel_api_url.placeholder": "Please enter BaoTa Panel URL", "access.form.baotapanel_api_url.tooltip": "For more information, see https://www.bt.cn/bbs/thread-20376-1-1.html", @@ -77,6 +79,18 @@ "access.form.byteplus_secret_key.label": "BytePlus SecretKey", "access.form.byteplus_secret_key.placeholder": "Please enter BytePlus SecretKey", "access.form.byteplus_secret_key.tooltip": "For more information, see https://docs.byteplus.com/en/docs/byteplus-platform/docs-managing-keys", + "access.form.cachefly_api_token.label": "CacheFly API token", + "access.form.cachefly_api_token.placeholder": "Please enter CacheFly API token", + "access.form.cachefly_api_token.tooltip": "For more information, see https://kb.cachefly.com/kb/guide/en/generating-tokens-and-keys-Oll9Irt5TI/Steps/2460228", + "access.form.cdnfly_api_url.label": "Cdnfly API URL", + "access.form.cdnfly_api_url.placeholder": "Please enter Cdnfly API URL", + "access.form.cdnfly_api_url.tooltip": "For more information, see https://doc.cdnfly.cn/anzhuangshuoming.html", + "access.form.cdnfly_api_key.label": "Cdnfly user API key", + "access.form.cdnfly_api_key.placeholder": "Please enter Cdnfly user API key", + "access.form.cdnfly_api_key.tooltip": "For more information, see https://doc.cdnfly.cn/shiyongjieshao.html", + "access.form.cdnfly_api_secret.label": "Cdnfly user API secret", + "access.form.cdnfly_api_secret.placeholder": "Please enter Cdnfly user API secret", + "access.form.cdnfly_api_secret.tooltip": "For more information, see https://doc.cdnfly.cn/shiyongjieshao.html", "access.form.cloudflare_dns_api_token.label": "Cloudflare API token", "access.form.cloudflare_dns_api_token.placeholder": "Please enter Cloudflare API token", "access.form.cloudflare_dns_api_token.tooltip": "For more information, see https://developers.cloudflare.com/fundamentals/api/get-started/create-token/", @@ -86,6 +100,18 @@ "access.form.cloudns_auth_password.label": "ClouDNS API user password", "access.form.cloudns_auth_password.placeholder": "Please enter ClouDNS API user password", "access.form.cloudns_auth_password.tooltip": "For more information, see https://www.cloudns.net/wiki/article/42/", + "access.form.cmcccloud_access_key_id.label": "CMCC ECloud AccessKeyId", + "access.form.cmcccloud_access_key_id.placeholder": "Please enter CMCC ECloud AccessKeyId", + "access.form.cmcccloud_access_key_id.tooltip": "For more information, see https://ecloud.10086.cn/op-help-center/doc/article/49739", + "access.form.cmcccloud_access_key_secret.label": "CMCC ECloud AccessKeySecret", + "access.form.cmcccloud_access_key_secret.placeholder": "Please enter CMCC ECloud AccessKeySecret", + "access.form.cmcccloud_access_key_secret.tooltip": "For more information, see https://ecloud.10086.cn/op-help-center/doc/article/49739", + "access.form.dnsla_api_id.label": "DNS.LA API ID", + "access.form.dnsla_api_id.placeholder": "Please enter DNS.LA API ID", + "access.form.dnsla_api_id.tooltip": "For more information, see https://www.dns.la/docs/ApiDoc", + "access.form.dnsla_api_secret.label": "DNS.LA API secret", + "access.form.dnsla_api_secret.placeholder": "Please enter DNS.LA API secret", + "access.form.dnsla_api_secret.tooltip": "For more information, see https://www.dns.la/docs/ApiDoc", "access.form.dogecloud_access_key.label": "Doge Cloud AccessKey", "access.form.dogecloud_access_key.placeholder": "Please enter Doge Cloud AccessKey", "access.form.dogecloud_access_key.tooltip": "For more information, see https://console.dogecloud.com/", @@ -98,6 +124,9 @@ "access.form.edgio_client_secret.label": "Edgio ClientSecret", "access.form.edgio_client_secret.placeholder": "Please enter Edgio ClientSecret", "access.form.edgio_client_secret.tooltip": "For more information, see https://docs.edg.io/applications/v7/rest_api/authentication#administering-api-clients", + "access.form.gcore_api_token.label": "Gcore API token", + "access.form.gcore_api_token.placeholder": "Please enter Gcore API token", + "access.form.gcore_api_token.tooltip": "For more information, see https://api.gcore.com/docs/iam#section/Authentication", "access.form.gname_app_id.label": "GNAME AppId", "access.form.gname_app_id.placeholder": "Please enter GNAME AppId", "access.form.gname_app_id.tooltip": "For more information, see https://www.gname.com/user#/dealer_api", @@ -116,10 +145,22 @@ "access.form.huaweicloud_secret_access_key.label": "Huawei Cloud SecretAccessKey", "access.form.huaweicloud_secret_access_key.placeholder": "Please enter Huawei Cloud SecretAccessKey", "access.form.huaweicloud_secret_access_key.tooltip": "For more information, see https://support.huaweicloud.com/intl/en-us/usermanual-ca/ca_01_0003.html", + "access.form.jdcloud_access_key_id.label": "JD Cloud AccessKeyId", + "access.form.jdcloud_access_key_id.placeholder": "Please enter JD Cloud AccessKeyId", + "access.form.jdcloud_access_key_id.tooltip": "For more information, see https://docs.jdcloud.com/en/account-management/accesskey-management", + "access.form.jdcloud_access_key_secret.label": "JD Cloud AccessKeySecret", + "access.form.jdcloud_access_key_secret.placeholder": "Please enter JD Cloud AccessKeySecret", + "access.form.jdcloud_access_key_secret.tooltip": "For more information, see https://docs.jdcloud.com/en/account-management/accesskey-management", "access.form.k8s_kubeconfig.label": "KubeConfig", "access.form.k8s_kubeconfig.placeholder": "Please enter KubeConfig file", "access.form.k8s_kubeconfig.upload": "Choose File ...", "access.form.k8s_kubeconfig.tooltip": "For more information, see https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/

Leave it blank to use the Pod's ServiceAccount.", + "access.form.namecheap_username.label": "Namecheap username", + "access.form.namecheap_username.placeholder": "Please enter Namecheap username", + "access.form.namecheap_username.tooltip": "For more information, see https://www.namecheap.com/support/api/intro/", + "access.form.namecheap_api_key.label": "Namecheap API key", + "access.form.namecheap_api_key.placeholder": "Please enter Namecheap API key", + "access.form.namecheap_api_key.tooltip": "For more information, see https://www.namecheap.com/support/api/intro/", "access.form.namedotcom_username.label": "Name.com username", "access.form.namedotcom_username.placeholder": "Please enter Name.com username", "access.form.namedotcom_username.tooltip": "For more information, see https://www.name.com/account/settings/api", @@ -147,6 +188,12 @@ "access.form.rainyun_api_key.label": "Rain Yun API key", "access.form.rainyun_api_key.placeholder": "Please enter Rain Yun API key", "access.form.rainyun_api_key.tooltip": "For more information, see https://www.rainyun.com/docs/account/racc/setting", + "access.form.safeline_api_url.label": "SafeLine URL", + "access.form.safeline_api_url.placeholder": "Please enter SafeLine URL", + "access.form.safeline_api_url.tooltip": "For more information, see https://docs.waf.chaitin.com/en/tutorials/install", + "access.form.safeline_api_token.label": "SafeLine API token", + "access.form.safeline_api_token.placeholder": "Please enter SafeLine API token", + "access.form.safeline_api_token.tooltip": "For more information, see https://docs.waf.chaitin.com/en/reference/articles/openapi", "access.form.ssh_host.label": "Server host", "access.form.ssh_host.placeholder": "Please enter server host", "access.form.ssh_port.label": "Server port", diff --git a/ui/src/i18n/locales/en/nls.common.json b/ui/src/i18n/locales/en/nls.common.json index d5e5508b..c9e671ce 100644 --- a/ui/src/i18n/locales/en/nls.common.json +++ b/ui/src/i18n/locales/en/nls.common.json @@ -35,76 +35,6 @@ "common.errmsg.ip_invalid": "Please enter a valid IP address", "common.errmsg.url_invalid": "Please enter a valid URL", - "provider.acmehttpreq": "Http Request (ACME Proxy)", - "provider.aliyun": "Alibaba Cloud", - "provider.aliyun.alb": "Alibaba Cloud - ALB (Application Load Balancer)", - "provider.aliyun.cas_deploy": "Alibaba Cloud - via CAS (Certificate Management Service) Deployment Job", - "provider.aliyun.cdn": "Alibaba Cloud - CDN (Content Delivery Network)", - "provider.aliyun.clb": "Alibaba Cloud - CLB (Classic Load Balancer)", - "provider.aliyun.dcdn": "Alibaba Cloud - DCDN (Dynamic Route for Content Delivery Network)", - "provider.aliyun.dns": "Alibaba Cloud - DNS (Domain Name Service)", - "provider.aliyun.esa": "Alibaba Cloud - ESA (Edge Security Acceleration)", - "provider.aliyun.live": "Alibaba Cloud - ApsaraVideo Live", - "provider.aliyun.nlb": "Alibaba Cloud - NLB (Network Load Balancer)", - "provider.aliyun.oss": "Alibaba Cloud - OSS (Object Storage Service)", - "provider.aliyun.waf": "Alibaba Cloud - WAF (Web Application Firewall)", - "provider.aws": "AWS", - "provider.aws.cloudfront": "AWS - CloudFront", - "provider.aws.route53": "AWS - Route53", - "provider.azure": "Azure", - "provider.azure.dns": "Azure - DNS", - "provider.baiducloud": "Baidu Cloud", - "provider.baiducloud.cdn": "Baidu Cloud - CDN (Content Delivery Network)", - "provider.baotapanel": "BaoTa Panel", - "provider.baotapanel.site": "BaoTa Panel - Site", - "provider.byteplus": "BytePlus", - "provider.byteplus.cdn": "BytePlus - CDN (Content Delivery Network)", - "provider.cloudflare": "Cloudflare", - "provider.cloudns": "ClouDNS", - "provider.dogecloud": "Doge Cloud", - "provider.dogecloud.cdn": "Doge Cloud - CDN (Content Delivery Network)", - "provider.edgio": "Edgio", - "provider.edgio.applications": "Edgio - Applications", - "provider.gname": "GNAME", - "provider.godaddy": "GoDaddy", - "provider.huaweicloud": "Huawei Cloud", - "provider.huaweicloud.cdn": "Huawei Cloud - CDN (Content Delivery Network)", - "provider.huaweicloud.dns": "Huawei Cloud - DNS (Domain Name Service)", - "provider.huaweicloud.elb": "Huawei Cloud - ELB (Elastic Load Balance)", - "provider.kubernetes": "Kubernetes", - "provider.kubernetes.secret": "Kubernetes - Secret", - "provider.local": "Local deployment", - "provider.namedotcom": "Name.com", - "provider.namesilo": "NameSilo", - "provider.ns1": "NS1 (IBM NS1 Connect)", - "provider.powerdns": "PowerDNS", - "provider.qiniu": "Qiniu", - "provider.qiniu.cdn": "Qiniu - CDN (Content Delivery Network)", - "provider.qiniu.pili": "Qiniu - Pili", - "provider.rainyun": "Rain Yun", - "provider.ssh": "SSH deployment", - "provider.tencentcloud": "Tencent Cloud", - "provider.tencentcloud.cdn": "Tencent Cloud - CDN (Content Delivery Network)", - "provider.tencentcloud.clb": "Tencent Cloud - CLB (Cloud Load Balancer)", - "provider.tencentcloud.cos": "Tencent Cloud - COS (Cloud Object Storage)", - "provider.tencentcloud.css": "Tencent Cloud - CSS (Cloud Streaming Service)", - "provider.tencentcloud.dns": "Tencent Cloud - DNS (Domain Name Service)", - "provider.tencentcloud.ecdn": "Tencent Cloud - ECDN (Enterprise Content Delivery Network)", - "provider.tencentcloud.eo": "Tencent Cloud - EdgeOne", - "provider.tencentcloud.ssl_deploy": "Tencent Cloud - via SSL Certificate Service Deployment Job", - "provider.ucloud": "UCloud", - "provider.ucloud.ucdn": "UCloud - UCDN (UCloud Content Delivery Network)", - "provider.ucloud.us3": "UCloud - US3 (UCloud Object-based Storage)", - "provider.volcengine": "Volcengine", - "provider.volcengine.cdn": "Volcengine - CDN (Content Delivery Network)", - "provider.volcengine.clb": "Volcengine - CLB (Cloud Load Balancer)", - "provider.volcengine.dcdn": "Volcengine - DCDN (Dynamic Content Delivery Network)", - "provider.volcengine.dns": "Volcengine - DNS (Domain Name Service)", - "provider.volcengine.live": "Volcengine - Live", - "provider.volcengine.tos": "Volcengine - TOS (Tinder Object Storage)", - "provider.webhook": "Webhook", - "provider.westcn": "West.cn", - "common.notifier.bark": "Bark", "common.notifier.dingtalk": "DingTalk", "common.notifier.email": "Email", diff --git a/ui/src/i18n/locales/en/nls.provider.json b/ui/src/i18n/locales/en/nls.provider.json index 5f9a97e1..e924b43a 100644 --- a/ui/src/i18n/locales/en/nls.provider.json +++ b/ui/src/i18n/locales/en/nls.provider.json @@ -12,6 +12,7 @@ "provider.aliyun.live": "Alibaba Cloud - ApsaraVideo Live", "provider.aliyun.nlb": "Alibaba Cloud - NLB (Network Load Balancer)", "provider.aliyun.oss": "Alibaba Cloud - OSS (Object Storage Service)", + "provider.aliyun.vod": "Alibaba Cloud - ApsaraVideo VOD (Video on Demand)", "provider.aliyun.waf": "Alibaba Cloud - WAF (Web Application Firewall)", "provider.akamai": "Akamai", "provider.akamai.cdn": "Akamai - CDN (Content Delivery Network)", @@ -22,25 +23,29 @@ "provider.azure.dns": "Azure - DNS", "provider.baiducloud": "Baidu Cloud", "provider.baiducloud.cdn": "Baidu Cloud - CDN (Content Delivery Network)", + "provider.baiducloud.dns": "Baidu Cloud - DNS (Domain Name Service)", "provider.baishan": "Baishan", "provider.baishan.cdn": "Baishan - CDN (Content Delivery Network)", "provider.baotapanel": "BaoTa Panel", + "provider.baotapanel.console": "BaoTa Panel - Console", "provider.baotapanel.site": "BaoTa Panel - Site", "provider.byteplus": "BytePlus", "provider.byteplus.cdn": "BytePlus - CDN (Content Delivery Network)", - "provider.cachefly": "Cachefly", + "provider.cachefly": "CacheFly", "provider.cdnfly": "Cdnfly", "provider.cloudflare": "Cloudflare", "provider.cloudns": "ClouDNS", "provider.cmcccloud": "China Mobile Cloud (ECloud)", "provider.ctcccloud": "China Telecom Cloud (State Cloud)", "provider.cucccloud": "China Unicom Cloud", + "provider.dnsla": "DNS.LA", "provider.dogecloud": "Doge Cloud", "provider.dogecloud.cdn": "Doge Cloud - CDN (Content Delivery Network)", "provider.edgio": "Edgio", "provider.edgio.applications": "Edgio - Applications", "provider.fastly": "Fastly", "provider.gcore": "Gcore", + "provider.gcore.cdn": "Gcore - CDN (Content Delivery Network)", "provider.gname": "GNAME", "provider.godaddy": "GoDaddy", "provider.goedge": "GoEdge", @@ -49,9 +54,17 @@ "provider.huaweicloud.cdn": "Huawei Cloud - CDN (Content Delivery Network)", "provider.huaweicloud.dns": "Huawei Cloud - DNS (Domain Name Service)", "provider.huaweicloud.elb": "Huawei Cloud - ELB (Elastic Load Balance)", + "provider.huaweicloud.waf": "Huawei Cloud - WAF (Web Application Firewall)", + "provider.jdcloud": "JD Cloud", + "provider.jdcloud.alb": "JD Cloud - ALB (Application Load Balancer)", + "provider.jdcloud.cdn": "JD Cloud - CDN (Content Delivery Network)", + "provider.jdcloud.dns": "JD Cloud - DNS", + "provider.jdcloud.live": "JD Cloud - Live Video", + "provider.jdcloud.vod": "JD Cloud - VOD (Video on Demand)", "provider.kubernetes": "Kubernetes", "provider.kubernetes.secret": "Kubernetes - Secret", "provider.local": "Local deployment", + "provider.namecheap": "Namecheap", "provider.namedotcom": "Name.com", "provider.namesilo": "NameSilo", "provider.ns1": "NS1 (IBM NS1 Connect)", @@ -71,6 +84,8 @@ "provider.tencentcloud.ecdn": "Tencent Cloud - ECDN (Enterprise Content Delivery Network)", "provider.tencentcloud.eo": "Tencent Cloud - EdgeOne", "provider.tencentcloud.ssl_deploy": "Tencent Cloud - via SSL Certificate Service Deployment Job", + "provider.tencentcloud.vod": "Tencent Cloud - VOD (Video on Demand)", + "provider.tencentcloud.waf": "Tencent Cloud - WAF (Web Application Firewall)", "provider.ucloud": "UCloud", "provider.ucloud.ucdn": "UCloud - UCDN (UCloud Content Delivery Network)", "provider.ucloud.us3": "UCloud - US3 (UCloud Object-based Storage)", @@ -79,6 +94,7 @@ "provider.volcengine.clb": "Volcengine - CLB (Cloud Load Balancer)", "provider.volcengine.dcdn": "Volcengine - DCDN (Dynamic Content Delivery Network)", "provider.volcengine.dns": "Volcengine - DNS (Domain Name Service)", + "provider.volcengine.imagex": "Volcengine - ImageX", "provider.volcengine.live": "Volcengine - Live", "provider.volcengine.tos": "Volcengine - TOS (Tinder Object Storage)", "provider.webhook": "Webhook", @@ -87,9 +103,9 @@ "provider.category.all": "All", "provider.category.cdn": "CDN", "provider.category.storage": "Storage", - "provider.category.loadbalance": "Load Balance", + "provider.category.loadbalance": "Loadbalance", "provider.category.firewall": "Firewall", - "provider.category.live": "Live", + "provider.category.av": "Audio/Video", "provider.category.website": "Website", "provider.category.other": "Other" } diff --git a/ui/src/i18n/locales/en/nls.workflow.nodes.json b/ui/src/i18n/locales/en/nls.workflow.nodes.json index a4b3a15e..ebf7cf3c 100644 --- a/ui/src/i18n/locales/en/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/en/nls.workflow.nodes.json @@ -46,6 +46,9 @@ "workflow_node.apply.form.huaweicloud_dns_region.label": "Huawei Cloud DNS region", "workflow_node.apply.form.huaweicloud_dns_region.placeholder": "Please enter Huawei Cloud DNS region (e.g. cn-north-1)", "workflow_node.apply.form.huaweicloud_dns_region.tooltip": "For more information, see https://console-intl.huaweicloud.com/apiexplorer/#/endpoint", + "workflow_node.apply.form.jdcloud_dns_region_id.label": "JD Cloud DNS region ID", + "workflow_node.apply.form.jdcloud_dns_region_id.placeholder": "Please enter JD Cloud DNS region ID (e.g. cn-north-1)", + "workflow_node.apply.form.jdcloud_dns_region_id.tooltip": "For more information, see https://docs.jdcloud.com/en/common-declaration/api/introduction", "workflow_node.apply.form.advanced_config.label": "Advanced settings", "workflow_node.apply.form.key_algorithm.label": "Certificate key algorithm", "workflow_node.apply.form.key_algorithm.placeholder": "Please select certificate key algorithm", @@ -175,6 +178,12 @@ "workflow_node.deploy.form.aliyun_oss_domain.label": "Alibaba Cloud OSS domain", "workflow_node.deploy.form.aliyun_oss_domain.placeholder": "Please enter Alibaba Cloud OSS domain name", "workflow_node.deploy.form.aliyun_oss_domain.tooltip": "For more information, see https://oss.console.aliyun.com", + "workflow_node.deploy.form.aliyun_vod_region.label": "Alibaba Cloud VOD region", + "workflow_node.deploy.form.aliyun_vod_region.placeholder": "Please enter Alibaba Cloud VOD region (e.g. cn-hangzhou)", + "workflow_node.deploy.form.aliyun_vod_region.tooltip": "For more information, see https://www.alibabacloud.com/help/en/vod/product-overview/regions", + "workflow_node.deploy.form.aliyun_vod_domain.label": "Alibaba Cloud VOD domain", + "workflow_node.deploy.form.aliyun_vod_domain.placeholder": "Please enter Alibaba Cloud VOD domain name", + "workflow_node.deploy.form.aliyun_vod_domain.tooltip": "For more information, see https://vod.console.aliyun.com", "workflow_node.deploy.form.aliyun_waf_region.label": "Alibaba Cloud WAF region", "workflow_node.deploy.form.aliyun_waf_region.placeholder": "Please enter Alibaba Cloud WAF region (e.g. cn-hangzhou)", "workflow_node.deploy.form.aliyun_waf_region.tooltip": "For more information, see https://www.alibabacloud.com/help/en/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-endpoint", @@ -190,18 +199,43 @@ "workflow_node.deploy.form.baiducloud_cdn_domain.label": "Baidu Cloud CDN domain", "workflow_node.deploy.form.baiducloud_cdn_domain.placeholder": "Please enter Baidu Cloud CDN domain name", "workflow_node.deploy.form.baiducloud_cdn_domain.tooltip": "For more information, see https://console.bce.baidu.com/cdn", + "workflow_node.deploy.form.baishan_cdn_domain.label": "Baishan CDN domain", + "workflow_node.deploy.form.baishan_cdn_domain.placeholder": "Please enter Baishan CDN domain name", + "workflow_node.deploy.form.baishan_cdn_domain.tooltip": "For more information, see https://cdnx.console.baishan.com", + "workflow_node.deploy.form.baotapanel_console_auto_restart.label": "Auto restart after deployment", + "workflow_node.deploy.form.baotapanel_site_type.label": "BaoTa Panel site type", + "workflow_node.deploy.form.baotapanel_site_type.placeholder": "Please select BaoTa Panel site type", + "workflow_node.deploy.form.baotapanel_site_type.option.php.label": "PHP sites", + "workflow_node.deploy.form.baotapanel_site_type.option.other.label": "Other sites", "workflow_node.deploy.form.baotapanel_site_name.label": "BaoTa Panel site name", "workflow_node.deploy.form.baotapanel_site_name.placeholder": "Please enter BaoTa Panel site name", "workflow_node.deploy.form.baotapanel_site_name.tooltip": "Usually equal to the website domain name.", + "workflow_node.deploy.form.baotapanel_site_names.label": "BaoTa Panel site names", + "workflow_node.deploy.form.baotapanel_site_names.placeholder": "Please enter BaoTa Panel site names (separated by semicolons)", + "workflow_node.deploy.form.baotapanel_site_names.errmsg.invalid": "Please enter a valid BaoTa Panel site name", + "workflow_node.deploy.form.baotapanel_site_names.tooltip": "Usually equal to the websites domain name.", + "workflow_node.deploy.form.baotapanel_site_names.multiple_input_modal.title": "Change BaoTa Panel site names", + "workflow_node.deploy.form.baotapanel_site_names.multiple_input_modal.placeholder": "Please enter BaoTa Panel site name", "workflow_node.deploy.form.byteplus_cdn_domain.label": "BytePlus CDN domain", "workflow_node.deploy.form.byteplus_cdn_domain.placeholder": "Please enter BytePlus CDN domain name", "workflow_node.deploy.form.byteplus_cdn_domain.tooltip": "For more information, see https://console.byteplus.com/cdn", + "workflow_node.deploy.form.cdnfly_resource_type.label": "Resource type", + "workflow_node.deploy.form.cdnfly_resource_type.placeholder": "Please select resource type", + "workflow_node.deploy.form.cdnfly_resource_type.option.site.label": "Site", + "workflow_node.deploy.form.cdnfly_resource_type.option.certificate.label": "Certificate", + "workflow_node.deploy.form.cdnfly_site_id.label": "Cdnfly site ID", + "workflow_node.deploy.form.cdnfly_site_id.placeholder": "Please enter Cdnfly site ID", + "workflow_node.deploy.form.cdnfly_certificate_id.label": "Cdnfly certificate ID", + "workflow_node.deploy.form.cdnfly_certificate_id.placeholder": "Please enter Cdnfly certificate ID", "workflow_node.deploy.form.dogecloud_cdn_domain.label": "Doge Cloud CDN domain", "workflow_node.deploy.form.dogecloud_cdn_domain.placeholder": "Please enter Doge Cloud CDN domain name", "workflow_node.deploy.form.dogecloud_cdn_domain.tooltip": "For more information, see https://console.dogecloud.com/", "workflow_node.deploy.form.edgio_applications_environment_id.label": "Edgio Applications environment ID", "workflow_node.deploy.form.edgio_applications_environment_id.placeholder": "Please enter Edgio Applications environment ID", "workflow_node.deploy.form.edgio_applications_environment_id.tooltip": "For more information, see https://edgio.app/", + "workflow_node.deploy.form.gcore_cdn_resource_id.label": "Gcore CDN resource ID", + "workflow_node.deploy.form.gcore_cdn_resource_id.placeholder": "Please enter Gcore CDN resource ID", + "workflow_node.deploy.form.gcore_cdn_resource_id.tooltip": "For more information, see https://cdn.gcore.com/resources/list", "workflow_node.deploy.form.huaweicloud_cdn_region.label": "Huawei Cloud CDN region", "workflow_node.deploy.form.huaweicloud_cdn_region.placeholder": "Please enter Huawei Cloud CDN region (e.g. cn-north-1)", "workflow_node.deploy.form.huaweicloud_cdn_region.tooltip": "For more information, see https://console-intl.huaweicloud.com/apiexplorer/#/endpoint", @@ -225,6 +259,45 @@ "workflow_node.deploy.form.huaweicloud_elb_listener_id.label": "Huawei Cloud ELB listener ID", "workflow_node.deploy.form.huaweicloud_elb_listener_id.placeholder": "Please enter Huawei Cloud ELB listener ID", "workflow_node.deploy.form.huaweicloud_elb_listener_id.tooltip": "For more information, see https://console-intl.huaweicloud.com/vpc/#/elb/list/grid", + "workflow_node.deploy.form.huaweicloud_waf_resource_type.label": "Resource type", + "workflow_node.deploy.form.huaweicloud_waf_resource_type.placeholder": "Please select resource type", + "workflow_node.deploy.form.huaweicloud_waf_resource_type.option.certificate.label": "WAF certificate", + "workflow_node.deploy.form.huaweicloud_waf_resource_type.option.cloudserver.label": "WAF cloud server", + "workflow_node.deploy.form.huaweicloud_waf_resource_type.option.premiumhost.label": "WAF premium host", + "workflow_node.deploy.form.huaweicloud_waf_region.label": "Huawei Cloud WAF region", + "workflow_node.deploy.form.huaweicloud_waf_region.placeholder": "Please enter Huawei Cloud WAF region (e.g. cn-north-1)", + "workflow_node.deploy.form.huaweicloud_waf_region.tooltip": "For more information, see https://console-intl.huaweicloud.com/apiexplorer/#/endpoint", + "workflow_node.deploy.form.huaweicloud_waf_certificate_id.label": "Huawei Cloud WAF certificate ID", + "workflow_node.deploy.form.huaweicloud_waf_certificate_id.placeholder": "Please enter Huawei Cloud WAF certificate ID", + "workflow_node.deploy.form.huaweicloud_waf_certificate_id.tooltip": "For more information, see https://console-intl.huaweicloud.com/console/#/waf/certificateManagement", + "workflow_node.deploy.form.huaweicloud_waf_domain.label": "Huawei Cloud WAF domain", + "workflow_node.deploy.form.huaweicloud_waf_domain.placeholder": "Please enter Huawei Cloud WAF domain name", + "workflow_node.deploy.form.huaweicloud_waf_domain.tooltip": "For more information, see https://console-intl.huaweicloud.com/console/#/waf/domain/list", + "workflow_node.deploy.form.jdcloud_alb_resource_type.label": "Resource type", + "workflow_node.deploy.form.jdcloud_alb_resource_type.placeholder": "Please select resource type", + "workflow_node.deploy.form.jdcloud_alb_resource_type.option.loadbalancer.label": "ALB load balancer", + "workflow_node.deploy.form.jdcloud_alb_resource_type.option.listener.label": "ALB listener", + "workflow_node.deploy.form.jdcloud_alb_region_id.label": "JD Cloud ALB region ID", + "workflow_node.deploy.form.jdcloud_alb_region_id.placeholder": "Please enter JD Cloud ALB region ID (e.g. cn-north-1)", + "workflow_node.deploy.form.jdcloud_alb_region_id.tooltip": "For more information, see https://docs.jdcloud.com/en/common-declaration/api/introduction", + "workflow_node.deploy.form.jdcloud_alb_loadbalancer_id.label": "JD Cloud ALB load balancer ID", + "workflow_node.deploy.form.jdcloud_alb_loadbalancer_id.placeholder": "Please enter JD Cloud ALB load balancer ID", + "workflow_node.deploy.form.jdcloud_alb_loadbalancer_id.tooltip": "For more information, see https://cns-console.jdcloud.com/host/loadBalance/list", + "workflow_node.deploy.form.jdcloud_alb_listener_id.label": "JD Cloud ALB listener ID", + "workflow_node.deploy.form.jdcloud_alb_listener_id.placeholder": "Please enter JD Cloud ALB listener ID", + "workflow_node.deploy.form.jdcloud_alb_listener_id.tooltip": "For more information, see https://cns-console.jdcloud.com/host/loadBalance/list", + "workflow_node.deploy.form.jdcloud_alb_snidomain.label": "JD Cloud ALB SNI domain (Optional)", + "workflow_node.deploy.form.jdcloud_alb_snidomain.placeholder": "Please enter JD Cloud ALB SNI domain name", + "workflow_node.deploy.form.jdcloud_alb_snidomain.tooltip": "For more information, see https://cns-console.jdcloud.com/host/loadBalance/list", + "workflow_node.deploy.form.jdcloud_cdn_domain.label": "JD Cloud CDN domain", + "workflow_node.deploy.form.jdcloud_cdn_domain.placeholder": "Please enter JD Cloud CDN domain name", + "workflow_node.deploy.form.jdcloud_cdn_domain.tooltip": "For more information, see https://cdn-console.jdcloud.com/", + "workflow_node.deploy.form.jdcloud_live_domain.label": "JD Cloud Live Video play domain", + "workflow_node.deploy.form.jdcloud_live_domain.placeholder": "Please enter JD Cloud Live Video play domain name", + "workflow_node.deploy.form.jdcloud_live_domain.tooltip": "For more information, see https://live-console.jdcloud.com/", + "workflow_node.deploy.form.jdcloud_vod_domain.label": "JD Cloud VOD domain", + "workflow_node.deploy.form.jdcloud_vod_domain.placeholder": "Please enter JD Cloud VOD domain name", + "workflow_node.deploy.form.jdcloud_vod_domain.tooltip": "For more information, see https://vod-console.jdcloud.com/", "workflow_node.deploy.form.k8s_namespace.label": "Kubernetes Namespace", "workflow_node.deploy.form.k8s_namespace.placeholder": "Please enter Kubernetes Namespace", "workflow_node.deploy.form.k8s_namespace.tooltip": "For more information, see https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/", @@ -285,6 +358,11 @@ "workflow_node.deploy.form.qiniu_pili_domain.label": "Qiniu Pili streaming domain", "workflow_node.deploy.form.qiniu_pili_domain.placeholder": "Please enter Qiniu Pili streaming domain name", "workflow_node.deploy.form.qiniu_pili_domain.tooltip": "For more information, see https://portal.qiniu.com/hub", + "workflow_node.deploy.form.safeline_resource_type.label": "Resource type", + "workflow_node.deploy.form.safeline_resource_type.placeholder": "Please select resource type", + "workflow_node.deploy.form.safeline_resource_type.option.certificate.label": "Certificate", + "workflow_node.deploy.form.safeline_certificate_id.label": "SafeLine certificate ID", + "workflow_node.deploy.form.safeline_certificate_id.placeholder": "Please enter SafeLine certificate ID", "workflow_node.deploy.form.ssh_format.label": "File format", "workflow_node.deploy.form.ssh_format.placeholder": "Please select file format", "workflow_node.deploy.form.ssh_format.option.pem.label": "PEM (*.pem, *.crt, *.key)", @@ -351,9 +429,9 @@ "workflow_node.deploy.form.tencentcloud_cos_domain.label": "Tencent Cloud COS domain", "workflow_node.deploy.form.tencentcloud_cos_domain.placeholder": "Please enter Tencent Cloud COS domain name", "workflow_node.deploy.form.tencentcloud_cos_domain.tooltip": "For more information, see https://console.tencentcloud.com/cos", - "workflow_node.deploy.form.tencentcloud_css_domain.label": "Tencent Cloud CSS playing domain", - "workflow_node.deploy.form.tencentcloud_css_domain.placeholder": "Please enter Tencent Cloud CSS playing domain name", - "workflow_node.deploy.form.tencentcloud_css_domain.tooltip": "For more information, see https://console.cloud.tencent.com/live/livestat", + "workflow_node.deploy.form.tencentcloud_css_domain.label": "Tencent Cloud CSS play domain", + "workflow_node.deploy.form.tencentcloud_css_domain.placeholder": "Please enter Tencent Cloud CSS play domain name", + "workflow_node.deploy.form.tencentcloud_css_domain.tooltip": "For more information, see https://console.cloud.tencent.com/live", "workflow_node.deploy.form.tencentcloud_ecdn_domain.label": "Tencent Cloud ECDN domain", "workflow_node.deploy.form.tencentcloud_ecdn_domain.placeholder": "Please enter Tencent Cloud ECDN domain name", "workflow_node.deploy.form.tencentcloud_ecdn_domain.tooltip": "For more information, see https://console.tencentcloud.com/cdn", @@ -373,6 +451,24 @@ "workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_ids.tooltip": "For more information, see https://cloud.tencent.com.cn/document/product/400/91667", "workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_ids.multiple_input_modal.title": "Change Tencent Cloud resource IDs", "workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_ids.multiple_input_modal.placeholder": "Please enter Tencent Cloud resouce ID", + "workflow_node.deploy.form.tencentcloud_vod_sub_app_id.label": "Tencent Cloud VOD App ID", + "workflow_node.deploy.form.tencentcloud_vod_sub_app_id.placeholder": "Please enter Tencent Cloud VOD App ID", + "workflow_node.deploy.form.tencentcloud_vod_sub_app_id.tooltip": "For more information, see https://console.cloud.tencent.com/vod", + "workflow_node.deploy.form.tencentcloud_vod_domain.label": "Tencent Cloud VOD domain", + "workflow_node.deploy.form.tencentcloud_vod_domain.placeholder": "Please enter Tencent Cloud VOD domain name", + "workflow_node.deploy.form.tencentcloud_vod_domain.tooltip": "For more information, see https://console.cloud.tencent.com/vod", + "workflow_node.deploy.form.tencentcloud_waf_region.label": "Tencent Cloud WAF region", + "workflow_node.deploy.form.tencentcloud_waf_region.placeholder": "Please enter Tencent Cloud WAF region (e.g. ap-guangzhou)", + "workflow_node.deploy.form.tencentcloud_waf_region.tooltip": "For more information, see https://www.tencentcloud.com/document/product/627/38085", + "workflow_node.deploy.form.tencentcloud_waf_domain.label": "Tencent Cloud WAF domain", + "workflow_node.deploy.form.tencentcloud_waf_domain.placeholder": "Please enter Tencent Cloud WAF domain name", + "workflow_node.deploy.form.tencentcloud_waf_domain.tooltip": "For more information, see https://console.tencentcloud.com/waf", + "workflow_node.deploy.form.tencentcloud_waf_domain_id.label": "Tencent Cloud WAF domain ID", + "workflow_node.deploy.form.tencentcloud_waf_domain_id.placeholder": "Please enter Tencent Cloud WAF domain ID", + "workflow_node.deploy.form.tencentcloud_waf_domain_id.tooltip": "For more information, see https://console.tencentcloud.com/waf", + "workflow_node.deploy.form.tencentcloud_waf_instance_id.label": "Tencent Cloud WAF instance ID", + "workflow_node.deploy.form.tencentcloud_waf_instance_id.placeholder": "Please enter Tencent Cloud WAF instance ID", + "workflow_node.deploy.form.tencentcloud_waf_instance_id.tooltip": "For more information, see https://console.tencentcloud.com/waf", "workflow_node.deploy.form.ucloud_ucdn_domain_id.label": "UCloud UCDN domain ID", "workflow_node.deploy.form.ucloud_ucdn_domain_id.placeholder": "Please enter UCloud UCDN domain ID", "workflow_node.deploy.form.ucloud_ucdn_domain_id.tooltip": "For more information, see https://console.ucloud-global.com/ucdn", @@ -400,6 +496,15 @@ "workflow_node.deploy.form.volcengine_dcdn_domain.label": "VolcEngine DCDN domain", "workflow_node.deploy.form.volcengine_dcdn_domain.placeholder": "Please enter VolcEngine DCDN domain name", "workflow_node.deploy.form.volcengine_dcdn_domain.tooltip": "For more information, see https://console.volcengine.com/dcdn/dashboard", + "workflow_node.deploy.form.volcengine_imagex_region.label": "VolcEngine ImageX region", + "workflow_node.deploy.form.volcengine_imagex_region.placeholder": "Please enter VolcEngine ImageX region (e.g. cn-north-1)", + "workflow_node.deploy.form.volcengine_imagex_region.tooltip": "For more information, see https://www.volcengine.com/docs/508/23757", + "workflow_node.deploy.form.volcengine_imagex_service_id.label": "VolcEngine ImageX service ID", + "workflow_node.deploy.form.volcengine_imagex_service_id.placeholder": "Please enter VolcEngine ImageX service ID", + "workflow_node.deploy.form.volcengine_imagex_service_id.tooltip": "For more information, see https://console.volcengine.com/imagex", + "workflow_node.deploy.form.volcengine_imagex_domain.label": "VolcEngine ImageX domain", + "workflow_node.deploy.form.volcengine_imagex_domain.placeholder": "Please enter VolcEngine ImageX domain name", + "workflow_node.deploy.form.volcengine_imagex_domain.tooltip": "For more information, see https://console.volcengine.com/imagex", "workflow_node.deploy.form.volcengine_live_domain.label": "VolcEngine Live streaming domain", "workflow_node.deploy.form.volcengine_live_domain.placeholder": "Please enter VolcEngine Live streaming domain name", "workflow_node.deploy.form.volcengine_live_domain.tooltip": "For more information, see https://console.volcengine.com/live", diff --git a/ui/src/i18n/locales/zh/nls.access.json b/ui/src/i18n/locales/zh/nls.access.json index 37ebb112..64b034d5 100644 --- a/ui/src/i18n/locales/zh/nls.access.json +++ b/ui/src/i18n/locales/zh/nls.access.json @@ -38,8 +38,8 @@ "access.form.aliyun_access_key_id.label": "阿里云 AccessKeyId", "access.form.aliyun_access_key_id.placeholder": "请输入阿里云 AccessKeyId", "access.form.aliyun_access_key_id.tooltip": "这是什么?请参阅 https://help.aliyun.com/zh/ram/user-guide/create-an-accesskey-pair", - "access.form.aliyun_access_key_secret.label": "阿里云 AccessKey Secret", - "access.form.aliyun_access_key_secret.placeholder": "请输入阿里云 AccessKey Secret", + "access.form.aliyun_access_key_secret.label": "阿里云 AccessKeySecret", + "access.form.aliyun_access_key_secret.placeholder": "请输入阿里云 AccessKeySecret", "access.form.aliyun_access_key_secret.tooltip": "这是什么?请参阅 https://help.aliyun.com/zh/ram/user-guide/create-an-accesskey-pair", "access.form.aws_access_key_id.label": "AWS AccessKeyId", "access.form.aws_access_key_id.placeholder": "请输入 AWS AccessKeyId", @@ -65,6 +65,8 @@ "access.form.baiducloud_secret_access_key.label": "百度智能云 SecretAccessKey", "access.form.baiducloud_secret_access_key.placeholder": "请输入百度智能云 SecretAccessKey", "access.form.baiducloud_secret_access_key.tooltip": "这是什么?请参阅 https://cloud.baidu.com/doc/Reference/s/jjwvz2e3p", + "access.form.baishan_api_token.label": "白山云 API Token", + "access.form.baishan_api_token.placeholder": "请输入白山云 API Token", "access.form.baotapanel_api_url.label": "宝塔面板 URL", "access.form.baotapanel_api_url.placeholder": "请输入宝塔面板 URL", "access.form.baotapanel_api_url.tooltip": "这是什么?请参阅 https://www.bt.cn/bbs/thread-20376-1-1.html", @@ -77,6 +79,18 @@ "access.form.byteplus_secret_key.label": "BytePlus SecretKey", "access.form.byteplus_secret_key.placeholder": "请输入 BytePlus SecretKey", "access.form.byteplus_secret_key.tooltip": "这是什么?请参阅 https://docs.byteplus.com/zh-CN/docs/byteplus-platform/docs-managing-keys", + "access.form.cachefly_api_token.label": "CacheFly API Token", + "access.form.cachefly_api_token.placeholder": "请输入 CacheFly API Token", + "access.form.cachefly_api_token.tooltip": "这是什么?请参阅 https://kb.cachefly.com/kb/guide/en/generating-tokens-and-keys-Oll9Irt5TI/Steps/2460228", + "access.form.cdnfly_api_url.label": "Cdnfly API URL", + "access.form.cdnfly_api_url.placeholder": "请输入 Cdnfly API URL", + "access.form.cdnfly_api_url.tooltip": "这是什么?请参阅 https://doc.cdnfly.cn/anzhuangshuoming.html", + "access.form.cdnfly_api_key.label": "Cdnfly 用户端 API Key", + "access.form.cdnfly_api_key.placeholder": "请输入 Cdnfly 用户端 API Key", + "access.form.cdnfly_api_key.tooltip": "这是什么?请参阅 https://doc.cdnfly.cn/shiyongjieshao.html", + "access.form.cdnfly_api_secret.label": "Cdnfly 用户端 API Secret", + "access.form.cdnfly_api_secret.placeholder": "请输入 Cdnfly 用户端 API Secret", + "access.form.cdnfly_api_secret.tooltip": "这是什么?请参阅 https://doc.cdnfly.cn/shiyongjieshao.html", "access.form.cloudflare_dns_api_token.label": "Cloudflare API Token", "access.form.cloudflare_dns_api_token.placeholder": "请输入 Cloudflare API Token", "access.form.cloudflare_dns_api_token.tooltip": "这是什么?请参阅 https://developers.cloudflare.com/fundamentals/api/get-started/create-token/", @@ -86,6 +100,18 @@ "access.form.cloudns_auth_password.label": "ClouDNS API 用户密码", "access.form.cloudns_auth_password.placeholder": "请输入 ClouDNS API 用户密码", "access.form.cloudns_auth_password.tooltip": "这是什么?请参阅 https://www.cloudns.net/wiki/article/42/", + "access.form.cmcccloud_access_key_id.label": "移动云 AccessKeyId", + "access.form.cmcccloud_access_key_id.placeholder": "请输入移动云 AccessKeyId", + "access.form.cmcccloud_access_key_id.tooltip": "这是什么?请参阅 https://ecloud.10086.cn/op-help-center/doc/article/49739", + "access.form.cmcccloud_access_key_secret.label": "移动云 AccessKeySecret", + "access.form.cmcccloud_access_key_secret.placeholder": "请输入移动云 AccessKeySecret", + "access.form.cmcccloud_access_key_secret.tooltip": "这是什么?请参阅 https://ecloud.10086.cn/op-help-center/doc/article/49739", + "access.form.dnsla_api_id.label": "DNS.LA API ID", + "access.form.dnsla_api_id.placeholder": "请输入 DNS.LA API ID", + "access.form.dnsla_api_id.tooltip": "这是什么?请参阅 https://www.dns.la/docs/ApiDoc", + "access.form.dnsla_api_secret.label": "DNS.LA API 密钥", + "access.form.dnsla_api_secret.placeholder": "请输入 DNS.LA API 密钥", + "access.form.dnsla_api_secret.tooltip": "这是什么?请参阅 https://www.dns.la/docs/ApiDoc", "access.form.dogecloud_access_key.label": "多吉云 AccessKey", "access.form.dogecloud_access_key.placeholder": "请输入多吉云 AccessKey", "access.form.dogecloud_access_key.tooltip": "这是什么?请参阅 https://console.dogecloud.com/", @@ -98,6 +124,9 @@ "access.form.edgio_client_secret.label": "Edgio 客户端密码", "access.form.edgio_client_secret.placeholder": "请输入 Edgio 客户端密码", "access.form.edgio_client_secret.tooltip": "这是什么?请参阅 https://docs.edg.io/applications/v7/rest_api/authentication#administering-api-clients", + "access.form.gcore_api_token.label": "Gcore API Token", + "access.form.gcore_api_token.placeholder": "请输入 Gcore API Token", + "access.form.gcore_api_token.tooltip": "这是什么?请参阅 https://api.gcore.com/docs/iam#section/Authentication", "access.form.gname_app_id.label": "GNAME AppId", "access.form.gname_app_id.placeholder": "请输入 GNAME AppId", "access.form.gname_app_id.tooltip": "这是什么?请参阅 https://www.gname.com/user#/dealer_api", @@ -116,10 +145,22 @@ "access.form.huaweicloud_secret_access_key.label": "华为云 SecretAccessKey", "access.form.huaweicloud_secret_access_key.placeholder": "请输入华为云 SecretAccessKey", "access.form.huaweicloud_secret_access_key.tooltip": "这是什么?请参阅 https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html", + "access.form.jdcloud_access_key_id.label": "京东云 AccessKeyId", + "access.form.jdcloud_access_key_id.placeholder": "请输入京东云 AccessKeyId", + "access.form.jdcloud_access_key_id.tooltip": "这是什么?请参阅 https://docs.jdcloud.com/cn/account-management/accesskey-management", + "access.form.jdcloud_access_key_secret.label": "京东云 AccessKeySecret", + "access.form.jdcloud_access_key_secret.placeholder": "请输入京东云 AccessKeySecret", + "access.form.jdcloud_access_key_secret.tooltip": "这是什么?请参阅 https://docs.jdcloud.com/cn/account-management/accesskey-management", "access.form.k8s_kubeconfig.label": "KubeConfig", "access.form.k8s_kubeconfig.placeholder": "请选择 KubeConfig 文件", "access.form.k8s_kubeconfig.upload": "选择文件", "access.form.k8s_kubeconfig.tooltip": "这是什么?请参阅 https://kubernetes.io/zh-cn/docs/concepts/configuration/organize-cluster-access-kubeconfig/

为空时,将使用 Pod 的 ServiceAccount 作为凭证。", + "access.form.namecheap_username.label": "Namecheap 用户名", + "access.form.namecheap_username.placeholder": "请输入 Namecheap 用户名", + "access.form.namecheap_username.tooltip": "这是什么?请参阅 https://www.namecheap.com/support/api/intro/", + "access.form.namecheap_api_key.label": "Namecheap API Key", + "access.form.namecheap_api_key.placeholder": "请输入 Namecheap API Key", + "access.form.namecheap_api_key.tooltip": "这是什么?请参阅 https://www.namecheap.com/support/api/intro/", "access.form.namedotcom_username.label": "Name.com 用户名", "access.form.namedotcom_username.placeholder": "请输入 Name.com 用户名", "access.form.namedotcom_username.tooltip": "这是什么?请参阅 https://www.name.com/account/settings/api", @@ -147,6 +188,12 @@ "access.form.rainyun_api_key.label": "雨云 API 密钥", "access.form.rainyun_api_key.placeholder": "请输入雨云 API 密钥", "access.form.rainyun_api_key.tooltip": "这是什么?请参阅 https://www.rainyun.com/docs/account/racc/setting", + "access.form.safeline_api_url.label": "雷池 URL", + "access.form.safeline_api_url.placeholder": "请输入雷池 URL", + "access.form.safeline_api_url.tooltip": "这是什么?请参阅 https://docs.waf-ce.chaitin.cn/zh/上手指南/安装雷池", + "access.form.safeline_api_token.label": "雷池 API Token", + "access.form.safeline_api_token.placeholder": "请输入雷池 API Token", + "access.form.safeline_api_token.tooltip": "这是什么?请参阅 https://docs.waf-ce.chaitin.cn/zh/更多技术文档/OPENAPI", "access.form.ssh_host.label": "服务器地址", "access.form.ssh_host.placeholder": "请输入服务器地址", "access.form.ssh_port.label": "服务器端口", diff --git a/ui/src/i18n/locales/zh/nls.provider.json b/ui/src/i18n/locales/zh/nls.provider.json index a4146670..f8d36830 100644 --- a/ui/src/i18n/locales/zh/nls.provider.json +++ b/ui/src/i18n/locales/zh/nls.provider.json @@ -12,6 +12,7 @@ "provider.aliyun.live": "阿里云 - 视频直播 Live", "provider.aliyun.nlb": "阿里云 - 网络型负载均衡 NLB", "provider.aliyun.oss": "阿里云 - 对象存储 OSS", + "provider.aliyun.vod": "阿里云 - 视频点播 VOD", "provider.aliyun.waf": "阿里云 - Web 应用防火墙 WAF", "provider.akamai": "Akamai", "provider.akamai.cdn": "Akamai - 内容分发网络 CDN", @@ -22,25 +23,29 @@ "provider.azure.dns": "Azure - DNS", "provider.baiducloud": "百度智能云", "provider.baiducloud.cdn": "百度智能云 - 内容分发网络 CDN", + "provider.baiducloud.dns": "百度智能云 - 智能云解析 DNS", "provider.baishan": "白山云", "provider.baishan.cdn": "白山云 - 内容分发网络 CDN", "provider.baotapanel": "宝塔面板", + "provider.baotapanel.console": "宝塔面板 - 面板", "provider.baotapanel.site": "宝塔面板 - 网站", "provider.byteplus": "BytePlus", "provider.byteplus.cdn": "BytePlus - 内容分发网络 CDN", - "provider.cachefly": "Cachefly", + "provider.cachefly": "CacheFly", "provider.cdnfly": "Cdnfly", "provider.cloudflare": "Cloudflare", "provider.cloudns": "ClouDNS", "provider.cmcccloud": "移动云", "provider.ctcccloud": "联通云", "provider.cucccloud": "天翼云", + "provider.dnsla": "DNS.LA", "provider.dogecloud": "多吉云", "provider.dogecloud.cdn": "多吉云 - 内容分发网络 CDN", "provider.edgio": "Edgio", "provider.edgio.applications": "Edgio - Applications", "provider.fastly": "Fastly", "provider.gcore": "Gcore", + "provider.gcore.cdn": "Gcore - 内容分发网络 CDN", "provider.gname": "GNAME", "provider.godaddy": "GoDaddy", "provider.goedge": "GoEdge", @@ -49,9 +54,17 @@ "provider.huaweicloud.cdn": "华为云 - 内容分发网络 CDN", "provider.huaweicloud.dns": "华为云 - 云解析 DNS", "provider.huaweicloud.elb": "华为云 - 弹性负载均衡 ELB", + "provider.huaweicloud.waf": "华为云 - Web 应用防火墙 WAF", + "provider.jdcloud": "京东云", + "provider.jdcloud.alb": "京东云 - 应用负载均衡 ALB", + "provider.jdcloud.cdn": "京东云 - 内容分发网络 CDN", + "provider.jdcloud.dns": "京东云 - 云解析 DNS", + "provider.jdcloud.live": "京东云 - 视频直播", + "provider.jdcloud.vod": "京东云 - 视频点播", "provider.kubernetes": "Kubernetes", "provider.kubernetes.secret": "Kubernetes - Secret", "provider.local": "本地部署", + "provider.namecheap": "Namecheap", "provider.namedotcom": "Name.com", "provider.namesilo": "NameSilo", "provider.ns1": "NS1(IBM NS1 Connect)", @@ -71,6 +84,8 @@ "provider.tencentcloud.ecdn": "腾讯云 - 全站加速网络 ECDN", "provider.tencentcloud.eo": "腾讯云 - 边缘安全加速平台 EdgeOne", "provider.tencentcloud.ssl_deploy": "腾讯云 - 通过 SSL 证书服务创建部署任务", + "provider.tencentcloud.vod": "腾讯云 - 云点播 VOD", + "provider.tencentcloud.waf": "腾讯云 - Web 应用防火墙 WAF", "provider.ucloud": "优刻得", "provider.ucloud.ucdn": "优刻得 - 内容分发 UCDN", "provider.ucloud.us3": "优刻得 - 对象存储 US3", @@ -79,6 +94,7 @@ "provider.volcengine.clb": "火山引擎 - 负载均衡 CLB", "provider.volcengine.dcdn": "火山引擎 - 全站加速 DCDN", "provider.volcengine.dns": "火山引擎 - 云解析 DNS", + "provider.volcengine.imagex": "火山引擎 - 图片服务 ImageX", "provider.volcengine.live": "火山引擎 - 视频直播 Live", "provider.volcengine.tos": "火山引擎 - 对象存储 TOS", "provider.webhook": "Webhook", @@ -86,10 +102,10 @@ "provider.category.all": "全部", "provider.category.cdn": "CDN", - "provider.category.storage": "存储", + "provider.category.storage": "文件存储", "provider.category.loadbalance": "负载均衡", "provider.category.firewall": "防火墙", - "provider.category.live": "直播", + "provider.category.av": "音视频", "provider.category.website": "网站", "provider.category.other": "其他" } diff --git a/ui/src/i18n/locales/zh/nls.workflow.nodes.json b/ui/src/i18n/locales/zh/nls.workflow.nodes.json index 705d8056..a4c0998b 100644 --- a/ui/src/i18n/locales/zh/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/zh/nls.workflow.nodes.json @@ -46,6 +46,9 @@ "workflow_node.apply.form.huaweicloud_dns_region.label": "华为云 DNS 服务区域", "workflow_node.apply.form.huaweicloud_dns_region.placeholder": "请输入华为云 DNS 服务区域(例如:cn-north-1)", "workflow_node.apply.form.huaweicloud_dns_region.tooltip": "这是什么?请参阅 https://console.huaweicloud.com/apiexplorer/#/endpoint", + "workflow_node.apply.form.jdcloud_dns_region_id.label": "京东云 DNS 服务地域 ID", + "workflow_node.apply.form.jdcloud_dns_region_id.placeholder": "请输入京东云 DNS 服务地域 ID(例如:cn-north-1)", + "workflow_node.apply.form.jdcloud_dns_region_id.tooltip": "这是什么?请参阅 https://docs.jdcloud.com/cn/common-declaration/api/introduction", "workflow_node.apply.form.advanced_config.label": "高级设置", "workflow_node.apply.form.key_algorithm.label": "数字证书算法", "workflow_node.apply.form.key_algorithm.placeholder": "请选择数字证书算法", @@ -101,7 +104,7 @@ "workflow_node.deploy.form.aliyun_alb_listener_id.placeholder": "请输入阿里云 ALB 监听器 ID", "workflow_node.deploy.form.aliyun_alb_listener_id.tooltip": "这是什么?请参阅 https://slb.console.aliyun.com/alb", "workflow_node.deploy.form.aliyun_alb_snidomain.label": "阿里云 ALB 扩展域名(可选)", - "workflow_node.deploy.form.aliyun_alb_snidomain.placeholder": "请输入阿里云 ALB 扩展域名", + "workflow_node.deploy.form.aliyun_alb_snidomain.placeholder": "请输入阿里云 ALB 扩展域名(支持泛域名)", "workflow_node.deploy.form.aliyun_alb_snidomain.tooltip": "这是什么?请参阅 https://slb.console.aliyun.com/alb

不填写时,将替换监听器的默认证书。", "workflow_node.deploy.form.aliyun_cas_deploy.guide": "小贴士:由于阿里云证书部署任务是异步的,此节点若执行成功仅代表已创建部署任务,实际部署结果需要你自行前往阿里云控制台查询。", "workflow_node.deploy.form.aliyun_cas_deploy_region.label": "阿里云 CAS 服务地域", @@ -133,14 +136,14 @@ "workflow_node.deploy.form.aliyun_clb_listener_port.placeholder": "请输入阿里云 CLB 监听端口", "workflow_node.deploy.form.aliyun_clb_listener_port.tooltip": "这是什么?请参阅 https://slb.console.aliyun.com/clb", "workflow_node.deploy.form.aliyun_clb_snidomain.label": "阿里云 CLB 扩展域名(可选)", - "workflow_node.deploy.form.aliyun_clb_snidomain.placeholder": "请输入阿里云 CLB 扩展域名", + "workflow_node.deploy.form.aliyun_clb_snidomain.placeholder": "请输入阿里云 CLB 扩展域名(支持泛域名)", "workflow_node.deploy.form.aliyun_clb_snidomain.tooltip": "这是什么?请参阅 https://slb.console.aliyun.com/clb

不填写时,将替换监听器的默认证书。", - "workflow_node.deploy.form.aliyun_cdn_domain.label": "阿里云 CDN 加速域名(支持泛域名)", - "workflow_node.deploy.form.aliyun_cdn_domain.placeholder": "请输入阿里云 CDN 加速域名", - "workflow_node.deploy.form.aliyun_cdn_domain.tooltip": "这是什么?请参阅 https://cdn.console.aliyun.com

泛域名表示形式为:*.example.com", - "workflow_node.deploy.form.aliyun_dcdn_domain.label": "阿里云 DCDN 加速域名(支持泛域名)", - "workflow_node.deploy.form.aliyun_dcdn_domain.placeholder": "请输入阿里云 DCDN 加速域名", - "workflow_node.deploy.form.aliyun_dcdn_domain.tooltip": "这是什么?请参阅 https://dcdn.console.aliyun.com

泛域名表示形式为:*.example.com", + "workflow_node.deploy.form.aliyun_cdn_domain.label": "阿里云 CDN 加速域名", + "workflow_node.deploy.form.aliyun_cdn_domain.placeholder": "请输入阿里云 CDN 加速域名(支持泛域名)", + "workflow_node.deploy.form.aliyun_cdn_domain.tooltip": "这是什么?请参阅 https://cdn.console.aliyun.com", + "workflow_node.deploy.form.aliyun_dcdn_domain.label": "阿里云 DCDN 加速域名", + "workflow_node.deploy.form.aliyun_dcdn_domain.placeholder": "请输入阿里云 DCDN 加速域名(支持泛域名)", + "workflow_node.deploy.form.aliyun_dcdn_domain.tooltip": "这是什么?请参阅 https://dcdn.console.aliyun.com", "workflow_node.deploy.form.aliyun_esa_region.label": "阿里云 ESA 服务地域", "workflow_node.deploy.form.aliyun_esa_region.placeholder": "请输入阿里云 ESA 服务地域(例如:cn-hangzhou)", "workflow_node.deploy.form.aliyun_esa_region.tooltip": "这是什么?请参阅 https://help.aliyun.com/zh/edge-security-acceleration/esa/api-esa-2024-09-10-endpoint", @@ -150,8 +153,8 @@ "workflow_node.deploy.form.aliyun_live_region.label": "阿里云视频直播服务地域", "workflow_node.deploy.form.aliyun_live_region.placeholder": "请输入阿里云视频直播服务地域(例如:cn-hangzhou)", "workflow_node.deploy.form.aliyun_live_region.tooltip": "这是什么?请参阅 https://help.aliyun.com/zh/live/product-overview/supported-regions", - "workflow_node.deploy.form.aliyun_live_domain.label": "阿里云视频直播流域名(支持泛域名)", - "workflow_node.deploy.form.aliyun_live_domain.placeholder": "请输入阿里云视频直播流域名", + "workflow_node.deploy.form.aliyun_live_domain.label": "阿里云视频直播流域名", + "workflow_node.deploy.form.aliyun_live_domain.placeholder": "请输入阿里云视频直播流域名(支持泛域名)", "workflow_node.deploy.form.aliyun_live_domain.tooltip": "这是什么?请参阅 https://live.console.aliyun.com", "workflow_node.deploy.form.aliyun_nlb_resource_type.label": "证书替换方式", "workflow_node.deploy.form.aliyun_nlb_resource_type.placeholder": "请选择证书替换方式", @@ -175,6 +178,12 @@ "workflow_node.deploy.form.aliyun_oss_domain.label": "阿里云 OSS 自定义域名", "workflow_node.deploy.form.aliyun_oss_domain.placeholder": "请输入阿里云 OSS 自定义域名", "workflow_node.deploy.form.aliyun_oss_domain.tooltip": "这是什么?请参阅 see https://oss.console.aliyun.com", + "workflow_node.deploy.form.aliyun_vod_region.label": "阿里云视频点播服务地域", + "workflow_node.deploy.form.aliyun_vod_region.placeholder": "请输入阿里云视频点播服务地域(例如:cn-hangzhou)", + "workflow_node.deploy.form.aliyun_vod_region.tooltip": "这是什么?请参阅 https://help.aliyun.com/zh/vod/product-overview/regions", + "workflow_node.deploy.form.aliyun_vod_domain.label": "阿里云视频点播加速域名", + "workflow_node.deploy.form.aliyun_vod_domain.placeholder": "请输入阿里云视频点播加速域名", + "workflow_node.deploy.form.aliyun_vod_domain.tooltip": "这是什么?请参阅 https://vod.console.aliyun.com", "workflow_node.deploy.form.aliyun_waf_region.label": "阿里云 WAF 服务地域", "workflow_node.deploy.form.aliyun_waf_region.placeholder": "请输入阿里云 WAF 服务地域(例如:cn-hangzhou)", "workflow_node.deploy.form.aliyun_waf_region.tooltip": "这是什么?请参阅 https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-endpoint", @@ -187,21 +196,46 @@ "workflow_node.deploy.form.aws_cloudfront_distribution_id.label": "AWS CloudFront 分配 ID", "workflow_node.deploy.form.aws_cloudfront_distribution_id.placeholder": "请输入 AWS CloudFront 分配 ID", "workflow_node.deploy.form.aws_cloudfront_distribution_id.tooltip": "这是什么?请参阅 https://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/distribution-working-with.html", - "workflow_node.deploy.form.baiducloud_cdn_domain.label": "百度智能云 CDN 加速域名(支持泛域名)", - "workflow_node.deploy.form.baiducloud_cdn_domain.placeholder": "请输入百度智能云 CDN 加速域名", - "workflow_node.deploy.form.baiducloud_cdn_domain.tooltip": "这是什么?请参阅 https://console.bce.baidu.com/cdn

泛域名表示形式为:*.example.com", + "workflow_node.deploy.form.baiducloud_cdn_domain.label": "百度智能云 CDN 加速域名", + "workflow_node.deploy.form.baiducloud_cdn_domain.placeholder": "请输入百度智能云 CDN 加速域名(支持泛域名)", + "workflow_node.deploy.form.baiducloud_cdn_domain.tooltip": "这是什么?请参阅 https://console.bce.baidu.com/cdn", + "workflow_node.deploy.form.baishan_cdn_domain.label": "白山云 CDN 加速域名", + "workflow_node.deploy.form.baishan_cdn_domain.placeholder": "请输入白山云 CDN 加速域名(支持泛域名)", + "workflow_node.deploy.form.baishan_cdn_domain.tooltip": "这是什么?请参阅 https://cdnx.console.baishan.com", + "workflow_node.deploy.form.baotapanel_console_auto_restart.label": "部署后自动重启面板服务", + "workflow_node.deploy.form.baotapanel_site_type.label": "宝塔面板网站类型", + "workflow_node.deploy.form.baotapanel_site_type.placeholder": "请选择宝塔面板网站类型", + "workflow_node.deploy.form.baotapanel_site_type.option.php.label": "PHP", + "workflow_node.deploy.form.baotapanel_site_type.option.other.label": "其他", "workflow_node.deploy.form.baotapanel_site_name.label": "宝塔面板网站名称", "workflow_node.deploy.form.baotapanel_site_name.placeholder": "请输入宝塔面板网站名称", "workflow_node.deploy.form.baotapanel_site_name.tooltip": "通常为网站域名。", - "workflow_node.deploy.form.byteplus_cdn_domain.label": "BytePlus CDN 域名(支持泛域名)", - "workflow_node.deploy.form.byteplus_cdn_domain.placeholder": "请输入 BytePlus CDN 域名", - "workflow_node.deploy.form.byteplus_cdn_domain.tooltip": "这是什么?请参阅 https://console.byteplus.com/cdn

泛域名表示形式为:*.example.com", + "workflow_node.deploy.form.baotapanel_site_names.label": "宝塔面板网站名称", + "workflow_node.deploy.form.baotapanel_site_names.placeholder": "请输入宝塔面板网站名称(多个值请用半角分号隔开)", + "workflow_node.deploy.form.baotapanel_site_names.errmsg.invalid": "请输入正确的宝塔面板网站名称", + "workflow_node.deploy.form.baotapanel_site_names.tooltip": "通常为网站域名。", + "workflow_node.deploy.form.baotapanel_site_names.multiple_input_modal.title": "修改宝塔面板网站名称", + "workflow_node.deploy.form.baotapanel_site_names.multiple_input_modal.placeholder": "请输入宝塔面板网站名称", + "workflow_node.deploy.form.byteplus_cdn_domain.label": "BytePlus CDN 域名", + "workflow_node.deploy.form.byteplus_cdn_domain.placeholder": "请输入 BytePlus CDN 域名(支持泛域名)", + "workflow_node.deploy.form.byteplus_cdn_domain.tooltip": "这是什么?请参阅 https://console.byteplus.com/cdn", + "workflow_node.deploy.form.cdnfly_resource_type.label": "证书替换方式", + "workflow_node.deploy.form.cdnfly_resource_type.placeholder": "请选择证书替换方式", + "workflow_node.deploy.form.cdnfly_resource_type.option.site.label": "替换指定网站的证书", + "workflow_node.deploy.form.cdnfly_resource_type.option.certificate.label": "替换指定证书", + "workflow_node.deploy.form.cdnfly_site_id.label": "Cdnfly 网站 ID", + "workflow_node.deploy.form.cdnfly_site_id.placeholder": "请输入 Cdnfly 网站 ID", + "workflow_node.deploy.form.cdnfly_certificate_id.label": "Cdnfly 证书 ID", + "workflow_node.deploy.form.cdnfly_certificate_id.placeholder": "请输入 Cdnfly 证书 ID", "workflow_node.deploy.form.dogecloud_cdn_domain.label": "多吉云 CDN 加速域名", "workflow_node.deploy.form.dogecloud_cdn_domain.placeholder": "请输入多吉云 CDN 加速域名", "workflow_node.deploy.form.dogecloud_cdn_domain.tooltip": "这是什么?请参阅 https://console.dogecloud.com", "workflow_node.deploy.form.edgio_applications_environment_id.label": "Edgio Applications 环境 ID", "workflow_node.deploy.form.edgio_applications_environment_id.placeholder": "请输入 Edgio Applications 环境 ID", "workflow_node.deploy.form.edgio_applications_environment_id.tooltip": "这是什么?请参阅 https://edgio.app/", + "workflow_node.deploy.form.gcore_cdn_resource_id.label": "Gcore CDN 资源 ID", + "workflow_node.deploy.form.gcore_cdn_resource_id.placeholder": "请输入 Gcore CDN 资源 ID", + "workflow_node.deploy.form.gcore_cdn_resource_id.tooltip": "这是什么?请参阅 https://cdn.gcore.com/resources/list", "workflow_node.deploy.form.huaweicloud_cdn_region.label": "华为云 CDN 服务区域", "workflow_node.deploy.form.huaweicloud_cdn_region.placeholder": "请输入华为云 CDN 服务区域(例如:cn-north-1)", "workflow_node.deploy.form.huaweicloud_cdn_region.tooltip": "这是什么?请参阅 https://console.huaweicloud.com/apiexplorer/#/endpoint", @@ -225,6 +259,45 @@ "workflow_node.deploy.form.huaweicloud_elb_listener_id.label": "华为云 ELB 监听器 ID", "workflow_node.deploy.form.huaweicloud_elb_listener_id.placeholder": "请输入华为云 ELB 监听器 ID", "workflow_node.deploy.form.huaweicloud_elb_listener_id.tooltip": "这是什么?请参阅 https://console.huaweicloud.com/vpc/#/elb/list/grid", + "workflow_node.deploy.form.huaweicloud_waf_resource_type.label": "证书替换方式", + "workflow_node.deploy.form.huaweicloud_waf_resource_type.placeholder": "请选择证书替换方式", + "workflow_node.deploy.form.huaweicloud_waf_resource_type.option.certificate.label": "替换指定证书", + "workflow_node.deploy.form.huaweicloud_waf_resource_type.option.cloudserver.label": "替换指定云模式防护网站的证书", + "workflow_node.deploy.form.huaweicloud_waf_resource_type.option.premiumhost.label": "替换指定独享模式防护网站的证书", + "workflow_node.deploy.form.huaweicloud_waf_region.label": "华为云 WAF 服务区域", + "workflow_node.deploy.form.huaweicloud_waf_region.placeholder": "请输入华为云 WAF 服务区域(例如:cn-north-1)", + "workflow_node.deploy.form.huaweicloud_waf_region.tooltip": "这是什么?请参阅 https://console.huaweicloud.com/apiexplorer/#/endpoint", + "workflow_node.deploy.form.huaweicloud_waf_certificate_id.label": "华为云 WAF 证书 ID", + "workflow_node.deploy.form.huaweicloud_waf_certificate_id.placeholder": "请输入华为云 WAF 证书 ID", + "workflow_node.deploy.form.huaweicloud_waf_certificate_id.tooltip": "这是什么?请参阅 https://console.huaweicloud.com/console/#/waf/certificateManagement", + "workflow_node.deploy.form.huaweicloud_waf_domain.label": "华为云 WAF 防护域名", + "workflow_node.deploy.form.huaweicloud_waf_domain.placeholder": "请输入华为云 WAF 防护域名(支持泛域名)", + "workflow_node.deploy.form.huaweicloud_waf_domain.tooltip": "这是什么?请参阅 https://console.huaweicloud.com/console/#/waf/domain/list", + "workflow_node.deploy.form.jdcloud_alb_resource_type.label": "证书替换方式", + "workflow_node.deploy.form.jdcloud_alb_resource_type.placeholder": "请选择证书替换方式", + "workflow_node.deploy.form.jdcloud_alb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 HTTPS/TLS 监听的证书", + "workflow_node.deploy.form.jdcloud_alb_resource_type.option.listener.label": "替换指定负载均衡监听器的证书", + "workflow_node.deploy.form.jdcloud_alb_region_id.label": "京东云 ALB 服务地域 ID", + "workflow_node.deploy.form.jdcloud_alb_region_id.placeholder": "请输入京东云 ALB 服务地域 ID(例如:cn-north-1", + "workflow_node.deploy.form.jdcloud_alb_region_id.tooltip": "这是什么?请参阅 https://docs.jdcloud.com/cn/common-declaration/api/introduction", + "workflow_node.deploy.form.jdcloud_alb_loadbalancer_id.label": "京东云 ALB 负载均衡器 ID", + "workflow_node.deploy.form.jdcloud_alb_loadbalancer_id.placeholder": "请输入京东云 ALB 负载均衡器 ID", + "workflow_node.deploy.form.jdcloud_alb_loadbalancer_id.tooltip": "这是什么?请参阅 https://cns-console.jdcloud.com/host/loadBalance/list", + "workflow_node.deploy.form.jdcloud_alb_listener_id.label": "京东云 ALB 监听器 ID", + "workflow_node.deploy.form.jdcloud_alb_listener_id.placeholder": "请输入京东云 ALB 监听器 ID", + "workflow_node.deploy.form.jdcloud_alb_listener_id.tooltip": "这是什么?请参阅 https://cns-console.jdcloud.com/host/loadBalance/list", + "workflow_node.deploy.form.jdcloud_alb_snidomain.label": "京东云 ALB 扩展域名(可选)", + "workflow_node.deploy.form.jdcloud_alb_snidomain.placeholder": "请输入京东云 ALB 扩展域名(支持泛域名)", + "workflow_node.deploy.form.jdcloud_alb_snidomain.tooltip": "这是什么?请参阅 https://cns-console.jdcloud.com/host/loadBalance/list

不填写时,将替换监听器的默认证书。", + "workflow_node.deploy.form.jdcloud_cdn_domain.label": "京东云 CDN 加速域名", + "workflow_node.deploy.form.jdcloud_cdn_domain.placeholder": "请输入京东云 CDN 加速域名(支持泛域名)", + "workflow_node.deploy.form.jdcloud_cdn_domain.tooltip": "这是什么?请参阅 https://cdn-console.jdcloud.com/", + "workflow_node.deploy.form.jdcloud_live_domain.label": "京东云视频直播播放域名", + "workflow_node.deploy.form.jdcloud_live_domain.placeholder": "请输入京东云视频直播播放域名", + "workflow_node.deploy.form.jdcloud_live_domain.tooltip": "这是什么?请参阅 https://live-console.jdcloud.com", + "workflow_node.deploy.form.jdcloud_vod_domain.label": "京东云视频点播加速域名", + "workflow_node.deploy.form.jdcloud_vod_domain.placeholder": "请输入京东云视频点播加速域名", + "workflow_node.deploy.form.jdcloud_vod_domain.tooltip": "这是什么?请参阅 https://vod-console.jdcloud.com/", "workflow_node.deploy.form.k8s_namespace.label": "Kubernetes 命名空间", "workflow_node.deploy.form.k8s_namespace.placeholder": "请输入 Kubernetes 命名空间", "workflow_node.deploy.form.k8s_namespace.tooltip": "这是什么?请参阅 https://kubernetes.io/zh-cn/docs/concepts/overview/working-with-objects/namespaces/", @@ -276,15 +349,20 @@ "workflow_node.deploy.form.local_preset_scripts.option.reload_nginx.label": "POSIX Bash - 重启 nginx 进程", "workflow_node.deploy.form.local_preset_scripts.option.binding_iis.label": "PowerShell - 导入并绑定到 IIS(需管理员权限)", "workflow_node.deploy.form.local_preset_scripts.option.binding_netsh.label": "PowerShell - 导入并绑定到 netsh(需管理员权限)", - "workflow_node.deploy.form.qiniu_cdn_domain.label": "七牛云 CDN 加速域名(支持泛域名)", - "workflow_node.deploy.form.qiniu_cdn_domain.placeholder": "请输入七牛云 CDN 加速域名", - "workflow_node.deploy.form.qiniu_cdn_domain.tooltip": "这是什么?请参阅 https://portal.qiniu.com/cdn

泛域名表示形式为:*.example.com", + "workflow_node.deploy.form.qiniu_cdn_domain.label": "七牛云 CDN 加速域名", + "workflow_node.deploy.form.qiniu_cdn_domain.placeholder": "请输入七牛云 CDN 加速域名(支持泛域名)", + "workflow_node.deploy.form.qiniu_cdn_domain.tooltip": "这是什么?请参阅 https://portal.qiniu.com/cdn", "workflow_node.deploy.form.qiniu_pili_hub.label": "七牛云视频直播空间名", "workflow_node.deploy.form.qiniu_pili_hub.placeholder": "请输入七牛云视频直播空间名", "workflow_node.deploy.form.qiniu_pili_hub.tooltip": "这是什么?请参阅 https://portal.qiniu.com/hub", "workflow_node.deploy.form.qiniu_pili_domain.label": "七牛云视频直播流域名", "workflow_node.deploy.form.qiniu_pili_domain.placeholder": "请输入七牛云视频直播流域名", "workflow_node.deploy.form.qiniu_pili_domain.tooltip": "这是什么?请参阅 https://portal.qiniu.com/hub", + "workflow_node.deploy.form.safeline_resource_type.label": "证书替换方式", + "workflow_node.deploy.form.safeline_resource_type.placeholder": "请选择证书替换方式", + "workflow_node.deploy.form.safeline_resource_type.option.certificate.label": "替换指定证书", + "workflow_node.deploy.form.safeline_certificate_id.label": "雷池证书 ID", + "workflow_node.deploy.form.safeline_certificate_id.placeholder": "请输入雷池证书 ID", "workflow_node.deploy.form.ssh_format.label": "文件格式", "workflow_node.deploy.form.ssh_format.placeholder": "请选择文件格式", "workflow_node.deploy.form.ssh_format.option.pem.label": "PEM 格式(*.pem, *.crt, *.key)", @@ -318,9 +396,9 @@ "workflow_node.deploy.form.ssh_preset_scripts.option.reload_nginx.label": "POSIX Bash - 重启 nginx 进程", "workflow_node.deploy.form.ssh_use_scp.label": "回退使用 SCP", "workflow_node.deploy.form.ssh_use_scp.tooltip": "如果你的远程服务器不支持 SFTP,请开启此选项回退为 SCP。", - "workflow_node.deploy.form.tencentcloud_cdn_domain.label": "腾讯云 CDN 加速域名(支持泛域名)", - "workflow_node.deploy.form.tencentcloud_cdn_domain.placeholder": "请输入腾讯云 CDN 加速域名", - "workflow_node.deploy.form.tencentcloud_cdn_domain.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/cdn

泛域名表示形式为:*.example.com", + "workflow_node.deploy.form.tencentcloud_cdn_domain.label": "腾讯云 CDN 加速域名", + "workflow_node.deploy.form.tencentcloud_cdn_domain.placeholder": "请输入腾讯云 CDN 加速域名(支持泛域名)", + "workflow_node.deploy.form.tencentcloud_cdn_domain.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/cdn", "workflow_node.deploy.form.tencentcloud_clb_resource_type.label": "证书替换方式", "workflow_node.deploy.form.tencentcloud_clb_resource_type.placeholder": "请选择证书替换方式", "workflow_node.deploy.form.tencentcloud_clb_resource_type.option.ssl_deploy.label": "通过 SSL 服务部署到云资源实例", @@ -353,10 +431,10 @@ "workflow_node.deploy.form.tencentcloud_cos_domain.tooltip": "这是什么?请参阅 see https://console.cloud.tencent.com/cos", "workflow_node.deploy.form.tencentcloud_css_domain.label": "腾讯云云直播播放域名", "workflow_node.deploy.form.tencentcloud_css_domain.placeholder": "请输入腾讯云云直播播放域名", - "workflow_node.deploy.form.tencentcloud_css_domain.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/live/livestat", - "workflow_node.deploy.form.tencentcloud_ecdn_domain.label": "腾讯云 ECDN 加速域名(支持泛域名)", - "workflow_node.deploy.form.tencentcloud_ecdn_domain.placeholder": "请输入腾讯云 ECDN 加速域名", - "workflow_node.deploy.form.tencentcloud_ecdn_domain.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/cdn

泛域名表示形式为:*.example.com", + "workflow_node.deploy.form.tencentcloud_css_domain.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/live", + "workflow_node.deploy.form.tencentcloud_ecdn_domain.label": "腾讯云 ECDN 加速域名", + "workflow_node.deploy.form.tencentcloud_ecdn_domain.placeholder": "请输入腾讯云 ECDN 加速域名(支持泛域名)", + "workflow_node.deploy.form.tencentcloud_ecdn_domain.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/cdn", "workflow_node.deploy.form.tencentcloud_eo_zone_id.label": "腾讯云 EdgeOne 站点 ID", "workflow_node.deploy.form.tencentcloud_eo_zone_id.placeholder": "请输入腾讯云 EdgeOne 站点 ID", "workflow_node.deploy.form.tencentcloud_eo_zone_id.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/edgeone", @@ -376,6 +454,24 @@ "workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_ids.tooltip": "这是什么?请参阅 https://cloud.tencent.com.cn/document/product/400/91667

注意与各产品本身的实例 ID 区分。", "workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_ids.multiple_input_modal.title": "修改腾讯云云产品资源 ID", "workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_ids.multiple_input_modal.placeholder": "请输入腾讯云云产品资源 ID", + "workflow_node.deploy.form.tencentcloud_vod_sub_app_id.label": "腾讯云云点播应用 ID", + "workflow_node.deploy.form.tencentcloud_vod_sub_app_id.placeholder": "请输入腾讯云云点播应用 ID", + "workflow_node.deploy.form.tencentcloud_vod_sub_app_id.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/vod", + "workflow_node.deploy.form.tencentcloud_vod_domain.label": "腾讯云云点播加速域名", + "workflow_node.deploy.form.tencentcloud_vod_domain.placeholder": "请输入腾讯云云点播加速域名", + "workflow_node.deploy.form.tencentcloud_vod_domain.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/vod", + "workflow_node.deploy.form.tencentcloud_waf_region.label": "腾讯云 WAF 产品地域", + "workflow_node.deploy.form.tencentcloud_waf_region.placeholder": "请输入腾讯云 WAF 产品地域(例如:ap-guangzhou)", + "workflow_node.deploy.form.tencentcloud_waf_region.tooltip": "这是什么?请参阅 https://cloud.tencent.com/document/product/627/47525", + "workflow_node.deploy.form.tencentcloud_waf_domain.label": "腾讯云 WAF 防护域名", + "workflow_node.deploy.form.tencentcloud_waf_domain.placeholder": "请输入腾讯云 WAF 防护域名", + "workflow_node.deploy.form.tencentcloud_waf_domain.tooltip": "这是什么?请参阅 see https://console.cloud.tencent.com/waf", + "workflow_node.deploy.form.tencentcloud_waf_domain_id.label": "腾讯云 WAF 域名 ID", + "workflow_node.deploy.form.tencentcloud_waf_domain_id.placeholder": "请输入腾讯云 WAF 域名 ID", + "workflow_node.deploy.form.tencentcloud_waf_domain_id.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/waf", + "workflow_node.deploy.form.tencentcloud_waf_instance_id.label": "腾讯云 WAF 实例 ID", + "workflow_node.deploy.form.tencentcloud_waf_instance_id.placeholder": "请输入腾讯云 WAF 实例 ID", + "workflow_node.deploy.form.tencentcloud_waf_instance_id.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/waf", "workflow_node.deploy.form.ucloud_ucdn_domain_id.label": "优刻得 UCDN 域名 ID", "workflow_node.deploy.form.ucloud_ucdn_domain_id.placeholder": "请输入优刻得 UCDN 域名 ID", "workflow_node.deploy.form.ucloud_ucdn_domain_id.tooltip": "这是什么?请参阅 https://console.ucloud.cn/ucdn", @@ -388,9 +484,9 @@ "workflow_node.deploy.form.ucloud_us3_domain.label": "优刻得 US3 自定义域名", "workflow_node.deploy.form.ucloud_us3_domain.placeholder": "请输入优刻得 US3 自定义域名", "workflow_node.deploy.form.ucloud_us3_domain.tooltip": "这是什么?请参阅 https://console.ucloud.cn/ufile", - "workflow_node.deploy.form.volcengine_cdn_domain.label": "火山引擎 CDN 加速域名(支持泛域名)", - "workflow_node.deploy.form.volcengine_cdn_domain.placeholder": "请输入火山引擎 CDN 加速域名", - "workflow_node.deploy.form.volcengine_cdn_domain.tooltip": "这是什么?请参阅 https://console.volcengine.com/cdn/homepage

泛域名表示形式为:*.example.com", + "workflow_node.deploy.form.volcengine_cdn_domain.label": "火山引擎 CDN 加速域名", + "workflow_node.deploy.form.volcengine_cdn_domain.placeholder": "请输入火山引擎 CDN 加速域名(支持泛域名)", + "workflow_node.deploy.form.volcengine_cdn_domain.tooltip": "这是什么?请参阅 https://console.volcengine.com/cdn/homepage", "workflow_node.deploy.form.volcengine_clb_resource_type.label": "证书替换方式", "workflow_node.deploy.form.volcengine_clb_resource_type.placeholder": "请选择证书替换方式", "workflow_node.deploy.form.volcengine_clb_resource_type.option.listener.label": "替换指定监听器的证书", @@ -400,14 +496,23 @@ "workflow_node.deploy.form.volcengine_clb_listener_id.label": "火山引擎 CLB 监听器 ID", "workflow_node.deploy.form.volcengine_clb_listener_id.placeholder": "请输入火山引擎 CLB 监听器 ID", "workflow_node.deploy.form.volcengine_clb_listener_id.tooltip": "这是什么?请参阅 https://console.volcengine.com/clb/LoadBalancer", - "workflow_node.deploy.form.volcengine_dcdn_domain.label": "火山引擎 DCDN 加速域名(支持泛域名)", - "workflow_node.deploy.form.volcengine_dcdn_domain.placeholder": "请输入火山引擎 DCDN 加速域名", - "workflow_node.deploy.form.volcengine_dcdn_domain.tooltip": "这是什么?请参阅 https://console.volcengine.com/dcdn/dashboard

泛域名表示形式为:*.example.com", - "workflow_node.deploy.form.volcengine_live_domain.label": "火山引擎视频直播流域名(支持泛域名)", - "workflow_node.deploy.form.volcengine_live_domain.placeholder": "请输入火山引擎视频直播流域名", - "workflow_node.deploy.form.volcengine_live_domain.tooltip": "这是什么?请参阅 https://console.volcengine.com/live

泛域名表示形式为:*.example.com", + "workflow_node.deploy.form.volcengine_dcdn_domain.label": "火山引擎 DCDN 加速域名", + "workflow_node.deploy.form.volcengine_dcdn_domain.placeholder": "请输入火山引擎 DCDN 加速域名(支持泛域名)", + "workflow_node.deploy.form.volcengine_dcdn_domain.tooltip": "这是什么?请参阅 https://console.volcengine.com/dcdn/dashboard", + "workflow_node.deploy.form.volcengine_imagex_region.label": "火山引擎 ImageX 服务地域", + "workflow_node.deploy.form.volcengine_imagex_region.placeholder": "请输入火山引擎 ImageX 服务地域(例如:cn-north-1)", + "workflow_node.deploy.form.volcengine_imagex_region.tooltip": "这是什么?请参阅 https://www.volcengine.com/docs/508/23757", + "workflow_node.deploy.form.volcengine_imagex_service_id.label": "火山引擎 TOS 服务 ID", + "workflow_node.deploy.form.volcengine_imagex_service_id.placeholder": "请输入火山引擎 TOS 服务 ID", + "workflow_node.deploy.form.volcengine_imagex_service_id.tooltip": "这是什么?请参阅 https://console.volcengine.com/imagex", + "workflow_node.deploy.form.volcengine_imagex_domain.label": "火山引擎 ImageX 绑定域名", + "workflow_node.deploy.form.volcengine_imagex_domain.placeholder": "请输入火山引擎 ImageX 绑定域名", + "workflow_node.deploy.form.volcengine_imagex_domain.tooltip": "这是什么?请参阅 see https://console.volcengine.com/imagex", + "workflow_node.deploy.form.volcengine_live_domain.label": "火山引擎视频直播流域名", + "workflow_node.deploy.form.volcengine_live_domain.placeholder": "请输入火山引擎视频直播流域名(支持泛域名)", + "workflow_node.deploy.form.volcengine_live_domain.tooltip": "这是什么?请参阅 https://console.volcengine.com/live", "workflow_node.deploy.form.volcengine_tos_region.label": "火山引擎 TOS 服务地域", - "workflow_node.deploy.form.volcengine_tos_region.placeholder": "请输入火山引擎 TOS 服务地域(例如:cn-beijing", + "workflow_node.deploy.form.volcengine_tos_region.placeholder": "请输入火山引擎 TOS 服务地域(例如:cn-beijing)", "workflow_node.deploy.form.volcengine_tos_region.tooltip": "这是什么?请参阅 https://www.volcengine.com/docs/6349/107356", "workflow_node.deploy.form.volcengine_tos_bucket.label": "火山引擎 TOS 存储桶名", "workflow_node.deploy.form.volcengine_tos_bucket.placeholder": "请输入火山引擎 TOS 存储桶名", diff --git a/ui/src/vite-env.d.ts b/ui/types/vite-env.d.ts similarity index 100% rename from ui/src/vite-env.d.ts rename to ui/types/vite-env.d.ts