diff --git a/go.mod b/go.mod index 123c69ae..190cc75c 100644 --- a/go.mod +++ b/go.mod @@ -8,54 +8,59 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates v0.9.0 - github.com/G-Core/gcorelabscdn-go v1.0.26 + github.com/G-Core/gcorelabscdn-go v1.0.28 github.com/alibabacloud-go/alb-20200616/v2 v2.2.8 github.com/alibabacloud-go/cas-20200407/v3 v3.0.4 github.com/alibabacloud-go/cdn-20180510/v5 v5.2.2 - github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.2 - github.com/alibabacloud-go/esa-20240910/v2 v2.22.1 + github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.4 + github.com/alibabacloud-go/esa-20240910/v2 v2.23.0 + github.com/alibabacloud-go/fc-20230330/v4 v4.1.7 + github.com/alibabacloud-go/fc-open-20210406/v2 v2.0.12 github.com/alibabacloud-go/live-20161101 v1.1.1 github.com/alibabacloud-go/nlb-20220430/v2 v2.0.3 github.com/alibabacloud-go/slb-20140515/v4 v4.0.10 - github.com/alibabacloud-go/tea v1.3.2 - github.com/alibabacloud-go/vod-20170321/v4 v4.6.1 + github.com/alibabacloud-go/tea v1.3.4 + github.com/alibabacloud-go/vod-20170321/v4 v4.7.0 github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.0.5 github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible github.com/aws/aws-sdk-go-v2/service/acm v1.31.1 - github.com/aws/aws-sdk-go-v2/service/cloudfront v1.45.1 - github.com/baidubce/bce-sdk-go v0.9.218 - github.com/byteplus-sdk/byteplus-sdk-golang v1.0.41 + github.com/aws/aws-sdk-go-v2/service/cloudfront v1.45.2 + github.com/baidubce/bce-sdk-go v0.9.221 + github.com/byteplus-sdk/byteplus-sdk-golang v1.0.42 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.138 - github.com/jdcloud-api/jdcloud-sdk-go v1.62.0 + github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.141 + github.com/jdcloud-api/jdcloud-sdk-go v1.64.0 + github.com/libdns/dynv6 v1.0.0 + github.com/libdns/libdns v0.2.3 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 + github.com/pkg/sftp v1.13.8 github.com/pocketbase/dbx v1.11.0 - github.com/pocketbase/pocketbase v0.25.9 + github.com/pocketbase/pocketbase v0.26.1 github.com/povsister/scp v0.0.0-20240802064259-28781e87b246 github.com/qiniu/go-sdk/v7 v7.25.2 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1115 - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1115 - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1115 - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1115 - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1115 - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1115 - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1102 - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1099 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1127 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1127 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1117 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1115 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1124 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1126 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1115 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1125 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.197 - github.com/volcengine/volcengine-go-sdk v1.0.184 + github.com/volcengine/volc-sdk-golang v1.0.199 + github.com/volcengine/volcengine-go-sdk v1.0.187 gitlab.ecloud.com/ecloud/ecloudsdkclouddns v1.0.1 gitlab.ecloud.com/ecloud/ecloudsdkcore v1.0.0 golang.org/x/crypto v0.36.0 golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 - k8s.io/api v0.32.2 - k8s.io/apimachinery v0.32.2 - k8s.io/client-go v0.32.2 + k8s.io/api v0.32.3 + k8s.io/apimachinery v0.32.3 + k8s.io/client-go v0.32.3 software.sslmate.com/src/go-pkcs12 v0.5.0 ) @@ -67,9 +72,6 @@ require ( 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.3 // indirect github.com/alibabacloud-go/alibabacloud-gateway-fc-util v0.0.7 // indirect - github.com/alibabacloud-go/fc-20230330/v4 v4.1.7 // indirect - github.com/alibabacloud-go/fc-open-20210406 v1.1.14 // indirect - github.com/alibabacloud-go/fc-open-20210406/v2 v2.0.12 // 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 @@ -88,6 +90,7 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.16.0 // indirect + github.com/go-sql-driver/mysql v1.8.1 // 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 @@ -109,7 +112,6 @@ 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/scf v1.0.1115 // indirect github.com/x448/float16 v0.8.4 // indirect go.mongodb.org/mongo-driver v1.17.2 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect @@ -137,20 +139,14 @@ require ( github.com/aliyun/credentials-go v1.4.3 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aws/aws-sdk-go-v2 v1.36.3 - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.8 // indirect github.com/aws/aws-sdk-go-v2/config v1.29.5 github.com/aws/aws-sdk-go-v2/credentials v1.17.58 github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.28 // indirect - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.58 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.32 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.6.0 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.13 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.13 // indirect - github.com/aws/aws-sdk-go-v2/service/s3 v1.75.3 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.24.15 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.14 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.33.14 // indirect @@ -168,10 +164,8 @@ require ( github.com/go-jose/go-jose/v4 v4.0.4 // indirect github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect github.com/goccy/go-json v0.10.4 // indirect - github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/uuid v1.6.0 - github.com/googleapis/gax-go/v2 v2.14.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -187,35 +181,29 @@ require ( github.com/pkg/errors v0.9.1 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/spf13/cast v1.7.1 // indirect - github.com/spf13/cobra v1.8.1 // indirect + github.com/spf13/cobra v1.9.1 // indirect github.com/spf13/pflag v1.0.6 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/stretchr/testify v1.10.0 // indirect github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1084 // indirect github.com/tjfoc/gmsm v1.4.1 // indirect - go.opencensus.io v0.24.0 // indirect - gocloud.dev v0.40.0 // indirect - golang.org/x/image v0.24.0 // indirect + golang.org/x/image v0.25.0 // indirect golang.org/x/mod v0.24.0 // indirect golang.org/x/net v0.37.0 // indirect - golang.org/x/oauth2 v0.26.0 // indirect + golang.org/x/oauth2 v0.28.0 // indirect golang.org/x/sync v0.12.0 golang.org/x/sys v0.31.0 // indirect golang.org/x/term v0.30.0 // indirect golang.org/x/text v0.23.0 // indirect golang.org/x/time v0.9.0 golang.org/x/tools v0.31.0 // indirect - golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect - google.golang.org/api v0.220.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 // indirect - google.golang.org/grpc v1.70.0 // indirect google.golang.org/protobuf v1.36.5 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect modernc.org/libc v1.61.13 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.8.2 // indirect - modernc.org/sqlite v1.35.0 // indirect + modernc.org/sqlite v1.36.1 // indirect ) replace gitlab.ecloud.com/ecloud/ecloudsdkcore v1.0.0 => ./internal/pkg/vendors/cmcc-sdk/ecloudsdkcore@v1.0.0 diff --git a/go.sum b/go.sum index 04555b1e..8c79203b 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,3 @@ -cel.dev/expr v0.19.0 h1:lXuo+nDhpyJSpWxpPVi5cPUwzKb+dsdOiw6IreM5yt0= -cel.dev/expr v0.19.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -15,26 +13,14 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= -cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= -cloud.google.com/go/auth v0.14.1 h1:AwoJbzUdxA/whv1qj3TLKwh3XX5sikny2fc40wUl+h0= -cloud.google.com/go/auth v0.14.1/go.mod h1:4JHUxlGXisL0AW8kXPtUF6ztuOksyfUQNFjfsOCXkPM= -cloud.google.com/go/auth/oauth2adapt v0.2.7 h1:/Lc7xODdqcEw8IrZ9SvwnlLX6j9FHQM74z6cBk9Rw6M= -cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= -cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/iam v1.2.2 h1:ozUSofHUGf/F4tCNy/mu9tHLTaxZFLOUiKzjcgWHGIA= -cloud.google.com/go/iam v1.2.2/go.mod h1:0Ys8ccaZHdI1dEUilwzqng/6ps2YB6vRsjIe00/+6JY= -cloud.google.com/go/monitoring v1.21.2 h1:FChwVtClH19E7pJ+e0xUhJPGksctZNVOk2UhMmblmdU= -cloud.google.com/go/monitoring v1.21.2/go.mod h1:hS3pXvaG8KgWTSz+dAdyzPrGUYmi2Q+WFX8g2hqVEZU= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -44,8 +30,6 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.47.0 h1:ajqgt30fnOMmLfWfu1PWcb+V9Dxz6n+9WKjdNg5R4HM= -cloud.google.com/go/storage v1.47.0/go.mod h1:Ks0vP374w0PW6jOUameJbapbQKXqkjGd/OJRp2fb9IQ= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= @@ -83,14 +67,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= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0/go.mod h1:6fTWu4m3jocfUZLYF5KsZC1TUfRvEjs7lM4crme/irw= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0 h1:GYUJLfvd++4DMuMhCFLgLXvFwofIxh/qOwoGuS/LTew= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0/go.mod h1:wRbFgBQUVm1YXrvWKofAEmq9HNJTDphbAaJSSX01KUI= +github.com/G-Core/gcorelabscdn-go v1.0.28 h1:6ymVMV3HPTICO5BWJCEcZZzgY+Pc/+/TQMzeXMN77GQ= +github.com/G-Core/gcorelabscdn-go v1.0.28/go.mod h1:iSGXaTvZBzDHQW+rKFS918BgFVpONcyLEijwh8WsXpE= github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= @@ -110,7 +88,6 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5 github.com/alex-ant/gomath v0.0.0-20160516115720-89013a210a82/go.mod h1:nLnM0KdK1CmygvjpDUO6m1TjSsiQtL61juhNsvV/JVI= github.com/alibabacloud-go/alb-20200616/v2 v2.2.8 h1:/6+1AqIiENG3u6RmEYWEQ/YZv3YgdFZkE6Xd9RZM6n0= github.com/alibabacloud-go/alb-20200616/v2 v2.2.8/go.mod h1:jU/K+GVb5b0vjiDpkf6E0dH77tsi1jTLGWm4ouCiRxk= -github.com/alibabacloud-go/alibabacloud-gateway-fc-util v0.0.6/go.mod h1:H0RPHXHP/ICfEQrKzQcCqXI15jcV4zaDPCOAmh3U9O8= github.com/alibabacloud-go/alibabacloud-gateway-fc-util v0.0.7 h1:RDatRb9RG39HjkevgzTeiVoDDaamoB+12GHNairp3Ag= github.com/alibabacloud-go/alibabacloud-gateway-fc-util v0.0.7/go.mod h1:H0RPHXHP/ICfEQrKzQcCqXI15jcV4zaDPCOAmh3U9O8= github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 h1:eIf+iGJxdU4U9ypaUfbtOWCsZSbTb8AUHvyPrxu6mAA= @@ -129,12 +106,11 @@ github.com/alibabacloud-go/darabonba-encode-util v0.0.2/go.mod h1:JiW9higWHYXm7F github.com/alibabacloud-go/darabonba-map v0.0.2 h1:qvPnGB4+dJbJIxOOfawxzF3hzMnIpjmafa0qOTp6udc= github.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+MtEzBunJwQGceGQlvaPGPc= github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.0/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ= -github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.1/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ= github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.2/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ= github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.5/go.mod h1:kUe8JqFmoVU7lfBauaDD5taFaW7mBI+xVsyHutYtabg= github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10/go.mod h1:26a14FGhZVELuz2cc2AolvW4RHmIO3/HRwsdHhaIPDE= -github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.2 h1:/tEcF4JeJLi3Mtq66ZFm/EYu4jRixJZtOhBkrU1mfBw= -github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.2/go.mod h1:Wxis0IBFusdbo44HO6KYYCJR1rRkoh47QQOYWvaheSU= +github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.4 h1:IGSZHlOnWwBbLtX5xDplQvZOH0nkrV7Wmq+Fto7JK5w= +github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.4/go.mod h1:Wxis0IBFusdbo44HO6KYYCJR1rRkoh47QQOYWvaheSU= github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg= github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ= github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo= @@ -148,12 +124,10 @@ github.com/alibabacloud-go/debug v1.0.1/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/ql github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE= github.com/alibabacloud-go/endpoint-util v1.1.1 h1:ZkBv2/jnghxtU0p+upSU0GGzW1VL9GQdZO3mcSUTUy8= github.com/alibabacloud-go/endpoint-util v1.1.1/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE= -github.com/alibabacloud-go/esa-20240910/v2 v2.22.1 h1:Wmvb90nS6IxJjVe+fUWv7jtXFrJttSh/WkFQ2HIsQmQ= -github.com/alibabacloud-go/esa-20240910/v2 v2.22.1/go.mod h1:P1w/+i7dE2xSXVHJznEOVImlLtqqrzUJQQk2AsyBJ6o= +github.com/alibabacloud-go/esa-20240910/v2 v2.23.0 h1:Z/AALmxhOfzN+35tNCvm62/pET4IlxhDQn4nsdLqNzk= +github.com/alibabacloud-go/esa-20240910/v2 v2.23.0/go.mod h1:P1w/+i7dE2xSXVHJznEOVImlLtqqrzUJQQk2AsyBJ6o= github.com/alibabacloud-go/fc-20230330/v4 v4.1.7 h1:rQvPfzPaouL/WGNgMDMCplA4wDscmVFff7aLCUkjv4g= github.com/alibabacloud-go/fc-20230330/v4 v4.1.7/go.mod h1:ssEfKO6MskPtq7QaQnyiOHGWLXOZcl7a8YIf8u56DGc= -github.com/alibabacloud-go/fc-open-20210406 v1.1.14 h1:avhpcxvdwexER2S1buxgnYoEq+/rWX3iMCgP3EZZz+E= -github.com/alibabacloud-go/fc-open-20210406 v1.1.14/go.mod h1:M3vmom/tsiVbnIBBZshm8JBXcniX9Ryek3NFX2Q95dg= github.com/alibabacloud-go/fc-open-20210406/v2 v2.0.12 h1:A3D8Mp6qf8DfR6Dt5MpS8aDVaWfS4N85T5CvGUvgrjM= github.com/alibabacloud-go/fc-open-20210406/v2 v2.0.12/go.mod h1:F5c0E5UB3k8v6neTtw3FBcJ1YCNFzVoL1JPRHTe33u4= github.com/alibabacloud-go/live-20161101 v1.1.1 h1:rUGfA8RHmCMtQ5M3yMSyRde+yRXWqVecmiXBU3XrGJ8= @@ -179,8 +153,9 @@ github.com/alibabacloud-go/tea v1.1.19/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= github.com/alibabacloud-go/tea v1.2.1/go.mod h1:qbzof29bM/IFhLMtJPrgTGK3eauV5J2wSyEUo4OEmnA= github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk= -github.com/alibabacloud-go/tea v1.3.2 h1:4xlOnwYaK3ek1Kh+fgYTOYYOfv+uv3SAiJEIYm+8vJk= github.com/alibabacloud-go/tea v1.3.2/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg= +github.com/alibabacloud-go/tea v1.3.4 h1:QGTns2930y+ANmoNcUS74TgYpsoqusSrLIyYDOvIFFI= +github.com/alibabacloud-go/tea v1.3.4/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg= github.com/alibabacloud-go/tea-fileform v1.1.1 h1:1YG6erAP3joQ0XdCXYIotuD7zyOM6qCR49xkp5FZDeU= github.com/alibabacloud-go/tea-fileform v1.1.1/go.mod h1:ZeCV91o4ISmxidd686f0ebdS5EDHWU+vW+TkjLhrsFE= github.com/alibabacloud-go/tea-oss-sdk v1.1.3 h1:EhAHI6edMeqgkZEqP7r4nc9iMWAUBKGxJHoBsOSKTtU= @@ -202,8 +177,8 @@ 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/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/vod-20170321/v4 v4.7.0 h1:hpsnJBX5EeMrFujopMCjfq+p8XbNvPhFw6LOTV/WHd8= +github.com/alibabacloud-go/vod-20170321/v4 v4.7.0/go.mod h1:TkgLKMSLu0qZN8Qdcu8svfHREyI64kjFvrp/GhrD4VQ= github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.0.5 h1:ldAm1nvsCq66igjtcZyGhAoLClr+2eZ/pMIBUdKCOMM= github.com/alibabacloud-go/waf-openapi-20211001/v5 v5.0.5/go.mod h1:DohGoS8BnMxHXghHebtjPP7+GMdxPsRN19T3nn2HcCU= github.com/aliyun/alibaba-cloud-sdk-go v1.63.83 h1:YBkf7H5CSgrlb3C1aWcpDt7Vk8UEGFPeD2OOirtt6IM= @@ -228,46 +203,32 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:W 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= -github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM= github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.8 h1:zAxi9p3wsZMIaVCdoiQp2uZ9k1LsZvmAnoTBeZPXom0= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.8/go.mod h1:3XkePX5dSaxveLAYY7nsbsZZrKxCyEuE5pM4ziFxyGg= github.com/aws/aws-sdk-go-v2/config v1.29.5 h1:4lS2IB+wwkj5J43Tq/AwvnscBerBJtQQ6YS7puzCI1k= github.com/aws/aws-sdk-go-v2/config v1.29.5/go.mod h1:SNzldMlDVbN6nWxM7XsUiNXPSa1LWlqiXtvh/1PrJGg= github.com/aws/aws-sdk-go-v2/credentials v1.17.58 h1:/d7FUpAPU8Lf2KUdjniQvfNdlMID0Sd9pS23FJ3SS9Y= github.com/aws/aws-sdk-go-v2/credentials v1.17.58/go.mod h1:aVYW33Ow10CyMQGFgC0ptMRIqJWvJ4nxZb0sUiuQT/A= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.28 h1:KwsodFKVQTlI5EyhRSugALzsV6mG/SGrdjlMXSZSdso= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.28/go.mod h1:EY3APf9MzygVhKuPXAc5H+MkGb8k/DOSQjWS0LgkKqI= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.58 h1:/BsEGAyMai+KdXS+CMHlLhB5miAO19wOqE6tj8azWPM= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.58/go.mod h1:KHM3lfl/sAJBCoLI1Lsg5w4SD2VDYWwQi7vxbKhw7TI= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 h1:Pg9URiobXy85kgFev3og2CuOZ8JZUBENF+dcgWBaYNk= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.32 h1:OIHj/nAhVzIXGzbAE+4XmZ8FPvro3THr6NlqErJc3wY= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.32/go.mod h1:LiBEsDo34OJXqdDlRGsilhlIiXR7DL+6Cx2f4p1EgzI= github.com/aws/aws-sdk-go-v2/service/acm v1.31.1 h1:FB1PgU6vlXbqehxZiHuYQRWo5Ou6sQrFJcUaRe27lRo= github.com/aws/aws-sdk-go-v2/service/acm v1.31.1/go.mod h1:3sKYAgRbuBa2QMYGh/WEclwnmfx+QoPhhX25PdSQSQM= -github.com/aws/aws-sdk-go-v2/service/cloudfront v1.45.1 h1:i5znMqubyVRwPT8MsBndfhtvjuSj4qRVAh9oVRXRPcI= -github.com/aws/aws-sdk-go-v2/service/cloudfront v1.45.1/go.mod h1:FIBJ48TS+qJb+Ne4qJ+0NeIhtPTVXItXooTeNeVI4Po= +github.com/aws/aws-sdk-go-v2/service/cloudfront v1.45.2 h1:S3JpsBLyn/jqSJ6GgsbDQHubmop6fshQk/iOaOeotsc= +github.com/aws/aws-sdk-go-v2/service/cloudfront v1.45.2/go.mod h1:FIBJ48TS+qJb+Ne4qJ+0NeIhtPTVXItXooTeNeVI4Po= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 h1:D4oz8/CzT9bAEYtVhSBmFj2dNOtaHOtMKc2vHBwYizA= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2/go.mod h1:Za3IHqTQ+yNcRHxu1OFucBh0ACZT4j4VQFF0BqpZcLY= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.6.0 h1:kT2WeWcFySdYpPgyqJMSUE7781Qucjtn6wBvrgm9P+M= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.6.0/go.mod h1:WYH1ABybY7JK9TITPnk6ZlP7gQB8psI4c9qDmMsnLSA= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.13 h1:SYVGSFQHlchIcy6e7x12bsrxClCXSP5et8cqVhL8cuw= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.13/go.mod h1:kizuDaLX37bG5WZaoxGPQR/LNFXpxp0vsUnqfkWXfNE= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.13 h1:OBsrtam3rk8NfBEq7OLOMm5HtQ9Yyw32X4UQMya/wjw= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.13/go.mod h1:3U4gFA5pmoCOja7aq4nSaIAGbaOHv2Yl2ug018cmC+Q= github.com/aws/aws-sdk-go-v2/service/route53 v1.48.1 h1:njgAP7Rtt4DGdTGFPhJ4gaZXCD1CDj/SZDa5W4ZgSTs= github.com/aws/aws-sdk-go-v2/service/route53 v1.48.1/go.mod h1:TN4PcCL0lvqmYcv+AV8iZFC4Sd0FM06QDaoBXrFEftU= -github.com/aws/aws-sdk-go-v2/service/s3 v1.75.3 h1:JBod0SnNqcWQ0+uAyzeRFG1zCHotW8DukumYYyNy0zo= -github.com/aws/aws-sdk-go-v2/service/s3 v1.75.3/go.mod h1:FHSHmyEUkzRbaFFqqm6bkLAOQHgqhsLmfCahvCBMiyA= github.com/aws/aws-sdk-go-v2/service/sso v1.24.15 h1:/eE3DogBjYlvlbhd2ssWyeuovWunHLxfgw3s/OJa4GQ= github.com/aws/aws-sdk-go-v2/service/sso v1.24.15/go.mod h1:2PCJYpi7EKeA5SkStAmZlF6fi0uUABuhtF8ILHjGc3Y= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.14 h1:M/zwXiL2iXUrHputuXgmO94TVNmcenPHxgLXLutodKE= @@ -277,8 +238,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.33.14/go.mod h1:dspXf/oYWGWo6DEvj98w github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= 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.218 h1:yOoktcJOoyCJmq06m6nZAif+RMndT4fF+Zj9RfidEn0= -github.com/baidubce/bce-sdk-go v0.9.218/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg= +github.com/baidubce/bce-sdk-go v0.9.221 h1:x5uTXND33m5TE3UBXYhlePuXcJi5rxNnBBt+bP7kPe0= +github.com/baidubce/bce-sdk-go v0.9.221/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= @@ -286,16 +247,14 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/blinkbean/dingtalk v1.1.3 h1:MbidFZYom7DTFHD/YIs+eaI7kRy52kmWE/sy0xjo6E4= github.com/blinkbean/dingtalk v1.1.3/go.mod h1:9BaLuGSBqY3vT5hstValh48DbsKO7vaHaJnG9pXwbto= -github.com/byteplus-sdk/byteplus-sdk-golang v1.0.41 h1:zLw2bwsW0gjNN1c9Zim1iv0g8ms+pV8pQ9yhLquOj1Q= -github.com/byteplus-sdk/byteplus-sdk-golang v1.0.41/go.mod h1:7iCaE+dR9EycrJU0GQyMhptbInLbQhsKXiDKDjNi8Vs= +github.com/byteplus-sdk/byteplus-sdk-golang v1.0.42 h1:Dm9FDjQP2SlAjUH7WAV7DFYDBFQz2uBxX6JULs0Sxs0= +github.com/byteplus-sdk/byteplus-sdk-golang v1.0.42/go.mod h1:CIL/T2dxgbIA79os+wl0Fq0vCbADTZNIddV6PNYB6DY= github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= -github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -317,12 +276,10 @@ github.com/cloudflare/cloudflare-go v0.114.0/go.mod h1:O7fYfFfA6wKqKFn2QIR9lhj7F github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 h1:QVw89YDxXxEe+l8gU8ETbOasdwEV+avkR75ZzsVV9WI= -github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/dave/jennifer v1.6.1/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -351,18 +308,12 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.13.1 h1:vPfJZCkob6yTMEgS+0TwfTUfbHjfy/6vOJ8hUWX/uXE= -github.com/envoyproxy/go-control-plane v0.13.1/go.mod h1:X45hY0mufo6Fd0KW3rqsGvQMw58jvjymeCzBU3mWyHw= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= -github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= -github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= -github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/franela/goblin v0.0.0-20210519012713-85d372ac71e2/go.mod h1:VzmDKDJVZI3aJmnRI9VjAn9nJ8qPPsN1fqzr9dqInIo= @@ -400,8 +351,6 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= @@ -458,8 +407,6 @@ github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= -github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -523,23 +470,15 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20250315033105-103756e64e1d h1:tx51Lf+wdE+aavqH8TcPJoCjTf4cE8hrMzROghCely0= +github.com/google/pprof v0.0.0-20250315033105-103756e64e1d/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= -github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI= -github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA= -github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= -github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q= -github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= @@ -578,8 +517,8 @@ github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.138 h1:VH/OZE73y0IRomF9QqCw71etSdfFbQIq/utq164IOVg= -github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.138/go.mod h1:Y/+YLCFCJtS29i2MbYPTUlNNfwXvkzEsZKR0imY/2aY= +github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.141 h1:8i57QAi5u+iPAYze92bkIvZoHiS0J45ndul5glr/NE8= +github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.141/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= @@ -592,8 +531,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/jdcloud-api/jdcloud-sdk-go v1.64.0 h1:xZc/ZRcrOhDx9Ra9htu6ui2gUUttmLsXIqH61LcvY4U= +github.com/jdcloud-api/jdcloud-sdk-go v1.64.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= @@ -646,6 +585,11 @@ github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgx github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/libdns/dynv6 v1.0.0 h1:JpOK9TYRTHETAe+SIw3lk8SgUi3eD250GK+4fAHu4ys= +github.com/libdns/dynv6 v1.0.0/go.mod h1:65PL/bAlyH0J+0WGlOJYnMpoIuXcg/FmW4dTBYWtYUU= +github.com/libdns/libdns v0.1.0/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40= +github.com/libdns/libdns v0.2.3 h1:ba30K4ObwMGB/QTmqUxf3H4/GmUrCAIkMWejeGl12v8= +github.com/libdns/libdns v0.2.3/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -741,17 +685,15 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= -github.com/pkg/sftp v1.13.7 h1:uv+I3nNJvlKZIQGSr8JVQLNHFU9YhhNpvC14Y6KgmSM= -github.com/pkg/sftp v1.13.7/go.mod h1:KMKI0t3T6hfA+lTR/ssZdunHo+uwq7ghoN09/FSu3DY= -github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= -github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= +github.com/pkg/sftp v1.13.8 h1:Xt7eJ/xqXv7s0VuzFw7JXhZj6Oc1zI6l4GK8KP9sFB0= +github.com/pkg/sftp v1.13.8/go.mod h1:DmvEkvKE2lshEeuo2JMp06yqcx9HVnR7e3zqQl42F3U= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pocketbase/dbx v1.11.0 h1:LpZezioMfT3K4tLrqA55wWFw1EtH1pM4tzSVa7kgszU= github.com/pocketbase/dbx v1.11.0/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs= -github.com/pocketbase/pocketbase v0.25.9 h1:/PSJcy39vEGv4lsBG4HV0ZFLcFsTdK9oMkJbxVlVJSs= -github.com/pocketbase/pocketbase v0.25.9/go.mod h1:gOnPr+g/GS+iqKh5XYXycdRWVGhiHY4c1H4TGjU9DDw= +github.com/pocketbase/pocketbase v0.26.1 h1:0WBqIRKKPCqp+xHPVLB4fevkoT9HVlR4BSuNwAt5oJ0= +github.com/pocketbase/pocketbase v0.26.1/go.mod h1:t5y5pfnhrEg//RuSzSg0a926OLZ0oQj66jYs3BzDJwA= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/povsister/scp v0.0.0-20240802064259-28781e87b246 h1:c4D8BPWLOxxdaxQLfLKQXH2YXY/E9yo3jrDSL54XrTw= @@ -814,9 +756,8 @@ github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= @@ -838,7 +779,6 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= @@ -846,27 +786,30 @@ github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQ github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1115 h1:HsrXyqKQB2mKfGq+ZkbylRCMrbtPCmmUBrwA8MhhEX0= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1115/go.mod h1:5cz1DtLlXK98U1Hh36oW4PjVOU+mbKg5wtCDmCc9Fcs= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1115 h1:QClUB1NRQNQSn4yp2msXjuU6aHS+5YKlAOL4tdrGtcs= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1115/go.mod h1:4MCC7p86SOARKb0P6FGC9s6KvCETI6t4oFrXDjgZD0M= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1127 h1:PiLZflqaW0690YsqIM/hqaVYjZJ3+cCJp4NHfw7h/uw= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1127/go.mod h1:V1+julLUOH0jKoVH6o6xgM4STWowzAL57M4VanUEEag= 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.1099/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1102/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1115 h1:lYeFC379r76seyzN7PHmSxv1ji9knmsXQJglDB/K0WE= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1115/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1117/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1124/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1125/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1126/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1127 h1:1uG8zc0b9gLbyTr27T0CzGtcdrL86CGGJ6Flkq867f4= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1127/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.1115 h1:qy05kto0yI5AG6u0+BHwfUK9jJUJ92081ee+wvSkpk8= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1115/go.mod h1:BSeUvwz3WO7BbTan1OKC0+NDeiULVZVovrd93qCtWJM= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1117 h1:Yc/r5zUAyukVI3huIuwE7koowCjDjOWqeRpBILCvOSE= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1117/go.mod h1:YxsorHl3sTRw+2GsUObMqcumDqAQ3zo9rLMtf3Cxj8U= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1115 h1:Qi7VWmJ0AQxEMlwKpbWfnsLA5QdNxekdcLJTBVdO85U= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1115/go.mod h1:P16nIMvmpSY+arTc2m2HyJmrYQP6CFnr48glz0+abyw= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1115 h1:xAMIp4en0Wm4FAS4zo5ZXeYT4FMXms68Fc2COP4J/TM= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1115/go.mod h1:3zCzHke2XQMBm6T2PIdnfTCXGxykV4uTTdRStpUdS0g= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1115 h1:3Xz/q/m9gl++KtPkrgaXvFCXjM1y9QmAbpG8qfLUm9M= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1115/go.mod h1:/NqwqdSTa8u2xPmr9BpAzY+2c49NP23AEGpkN93AR6g= -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/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1124 h1:LQKAlxFb0sYiE8ojK5h9+seuFzogoJtYnXmiRF+4F4Q= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1124/go.mod h1:tYbK0FbHVG+78od7eZpzczE8qk0JWKO/osTQWuiJ3Fo= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1126 h1:+CJQNXLdLP0GLaz2fnPECQsU+WdOmW3BQ54cNoQgMKA= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1126/go.mod h1:eY3GoWilNoCPOEw2Lp4o+h02nEfc+BoZnqK3TlK6F7I= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1115 h1:rO0LdbcNtT5VlL9sB/K3Ve848uLp1rgg3R8igT9xsFQ= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod v1.0.1115/go.mod h1:jJR8Y5sHuujSXZy0cpCgBk180TvPNsLw9hEoSH9w7iA= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1125 h1:IR9pJqHjHr7KyncRVxld9iltfnmy9sCC+0USZrs3rOw= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1125/go.mod h1:5+5QrF7x+AW1KPM7F+YRzD74L88RXHZ6BxDF07b8QkE= 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= @@ -881,10 +824,10 @@ github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/X github.com/volcengine/ve-tos-golang-sdk/v2 v2.7.9 h1:fEnScn2dXfvfNcFnvJnpf/cYdj8kLIe5QC5qORlFO2c= github.com/volcengine/ve-tos-golang-sdk/v2 v2.7.9/go.mod h1:IrjK84IJJTuOZOTMv/P18Ydjy/x+ow7fF7q11jAxXLM= github.com/volcengine/volc-sdk-golang v1.0.23/go.mod h1:AfG/PZRUkHJ9inETvbjNifTDgut25Wbkm2QoYBTbvyU= -github.com/volcengine/volc-sdk-golang v1.0.197 h1:jJlcMp+4i3lVL2ZZTVo8u3cndlXzC5SZoqH/4M6pyuw= -github.com/volcengine/volc-sdk-golang v1.0.197/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ= -github.com/volcengine/volcengine-go-sdk v1.0.184 h1:bL8/dEkYwZvy5fqHO9+HIp1X6eBjIqR7yLmo+bmOaeU= -github.com/volcengine/volcengine-go-sdk v1.0.184/go.mod h1:gfEDc1s7SYaGoY+WH2dRrS3qiuDJMkwqyfXWCa7+7oA= +github.com/volcengine/volc-sdk-golang v1.0.199 h1:zv9QOqTl/IsLwtfC37GlJtcz6vMAHi+pjq8ILWjLYUc= +github.com/volcengine/volc-sdk-golang v1.0.199/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ= +github.com/volcengine/volcengine-go-sdk v1.0.187 h1:YpZjydoyHDA/ofnF6mYCelbOoo9pJsBEiQOOSJzGSOY= +github.com/volcengine/volcengine-go-sdk v1.0.187/go.mod h1:gfEDc1s7SYaGoY+WH2dRrS3qiuDJMkwqyfXWCa7+7oA= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= @@ -913,26 +856,6 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/contrib/detectors/gcp v1.32.0 h1:P78qWqkLSShicHmAzfECaTgvslqHxblNE9j62Ws1NK8= -go.opentelemetry.io/contrib/detectors/gcp v1.32.0/go.mod h1:TVqo0Sda4Cv8gCIixd7LuLwW4EylumVWfhjZJjDD4DU= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0 h1:PS8wXpbyaDJQ2VDHHncMe9Vct0Zn1fEjpsjrLxGJoSc= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0/go.mod h1:HDBUsEjOuRC0EzKZ1bSaRGZWUBAzo+MhAcUUORSr4D0= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= -go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= -go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= -go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= -go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= -go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= -go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= -go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU= -go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= -go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= -go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= @@ -942,8 +865,6 @@ go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9i go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -gocloud.dev v0.40.0 h1:f8LgP+4WDqOG/RXoUcyLpeIAGOcAbZrZbDQCUee10ng= -gocloud.dev v0.40.0/go.mod h1:drz+VyYNBvrMTW0KZiBAYEdl8lbNZx+OQ7oQvdrFmSQ= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -968,12 +889,12 @@ golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45 golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -995,8 +916,8 @@ golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86h golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ= -golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8= +golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ= +golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1087,8 +1008,8 @@ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE= -golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= +golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1105,6 +1026,7 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1177,12 +1099,12 @@ golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= @@ -1194,12 +1116,12 @@ golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1219,6 +1141,7 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1288,8 +1211,6 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= -golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= @@ -1310,8 +1231,6 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.220.0 h1:3oMI4gdBgB72WFVwE1nerDD8W3HUOS4kypK6rRLbGns= -google.golang.org/api v0.220.0/go.mod h1:26ZAlY6aN/8WgpCzjPNy18QpYaz7Zgg1h0qe1GkZEmY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1350,12 +1269,6 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 h1:ToEetK57OidYuqD4Q5w+vfEnPvPpuTwedCNVohYJfNk= -google.golang.org/genproto v0.0.0-20241118233622-e639e219e697/go.mod h1:JJrvXBWRZaFMxBufik1a4RpFw4HhgVtBBWQeQgUj2cc= -google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q= -google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6 h1:2duwAxN2+k0xLNpjnHTXoMUgnv6VPSp5fiqTuwSxjmI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250207221924-e9438ea467c6/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1373,8 +1286,6 @@ google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= -google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1435,12 +1346,12 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.32.2 h1:bZrMLEkgizC24G9eViHGOPbW+aRo9duEISRIJKfdJuw= -k8s.io/api v0.32.2/go.mod h1:hKlhk4x1sJyYnHENsrdCWw31FEmCijNGPJO5WzHiJ6Y= -k8s.io/apimachinery v0.32.2 h1:yoQBR9ZGkA6Rgmhbp/yuT9/g+4lxtsGYwW6dR6BDPLQ= -k8s.io/apimachinery v0.32.2/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= -k8s.io/client-go v0.32.2 h1:4dYCD4Nz+9RApM2b/3BtVvBHw54QjMFUl1OLcJG5yOA= -k8s.io/client-go v0.32.2/go.mod h1:fpZ4oJXclZ3r2nDOv+Ux3XcJutfrwjKTCHz2H3sww94= +k8s.io/api v0.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls= +k8s.io/api v0.32.3/go.mod h1:2wEDTXADtm/HA7CCMD8D8bK4yuBUptzaRhYcYEEYA3k= +k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U= +k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= +k8s.io/client-go v0.32.3 h1:RKPVltzopkSgHS7aS98QdscAgtgah/+zmpAogooIqVU= +k8s.io/client-go v0.32.3/go.mod h1:3v0+3k4IcT9bXTc4V2rt+d2ZPPG700Xy6Oi0Gdl2PaY= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 h1:hcha5B1kVACrLujCKLbr8XWMxCxzQx42DY8QKYJrDLg= @@ -1466,8 +1377,8 @@ modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= -modernc.org/sqlite v1.35.0 h1:yQps4fegMnZFdphtzlfQTCNBWtS0CZv48pRpW3RFHRw= -modernc.org/sqlite v1.35.0/go.mod h1:9cr2sicr7jIaWTBKQmAxQLfBv9LL0su4ZTEV+utt3ic= +modernc.org/sqlite v1.36.1 h1:bDa8BJUH4lg6EGkLbahKe/8QqoF8p9gArSc6fTqYhyQ= +modernc.org/sqlite v1.36.1/go.mod h1:7MPwH7Z6bREicF9ZVUR78P1IKuxfZ8mRIDHD0iD+8TU= modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= diff --git a/internal/app/scheduler.go b/internal/app/scheduler.go index 1b16ac32..c5e93c9f 100644 --- a/internal/app/scheduler.go +++ b/internal/app/scheduler.go @@ -3,6 +3,7 @@ package app import ( "sync" "time" + _ "time/tzdata" "github.com/pocketbase/pocketbase/tools/cron" ) diff --git a/internal/applicant/acme_user.go b/internal/applicant/acme_user.go index f8e80a03..107e417c 100644 --- a/internal/applicant/acme_user.go +++ b/internal/applicant/acme_user.go @@ -13,7 +13,7 @@ import ( "golang.org/x/sync/singleflight" "github.com/usual2970/certimate/internal/domain" - "github.com/usual2970/certimate/internal/pkg/utils/certs" + "github.com/usual2970/certimate/internal/pkg/utils/certutil" "github.com/usual2970/certimate/internal/repository" ) @@ -40,7 +40,7 @@ func newAcmeUser(ca, email string) (*acmeUser, error) { return nil, err } - keyPEM, err := certs.ConvertECPrivateKeyToPEM(key) + keyPEM, err := certutil.ConvertECPrivateKeyToPEM(key) if err != nil { return nil, err } @@ -64,7 +64,7 @@ func (u acmeUser) GetRegistration() *registration.Resource { } func (u *acmeUser) GetPrivateKey() crypto.PrivateKey { - rs, _ := certs.ParseECPrivateKeyFromPEM(u.privkey) + rs, _ := certutil.ParseECPrivateKeyFromPEM(u.privkey) return rs } diff --git a/internal/applicant/applicant.go b/internal/applicant/applicant.go index 5acc8800..ebe6208f 100644 --- a/internal/applicant/applicant.go +++ b/internal/applicant/applicant.go @@ -18,7 +18,7 @@ import ( "golang.org/x/time/rate" "github.com/usual2970/certimate/internal/domain" - uslices "github.com/usual2970/certimate/internal/pkg/utils/slices" + "github.com/usual2970/certimate/internal/pkg/utils/sliceutil" "github.com/usual2970/certimate/internal/repository" ) @@ -58,12 +58,12 @@ func NewWithApplyNode(node *domain.WorkflowNode) (Applicant, error) { nodeConfig := node.GetConfigForApply() options := &applicantOptions{ - Domains: uslices.Filter(strings.Split(nodeConfig.Domains, ";"), func(s string) bool { return s != "" }), + Domains: sliceutil.Filter(strings.Split(nodeConfig.Domains, ";"), func(s string) bool { return s != "" }), ContactEmail: nodeConfig.ContactEmail, Provider: domain.ApplyDNSProviderType(nodeConfig.Provider), ProviderApplyConfig: nodeConfig.ProviderConfig, KeyAlgorithm: nodeConfig.KeyAlgorithm, - Nameservers: uslices.Filter(strings.Split(nodeConfig.Nameservers, ";"), func(s string) bool { return s != "" }), + Nameservers: sliceutil.Filter(strings.Split(nodeConfig.Nameservers, ";"), func(s string) bool { return s != "" }), DnsPropagationTimeout: nodeConfig.DnsPropagationTimeout, DnsTTL: nodeConfig.DnsTTL, DisableFollowCNAME: nodeConfig.DisableFollowCNAME, diff --git a/internal/applicant/providers.go b/internal/applicant/providers.go index cc8a3cfd..dcfc1dde 100644 --- a/internal/applicant/providers.go +++ b/internal/applicant/providers.go @@ -15,6 +15,7 @@ import ( 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" + pDynv6 "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/dynv6" 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" @@ -29,7 +30,7 @@ import ( 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" + "github.com/usual2970/certimate/internal/pkg/utils/maputil" ) func createApplicant(options *applicantOptions) (challenge.Provider, error) { @@ -41,7 +42,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { case domain.ApplyDNSProviderTypeACMEHttpReq: { access := domain.AccessConfigForACMEHttpReq{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -58,7 +59,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { case domain.ApplyDNSProviderTypeAliyun, domain.ApplyDNSProviderTypeAliyunDNS: { access := domain.AccessConfigForAliyun{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -74,15 +75,15 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { case domain.ApplyDNSProviderTypeAWS, domain.ApplyDNSProviderTypeAWSRoute53: { access := domain.AccessConfigForAWS{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } applicant, err := pAWSRoute53.NewChallengeProvider(&pAWSRoute53.ChallengeProviderConfig{ AccessKeyId: access.AccessKeyId, SecretAccessKey: access.SecretAccessKey, - Region: maps.GetValueAsString(options.ProviderApplyConfig, "region"), - HostedZoneId: maps.GetValueAsString(options.ProviderApplyConfig, "hostedZoneId"), + Region: maputil.GetString(options.ProviderApplyConfig, "region"), + HostedZoneId: maputil.GetString(options.ProviderApplyConfig, "hostedZoneId"), DnsPropagationTimeout: options.DnsPropagationTimeout, DnsTTL: options.DnsTTL, }) @@ -92,7 +93,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { case domain.ApplyDNSProviderTypeAzure, domain.ApplyDNSProviderTypeAzureDNS: { access := domain.AccessConfigForAzure{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -110,7 +111,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { case domain.ApplyDNSProviderTypeBaiduCloud, domain.ApplyDNSProviderTypeBaiduCloudDNS: { access := domain.AccessConfigForBaiduCloud{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -126,7 +127,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { case domain.ApplyDNSProviderTypeCloudflare: { access := domain.AccessConfigForCloudflare{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -141,7 +142,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { case domain.ApplyDNSProviderTypeClouDNS: { access := domain.AccessConfigForClouDNS{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -157,7 +158,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { case domain.ApplyDNSProviderTypeCMCCCloud: { access := domain.AccessConfigForCMCCCloud{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -173,7 +174,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { case domain.ApplyDNSProviderTypeDNSLA: { access := domain.AccessConfigForDNSLA{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -186,10 +187,25 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { return applicant, err } + case domain.ApplyDNSProviderTypeDynv6: + { + access := domain.AccessConfigForDynv6{} + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + applicant, err := pDynv6.NewChallengeProvider(&pDynv6.ChallengeProviderConfig{ + HttpToken: access.HttpToken, + DnsPropagationTimeout: options.DnsPropagationTimeout, + DnsTTL: options.DnsTTL, + }) + return applicant, err + } + case domain.ApplyDNSProviderTypeGcore: { access := domain.AccessConfigForGcore{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -204,7 +220,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { case domain.ApplyDNSProviderTypeGname: { access := domain.AccessConfigForGname{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -220,7 +236,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { case domain.ApplyDNSProviderTypeGoDaddy: { access := domain.AccessConfigForGoDaddy{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -236,14 +252,14 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { case domain.ApplyDNSProviderTypeHuaweiCloud, domain.ApplyDNSProviderTypeHuaweiCloudDNS: { access := domain.AccessConfigForHuaweiCloud{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } applicant, err := pHuaweiCloud.NewChallengeProvider(&pHuaweiCloud.ChallengeProviderConfig{ AccessKeyId: access.AccessKeyId, SecretAccessKey: access.SecretAccessKey, - Region: maps.GetValueAsString(options.ProviderApplyConfig, "region"), + Region: maputil.GetString(options.ProviderApplyConfig, "region"), DnsPropagationTimeout: options.DnsPropagationTimeout, DnsTTL: options.DnsTTL, }) @@ -253,14 +269,14 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { case domain.ApplyDNSProviderTypeJDCloud, domain.ApplyDNSProviderTypeJDCloudDNS: { access := domain.AccessConfigForJDCloud{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.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"), + RegionId: maputil.GetString(options.ProviderApplyConfig, "region_id"), DnsPropagationTimeout: options.DnsPropagationTimeout, DnsTTL: options.DnsTTL, }) @@ -270,7 +286,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { case domain.ApplyDNSProviderTypeNamecheap: { access := domain.AccessConfigForNamecheap{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -286,7 +302,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { case domain.ApplyDNSProviderTypeNameDotCom: { access := domain.AccessConfigForNameDotCom{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -302,7 +318,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { case domain.ApplyDNSProviderTypeNameSilo: { access := domain.AccessConfigForNameSilo{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -317,7 +333,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { case domain.ApplyDNSProviderTypeNS1: { access := domain.AccessConfigForNS1{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -332,7 +348,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { case domain.ApplyDNSProviderTypePowerDNS: { access := domain.AccessConfigForPowerDNS{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -348,7 +364,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { case domain.ApplyDNSProviderTypeRainYun: { access := domain.AccessConfigForRainYun{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -363,7 +379,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { case domain.ApplyDNSProviderTypeTencentCloud, domain.ApplyDNSProviderTypeTencentCloudDNS: { access := domain.AccessConfigForTencentCloud{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -379,7 +395,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { case domain.ApplyDNSProviderTypeVolcEngine, domain.ApplyDNSProviderTypeVolcEngineDNS: { access := domain.AccessConfigForVolcEngine{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -395,7 +411,7 @@ func createApplicant(options *applicantOptions) (challenge.Provider, error) { case domain.ApplyDNSProviderTypeWestcn: { access := domain.AccessConfigForWestcn{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } diff --git a/internal/certificate/service.go b/internal/certificate/service.go index adcb8b97..f8874f2d 100644 --- a/internal/certificate/service.go +++ b/internal/certificate/service.go @@ -11,11 +11,13 @@ import ( "time" "github.com/go-acme/lego/v4/certcrypto" + "github.com/pocketbase/dbx" + "github.com/usual2970/certimate/internal/app" "github.com/usual2970/certimate/internal/domain" "github.com/usual2970/certimate/internal/domain/dtos" "github.com/usual2970/certimate/internal/notify" - "github.com/usual2970/certimate/internal/pkg/utils/certs" + "github.com/usual2970/certimate/internal/pkg/utils/certutil" "github.com/usual2970/certimate/internal/repository" ) @@ -27,21 +29,29 @@ const ( type certificateRepository interface { ListExpireSoon(ctx context.Context) ([]*domain.Certificate, error) GetById(ctx context.Context, id string) (*domain.Certificate, error) + DeleteWhere(ctx context.Context, exprs ...dbx.Expression) (int, error) +} + +type settingsRepository interface { + GetByName(ctx context.Context, name string) (*domain.Settings, error) } type CertificateService struct { - certRepo certificateRepository + certificateRepo certificateRepository + settingsRepo settingsRepository } -func NewCertificateService(certRepo certificateRepository) *CertificateService { +func NewCertificateService(certificateRepo certificateRepository, settingsRepo settingsRepository) *CertificateService { return &CertificateService{ - certRepo: certRepo, + certificateRepo: certificateRepo, + settingsRepo: settingsRepo, } } func (s *CertificateService) InitSchedule(ctx context.Context) error { + // 每日发送过期证书提醒 app.GetScheduler().MustAdd("certificateExpireSoonNotify", "0 0 * * *", func() { - certificates, err := s.certRepo.ListExpireSoon(context.Background()) + certificates, err := s.certificateRepo.ListExpireSoon(context.Background()) if err != nil { app.GetLogger().Error("failed to get certificates which expire soon", "err", err) return @@ -56,11 +66,37 @@ func (s *CertificateService) InitSchedule(ctx context.Context) error { app.GetLogger().Error("failed to send notification", "err", err) } }) + + // 每日清理过期证书 + app.GetScheduler().MustAdd("certificateExpiredCleanup", "0 0 * * *", func() { + settings, err := s.settingsRepo.GetByName(ctx, "persistence") + if err != nil { + app.GetLogger().Error("failed to get persistence settings", "err", err) + return + } + + var settingsContent *domain.PersistenceSettingsContent + json.Unmarshal([]byte(settings.Content), &settingsContent) + if settingsContent != nil && settingsContent.ExpiredCertificatesMaxDaysRetention != 0 { + ret, err := s.certificateRepo.DeleteWhere( + context.Background(), + dbx.NewExp(fmt.Sprintf("expireAt 0 { + app.GetLogger().Info(fmt.Sprintf("cleanup %d expired certificates", ret)) + } + } + }) + return nil } func (s *CertificateService) ArchiveFile(ctx context.Context, req *dtos.CertificateArchiveFileReq) (*dtos.CertificateArchiveFileResp, error) { - certificate, err := s.certRepo.GetById(ctx, req.CertificateId) + certificate, err := s.certificateRepo.GetById(ctx, req.CertificateId) if err != nil { return nil, err } @@ -109,7 +145,7 @@ func (s *CertificateService) ArchiveFile(ctx context.Context, req *dtos.Certific { const pfxPassword = "certimate" - certPFX, err := certs.TransformCertificateFromPEMToPFX(certificate.Certificate, certificate.PrivateKey, pfxPassword) + certPFX, err := certutil.TransformCertificateFromPEMToPFX(certificate.Certificate, certificate.PrivateKey, pfxPassword) if err != nil { return nil, err } @@ -147,7 +183,7 @@ func (s *CertificateService) ArchiveFile(ctx context.Context, req *dtos.Certific { const jksPassword = "certimate" - certJKS, err := certs.TransformCertificateFromPEMToJKS(certificate.Certificate, certificate.PrivateKey, jksPassword, jksPassword, jksPassword) + certJKS, err := certutil.TransformCertificateFromPEMToJKS(certificate.Certificate, certificate.PrivateKey, jksPassword, jksPassword, jksPassword) if err != nil { return nil, err } @@ -187,7 +223,7 @@ func (s *CertificateService) ArchiveFile(ctx context.Context, req *dtos.Certific } func (s *CertificateService) ValidateCertificate(ctx context.Context, req *dtos.CertificateValidateCertificateReq) (*dtos.CertificateValidateCertificateResp, error) { - certX509, err := certs.ParseCertificateFromPEM(req.Certificate) + certX509, err := certutil.ParseCertificateFromPEM(req.Certificate) if err != nil { return nil, err } else if time.Now().After(certX509.NotAfter) { diff --git a/internal/deployer/deployer.go b/internal/deployer/deployer.go index f95442a6..36e92866 100644 --- a/internal/deployer/deployer.go +++ b/internal/deployer/deployer.go @@ -3,14 +3,16 @@ package deployer import ( "context" "fmt" + "log/slog" "github.com/usual2970/certimate/internal/domain" "github.com/usual2970/certimate/internal/pkg/core/deployer" - "github.com/usual2970/certimate/internal/pkg/core/logger" "github.com/usual2970/certimate/internal/repository" ) type Deployer interface { + SetLogger(*slog.Logger) + Deploy(ctx context.Context) error } @@ -52,7 +54,6 @@ func NewWithDeployNode(node *domain.WorkflowNode, certdata struct { } return &proxyDeployer{ - logger: logger.NewNilLogger(), deployer: deployer, deployCertificate: certdata.Certificate, deployPrivateKey: certdata.PrivateKey, @@ -61,12 +62,19 @@ func NewWithDeployNode(node *domain.WorkflowNode, certdata struct { // TODO: 暂时使用代理模式以兼容之前版本代码,后续重新实现此处逻辑 type proxyDeployer struct { - logger logger.Logger deployer deployer.Deployer deployCertificate string deployPrivateKey string } +func (d *proxyDeployer) SetLogger(logger *slog.Logger) { + if logger == nil { + panic("logger is nil") + } + + d.deployer.WithLogger(logger) +} + func (d *proxyDeployer) Deploy(ctx context.Context) error { _, err := d.deployer.Deploy(ctx, d.deployCertificate, d.deployPrivateKey) return err diff --git a/internal/deployer/providers.go b/internal/deployer/providers.go index 5c785780..a83fb681 100644 --- a/internal/deployer/providers.go +++ b/internal/deployer/providers.go @@ -9,6 +9,7 @@ import ( p1PanelConsole "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/1panel-console" p1PanelSite "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/1panel-site" pAliyunALB "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-alb" + pAliyunCAS "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-cas" 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" @@ -20,7 +21,9 @@ import ( pAliyunOSS "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-oss" pAliyunVOD "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-vod" pAliyunWAF "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aliyun-waf" + pAWSACM "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aws-acm" pAWSCloudFront "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/aws-cloudfront" + pAzureKeyVault "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/azure-keyvault" 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" @@ -51,11 +54,13 @@ import ( pTencentCloudECDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-ecdn" pTencentCloudEO "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-eo" pTencentCloudSCF "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-scf" + pTencentCloudSSL "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-ssl" pTencentCloudSSLDeploy "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-ssl-deploy" 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" + pUpyunCDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/upyun-cdn" 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" @@ -63,8 +68,8 @@ import ( 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" + "github.com/usual2970/certimate/internal/pkg/utils/maputil" + "github.com/usual2970/certimate/internal/pkg/utils/sliceutil" ) func createDeployer(options *deployerOptions) (deployer.Deployer, error) { @@ -76,7 +81,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { case domain.DeployProviderType1PanelConsole, domain.DeployProviderType1PanelSite: { access := domain.AccessConfigFor1Panel{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -86,7 +91,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { ApiUrl: access.ApiUrl, ApiKey: access.ApiKey, AllowInsecureConnections: access.AllowInsecureConnections, - AutoRestart: maps.GetValueAsBool(options.ProviderDeployConfig, "autoRestart"), + AutoRestart: maputil.GetBool(options.ProviderDeployConfig, "autoRestart"), }) return deployer, err @@ -95,7 +100,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { ApiUrl: access.ApiUrl, ApiKey: access.ApiKey, AllowInsecureConnections: access.AllowInsecureConnections, - WebsiteId: maps.GetValueAsInt64(options.ProviderDeployConfig, "websiteId"), + WebsiteId: maputil.GetInt64(options.ProviderDeployConfig, "websiteId"), }) return deployer, err @@ -104,10 +109,10 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { } } - case domain.DeployProviderTypeAliyunALB, domain.DeployProviderTypeAliyunCASDeploy, domain.DeployProviderTypeAliyunCDN, domain.DeployProviderTypeAliyunCLB, domain.DeployProviderTypeAliyunDCDN, domain.DeployProviderTypeAliyunESA, domain.DeployProviderTypeAliyunFC, domain.DeployProviderTypeAliyunLive, domain.DeployProviderTypeAliyunNLB, domain.DeployProviderTypeAliyunOSS, domain.DeployProviderTypeAliyunVOD, domain.DeployProviderTypeAliyunWAF: + case domain.DeployProviderTypeAliyunALB, domain.DeployProviderTypeAliyunCAS, domain.DeployProviderTypeAliyunCASDeploy, domain.DeployProviderTypeAliyunCDN, domain.DeployProviderTypeAliyunCLB, domain.DeployProviderTypeAliyunDCDN, domain.DeployProviderTypeAliyunESA, domain.DeployProviderTypeAliyunFC, domain.DeployProviderTypeAliyunLive, domain.DeployProviderTypeAliyunNLB, domain.DeployProviderTypeAliyunOSS, domain.DeployProviderTypeAliyunVOD, domain.DeployProviderTypeAliyunWAF: { access := domain.AccessConfigForAliyun{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -116,11 +121,19 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pAliyunALB.NewDeployer(&pAliyunALB.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.AccessKeySecret, - Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), - 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"), + Region: maputil.GetString(options.ProviderDeployConfig, "region"), + ResourceType: pAliyunALB.ResourceType(maputil.GetString(options.ProviderDeployConfig, "resourceType")), + LoadbalancerId: maputil.GetString(options.ProviderDeployConfig, "loadbalancerId"), + ListenerId: maputil.GetString(options.ProviderDeployConfig, "listenerId"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), + }) + return deployer, err + + case domain.DeployProviderTypeAliyunCAS: + deployer, err := pAliyunCAS.NewDeployer(&pAliyunCAS.DeployerConfig{ + AccessKeyId: access.AccessKeyId, + AccessKeySecret: access.AccessKeySecret, + Region: maputil.GetString(options.ProviderDeployConfig, "region"), }) return deployer, err @@ -128,9 +141,9 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { 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 != "" }), + Region: maputil.GetString(options.ProviderDeployConfig, "region"), + ResourceIds: sliceutil.Filter(strings.Split(maputil.GetString(options.ProviderDeployConfig, "resourceIds"), ";"), func(s string) bool { return s != "" }), + ContactIds: sliceutil.Filter(strings.Split(maputil.GetString(options.ProviderDeployConfig, "contactIds"), ";"), func(s string) bool { return s != "" }), }) return deployer, err @@ -138,7 +151,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pAliyunCDN.NewDeployer(&pAliyunCDN.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.AccessKeySecret, - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -146,11 +159,11 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pAliyunCLB.NewDeployer(&pAliyunCLB.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.AccessKeySecret, - Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), - 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"), + Region: maputil.GetString(options.ProviderDeployConfig, "region"), + ResourceType: pAliyunCLB.ResourceType(maputil.GetString(options.ProviderDeployConfig, "resourceType")), + LoadbalancerId: maputil.GetString(options.ProviderDeployConfig, "loadbalancerId"), + ListenerPort: maputil.GetOrDefaultInt32(options.ProviderDeployConfig, "listenerPort", 443), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -158,7 +171,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pAliyunDCDN.NewDeployer(&pAliyunDCDN.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.AccessKeySecret, - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -166,8 +179,8 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pAliyunESA.NewDeployer(&pAliyunESA.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.AccessKeySecret, - Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), - SiteId: maps.GetValueAsInt64(options.ProviderDeployConfig, "siteId"), + Region: maputil.GetString(options.ProviderDeployConfig, "region"), + SiteId: maputil.GetInt64(options.ProviderDeployConfig, "siteId"), }) return deployer, err @@ -175,9 +188,9 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pAliyunFC.NewDeployer(&pAliyunFC.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.AccessKeySecret, - Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), - ServiceVersion: maps.GetValueAsString(options.ProviderDeployConfig, "serviceVersion"), - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + Region: maputil.GetString(options.ProviderDeployConfig, "region"), + ServiceVersion: maputil.GetOrDefaultString(options.ProviderDeployConfig, "serviceVersion", "3.0"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -185,8 +198,8 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pAliyunLive.NewDeployer(&pAliyunLive.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.AccessKeySecret, - Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + Region: maputil.GetString(options.ProviderDeployConfig, "region"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -194,10 +207,10 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pAliyunNLB.NewDeployer(&pAliyunNLB.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.AccessKeySecret, - Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), - ResourceType: pAliyunNLB.ResourceType(maps.GetValueAsString(options.ProviderDeployConfig, "resourceType")), - LoadbalancerId: maps.GetValueAsString(options.ProviderDeployConfig, "loadbalancerId"), - ListenerId: maps.GetValueAsString(options.ProviderDeployConfig, "listenerId"), + Region: maputil.GetString(options.ProviderDeployConfig, "region"), + ResourceType: pAliyunNLB.ResourceType(maputil.GetString(options.ProviderDeployConfig, "resourceType")), + LoadbalancerId: maputil.GetString(options.ProviderDeployConfig, "loadbalancerId"), + ListenerId: maputil.GetString(options.ProviderDeployConfig, "listenerId"), }) return deployer, err @@ -205,9 +218,9 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { 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"), + Region: maputil.GetString(options.ProviderDeployConfig, "region"), + Bucket: maputil.GetString(options.ProviderDeployConfig, "bucket"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -215,8 +228,8 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pAliyunVOD.NewDeployer(&pAliyunVOD.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.AccessKeySecret, - Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + Region: maputil.GetString(options.ProviderDeployConfig, "region"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -224,9 +237,10 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pAliyunWAF.NewDeployer(&pAliyunWAF.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.AccessKeySecret, - Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), - InstanceId: maps.GetValueAsString(options.ProviderDeployConfig, "instanceId"), - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + Region: maputil.GetString(options.ProviderDeployConfig, "region"), + ServiceVersion: maputil.GetOrDefaultString(options.ProviderDeployConfig, "serviceVersion", "3.0"), + InstanceId: maputil.GetString(options.ProviderDeployConfig, "instanceId"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -235,20 +249,51 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { } } - case domain.DeployProviderTypeAWSCloudFront: + case domain.DeployProviderTypeAWSACM, domain.DeployProviderTypeAWSCloudFront: { access := domain.AccessConfigForAWS{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } switch options.Provider { + case domain.DeployProviderTypeAWSACM: + deployer, err := pAWSACM.NewDeployer(&pAWSACM.DeployerConfig{ + AccessKeyId: access.AccessKeyId, + SecretAccessKey: access.SecretAccessKey, + Region: maputil.GetString(options.ProviderDeployConfig, "region"), + }) + return deployer, err + case domain.DeployProviderTypeAWSCloudFront: deployer, err := pAWSCloudFront.NewDeployer(&pAWSCloudFront.DeployerConfig{ AccessKeyId: access.AccessKeyId, SecretAccessKey: access.SecretAccessKey, - Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), - DistributionId: maps.GetValueAsString(options.ProviderDeployConfig, "distributionId"), + Region: maputil.GetString(options.ProviderDeployConfig, "region"), + DistributionId: maputil.GetString(options.ProviderDeployConfig, "distributionId"), + }) + return deployer, err + + default: + break + } + } + + case domain.DeployProviderTypeAzureKeyVault: + { + access := domain.AccessConfigForAzure{} + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + switch options.Provider { + case domain.DeployProviderTypeAzureKeyVault: + deployer, err := pAzureKeyVault.NewDeployer(&pAzureKeyVault.DeployerConfig{ + TenantId: access.TenantId, + ClientId: access.ClientId, + ClientSecret: access.ClientSecret, + CloudName: access.CloudName, + KeyVaultName: maputil.GetString(options.ProviderDeployConfig, "keyvaultName"), }) return deployer, err @@ -260,7 +305,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { case domain.DeployProviderTypeBaiduCloudCDN: { access := domain.AccessConfigForBaiduCloud{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -269,7 +314,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pBaiduCloudCDN.NewDeployer(&pBaiduCloudCDN.DeployerConfig{ AccessKeyId: access.AccessKeyId, SecretAccessKey: access.SecretAccessKey, - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -281,7 +326,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { case domain.DeployProviderTypeBaishanCDN: { access := domain.AccessConfigForBaishan{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -289,7 +334,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { case domain.DeployProviderTypeBaishanCDN: deployer, err := pBaishanCDN.NewDeployer(&pBaishanCDN.DeployerConfig{ ApiToken: access.ApiToken, - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -301,7 +346,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { case domain.DeployProviderTypeBaotaPanelConsole, domain.DeployProviderTypeBaotaPanelSite: { access := domain.AccessConfigForBaotaPanel{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -311,7 +356,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { ApiUrl: access.ApiUrl, ApiKey: access.ApiKey, AllowInsecureConnections: access.AllowInsecureConnections, - AutoRestart: maps.GetValueAsBool(options.ProviderDeployConfig, "autoRestart"), + AutoRestart: maputil.GetBool(options.ProviderDeployConfig, "autoRestart"), }) return deployer, err @@ -320,9 +365,9 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { ApiUrl: access.ApiUrl, ApiKey: access.ApiKey, AllowInsecureConnections: access.AllowInsecureConnections, - 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 != "" }), + SiteType: maputil.GetOrDefaultString(options.ProviderDeployConfig, "siteType", "other"), + SiteName: maputil.GetString(options.ProviderDeployConfig, "siteName"), + SiteNames: sliceutil.Filter(strings.Split(maputil.GetString(options.ProviderDeployConfig, "siteNames"), ";"), func(s string) bool { return s != "" }), }) return deployer, err @@ -334,7 +379,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { case domain.DeployProviderTypeBytePlusCDN: { access := domain.AccessConfigForBytePlus{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -343,7 +388,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pBytePlusCDN.NewDeployer(&pBytePlusCDN.DeployerConfig{ AccessKey: access.AccessKey, SecretKey: access.SecretKey, - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -355,7 +400,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { case domain.DeployProviderTypeCacheFly: { access := domain.AccessConfigForCacheFly{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -368,7 +413,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { case domain.DeployProviderTypeCdnfly: { access := domain.AccessConfigForCdnfly{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -376,9 +421,9 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { 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"), + ResourceType: pCdnfly.ResourceType(maputil.GetString(options.ProviderDeployConfig, "resourceType")), + SiteId: maputil.GetString(options.ProviderDeployConfig, "siteId"), + CertificateId: maputil.GetString(options.ProviderDeployConfig, "certificateId"), }) return deployer, err } @@ -386,14 +431,14 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { case domain.DeployProviderTypeDogeCloudCDN: { access := domain.AccessConfigForDogeCloud{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } deployer, err := pDogeCDN.NewDeployer(&pDogeCDN.DeployerConfig{ AccessKey: access.AccessKey, SecretKey: access.SecretKey, - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err } @@ -401,14 +446,14 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { case domain.DeployProviderTypeEdgioApplications: { access := domain.AccessConfigForEdgio{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } deployer, err := pEdgioApplications.NewDeployer(&pEdgioApplications.DeployerConfig{ ClientId: access.ClientId, ClientSecret: access.ClientSecret, - EnvironmentId: maps.GetValueAsString(options.ProviderDeployConfig, "environmentId"), + EnvironmentId: maputil.GetString(options.ProviderDeployConfig, "environmentId"), }) return deployer, err } @@ -416,7 +461,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { case domain.DeployProviderTypeGcoreCDN: { access := domain.AccessConfigForGcore{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -424,7 +469,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { case domain.DeployProviderTypeGcoreCDN: deployer, err := pGcoreCDN.NewDeployer(&pGcoreCDN.DeployerConfig{ ApiToken: access.ApiToken, - ResourceId: maps.GetValueAsInt64(options.ProviderDeployConfig, "resourceId"), + ResourceId: maputil.GetInt64(options.ProviderDeployConfig, "resourceId"), }) return deployer, err @@ -436,7 +481,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { case domain.DeployProviderTypeHuaweiCloudCDN, domain.DeployProviderTypeHuaweiCloudELB, domain.DeployProviderTypeHuaweiCloudWAF: { access := domain.AccessConfigForHuaweiCloud{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -445,8 +490,8 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pHuaweiCloudCDN.NewDeployer(&pHuaweiCloudCDN.DeployerConfig{ AccessKeyId: access.AccessKeyId, SecretAccessKey: access.SecretAccessKey, - Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + Region: maputil.GetString(options.ProviderDeployConfig, "region"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -454,11 +499,11 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pHuaweiCloudELB.NewDeployer(&pHuaweiCloudELB.DeployerConfig{ AccessKeyId: access.AccessKeyId, SecretAccessKey: access.SecretAccessKey, - Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), - 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"), + Region: maputil.GetString(options.ProviderDeployConfig, "region"), + ResourceType: pHuaweiCloudELB.ResourceType(maputil.GetString(options.ProviderDeployConfig, "resourceType")), + CertificateId: maputil.GetString(options.ProviderDeployConfig, "certificateId"), + LoadbalancerId: maputil.GetString(options.ProviderDeployConfig, "loadbalancerId"), + ListenerId: maputil.GetString(options.ProviderDeployConfig, "listenerId"), }) return deployer, err @@ -466,10 +511,10 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { 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"), + Region: maputil.GetString(options.ProviderDeployConfig, "region"), + ResourceType: pHuaweiCloudWAF.ResourceType(maputil.GetString(options.ProviderDeployConfig, "resourceType")), + CertificateId: maputil.GetString(options.ProviderDeployConfig, "certificateId"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -481,7 +526,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { case domain.DeployProviderTypeJDCloudALB, domain.DeployProviderTypeJDCloudCDN, domain.DeployProviderTypeJDCloudLive, domain.DeployProviderTypeJDCloudVOD: { access := domain.AccessConfigForJDCloud{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -490,10 +535,10 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { 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"), + RegionId: maputil.GetString(options.ProviderDeployConfig, "regionId"), + ResourceType: pJDCloudALB.ResourceType(maputil.GetString(options.ProviderDeployConfig, "resourceType")), + LoadbalancerId: maputil.GetString(options.ProviderDeployConfig, "loadbalancerId"), + ListenerId: maputil.GetString(options.ProviderDeployConfig, "listenerId"), }) return deployer, err @@ -501,7 +546,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pJDCloudCDN.NewDeployer(&pJDCloudCDN.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.AccessKeySecret, - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -509,7 +554,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pJDCloudLive.NewDeployer(&pJDCloudLive.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.AccessKeySecret, - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -517,7 +562,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pJDCloudVOD.NewDeployer(&pJDCloudVOD.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.AccessKeySecret, - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -529,16 +574,16 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { case domain.DeployProviderTypeLocal: { 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: 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"), + ShellEnv: pLocal.ShellEnvType(maputil.GetString(options.ProviderDeployConfig, "shellEnv")), + PreCommand: maputil.GetString(options.ProviderDeployConfig, "preCommand"), + PostCommand: maputil.GetString(options.ProviderDeployConfig, "postCommand"), + OutputFormat: pLocal.OutputFormatType(maputil.GetOrDefaultString(options.ProviderDeployConfig, "format", string(pLocal.OUTPUT_FORMAT_PEM))), + OutputCertPath: maputil.GetString(options.ProviderDeployConfig, "certPath"), + OutputKeyPath: maputil.GetString(options.ProviderDeployConfig, "keyPath"), + PfxPassword: maputil.GetString(options.ProviderDeployConfig, "pfxPassword"), + JksAlias: maputil.GetString(options.ProviderDeployConfig, "jksAlias"), + JksKeypass: maputil.GetString(options.ProviderDeployConfig, "jksKeypass"), + JksStorepass: maputil.GetString(options.ProviderDeployConfig, "jksStorepass"), }) return deployer, err } @@ -546,34 +591,34 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { case domain.DeployProviderTypeKubernetesSecret: { access := domain.AccessConfigForKubernetes{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } 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"), + Namespace: maputil.GetOrDefaultString(options.ProviderDeployConfig, "namespace", "default"), + SecretName: maputil.GetString(options.ProviderDeployConfig, "secretName"), + SecretType: maputil.GetOrDefaultString(options.ProviderDeployConfig, "secretType", "kubernetes.io/tls"), + SecretDataKeyForCrt: maputil.GetOrDefaultString(options.ProviderDeployConfig, "secretDataKeyForCrt", "tls.crt"), + SecretDataKeyForKey: maputil.GetOrDefaultString(options.ProviderDeployConfig, "secretDataKeyForKey", "tls.key"), }) return deployer, err } - case domain.DeployProviderTypeQiniuCDN, domain.DeployProviderTypeQiniuPili: + case domain.DeployProviderTypeQiniuCDN, domain.DeployProviderTypeQiniuKodo, domain.DeployProviderTypeQiniuPili: { access := domain.AccessConfigForQiniu{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } switch options.Provider { - case domain.DeployProviderTypeQiniuCDN: + case domain.DeployProviderTypeQiniuCDN, domain.DeployProviderTypeQiniuKodo: deployer, err := pQiniuCDN.NewDeployer(&pQiniuCDN.DeployerConfig{ AccessKey: access.AccessKey, SecretKey: access.SecretKey, - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -581,8 +626,8 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pQiniuPili.NewDeployer(&pQiniuPili.DeployerConfig{ AccessKey: access.AccessKey, SecretKey: access.SecretKey, - Hub: maps.GetValueAsString(options.ProviderDeployConfig, "hub"), - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + Hub: maputil.GetString(options.ProviderDeployConfig, "hub"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -594,7 +639,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { case domain.DeployProviderTypeSafeLine: { access := domain.AccessConfigForSafeLine{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -602,8 +647,8 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { ApiUrl: access.ApiUrl, ApiToken: access.ApiToken, AllowInsecureConnections: access.AllowInsecureConnections, - ResourceType: pSafeLine.ResourceType(maps.GetValueAsString(options.ProviderDeployConfig, "resourceType")), - CertificateId: maps.GetValueAsInt32(options.ProviderDeployConfig, "certificateId"), + ResourceType: pSafeLine.ResourceType(maputil.GetString(options.ProviderDeployConfig, "resourceType")), + CertificateId: maputil.GetInt32(options.ProviderDeployConfig, "certificateId"), }) return deployer, err } @@ -611,7 +656,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { case domain.DeployProviderTypeSSH: { access := domain.AccessConfigForSSH{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -622,24 +667,24 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { SshPassword: access.Password, SshKey: access.Key, SshKeyPassphrase: access.KeyPassphrase, - UseSCP: maps.GetValueAsBool(options.ProviderDeployConfig, "useSCP"), - PreCommand: maps.GetValueAsString(options.ProviderDeployConfig, "preCommand"), - PostCommand: maps.GetValueAsString(options.ProviderDeployConfig, "postCommand"), - 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"), + UseSCP: maputil.GetBool(options.ProviderDeployConfig, "useSCP"), + PreCommand: maputil.GetString(options.ProviderDeployConfig, "preCommand"), + PostCommand: maputil.GetString(options.ProviderDeployConfig, "postCommand"), + OutputFormat: pSSH.OutputFormatType(maputil.GetOrDefaultString(options.ProviderDeployConfig, "format", string(pSSH.OUTPUT_FORMAT_PEM))), + OutputCertPath: maputil.GetString(options.ProviderDeployConfig, "certPath"), + OutputKeyPath: maputil.GetString(options.ProviderDeployConfig, "keyPath"), + PfxPassword: maputil.GetString(options.ProviderDeployConfig, "pfxPassword"), + JksAlias: maputil.GetString(options.ProviderDeployConfig, "jksAlias"), + JksKeypass: maputil.GetString(options.ProviderDeployConfig, "jksKeypass"), + JksStorepass: maputil.GetString(options.ProviderDeployConfig, "jksStorepass"), }) return deployer, err } - case domain.DeployProviderTypeTencentCloudCDN, domain.DeployProviderTypeTencentCloudCLB, domain.DeployProviderTypeTencentCloudCOS, domain.DeployProviderTypeTencentCloudCSS, domain.DeployProviderTypeTencentCloudECDN, domain.DeployProviderTypeTencentCloudEO, domain.DeployProviderTypeTencentCloudSCF, domain.DeployProviderTypeTencentCloudSSLDeploy, domain.DeployProviderTypeTencentCloudVOD, domain.DeployProviderTypeTencentCloudWAF: + case domain.DeployProviderTypeTencentCloudCDN, domain.DeployProviderTypeTencentCloudCLB, domain.DeployProviderTypeTencentCloudCOS, domain.DeployProviderTypeTencentCloudCSS, domain.DeployProviderTypeTencentCloudECDN, domain.DeployProviderTypeTencentCloudEO, domain.DeployProviderTypeTencentCloudSCF, domain.DeployProviderTypeTencentCloudSSL, domain.DeployProviderTypeTencentCloudSSLDeploy, domain.DeployProviderTypeTencentCloudVOD, domain.DeployProviderTypeTencentCloudWAF: { access := domain.AccessConfigForTencentCloud{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -648,7 +693,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pTencentCloudCDN.NewDeployer(&pTencentCloudCDN.DeployerConfig{ SecretId: access.SecretId, SecretKey: access.SecretKey, - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -656,11 +701,11 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pTencentCloudCLB.NewDeployer(&pTencentCloudCLB.DeployerConfig{ SecretId: access.SecretId, SecretKey: access.SecretKey, - Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), - 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"), + Region: maputil.GetString(options.ProviderDeployConfig, "region"), + ResourceType: pTencentCloudCLB.ResourceType(maputil.GetString(options.ProviderDeployConfig, "resourceType")), + LoadbalancerId: maputil.GetString(options.ProviderDeployConfig, "loadbalancerId"), + ListenerId: maputil.GetString(options.ProviderDeployConfig, "listenerId"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -668,9 +713,9 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { 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"), + Region: maputil.GetString(options.ProviderDeployConfig, "region"), + Bucket: maputil.GetString(options.ProviderDeployConfig, "bucket"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -678,7 +723,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pTencentCloudCSS.NewDeployer(&pTencentCloudCSS.DeployerConfig{ SecretId: access.SecretId, SecretKey: access.SecretKey, - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -686,7 +731,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pTencentCloudECDN.NewDeployer(&pTencentCloudECDN.DeployerConfig{ SecretId: access.SecretId, SecretKey: access.SecretKey, - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -694,8 +739,8 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pTencentCloudEO.NewDeployer(&pTencentCloudEO.DeployerConfig{ SecretId: access.SecretId, SecretKey: access.SecretKey, - ZoneId: maps.GetValueAsString(options.ProviderDeployConfig, "zoneId"), - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + ZoneId: maputil.GetString(options.ProviderDeployConfig, "zoneId"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -703,8 +748,15 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pTencentCloudSCF.NewDeployer(&pTencentCloudSCF.DeployerConfig{ SecretId: access.SecretId, SecretKey: access.SecretKey, - Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + Region: maputil.GetString(options.ProviderDeployConfig, "region"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), + }) + return deployer, err + + case domain.DeployProviderTypeTencentCloudSSL: + deployer, err := pTencentCloudSSL.NewDeployer(&pTencentCloudSSL.DeployerConfig{ + SecretId: access.SecretId, + SecretKey: access.SecretKey, }) return deployer, err @@ -712,9 +764,9 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { 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 != "" }), + Region: maputil.GetString(options.ProviderDeployConfig, "region"), + ResourceType: maputil.GetString(options.ProviderDeployConfig, "resourceType"), + ResourceIds: sliceutil.Filter(strings.Split(maputil.GetString(options.ProviderDeployConfig, "resourceIds"), ";"), func(s string) bool { return s != "" }), }) return deployer, err @@ -722,8 +774,8 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pTencentCloudVOD.NewDeployer(&pTencentCloudVOD.DeployerConfig{ SecretId: access.SecretId, SecretKey: access.SecretKey, - SubAppId: maps.GetValueAsInt64(options.ProviderDeployConfig, "subAppId"), - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + SubAppId: maputil.GetInt64(options.ProviderDeployConfig, "subAppId"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -731,9 +783,9 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { 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"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), + DomainId: maputil.GetString(options.ProviderDeployConfig, "domainId"), + InstanceId: maputil.GetString(options.ProviderDeployConfig, "instanceId"), }) return deployer, err @@ -745,7 +797,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { case domain.DeployProviderTypeUCloudUCDN, domain.DeployProviderTypeUCloudUS3: { access := domain.AccessConfigForUCloud{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -755,7 +807,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { PrivateKey: access.PrivateKey, PublicKey: access.PublicKey, ProjectId: access.ProjectId, - DomainId: maps.GetValueAsString(options.ProviderDeployConfig, "domainId"), + DomainId: maputil.GetString(options.ProviderDeployConfig, "domainId"), }) return deployer, err @@ -764,9 +816,30 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { 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"), + Region: maputil.GetString(options.ProviderDeployConfig, "region"), + Bucket: maputil.GetString(options.ProviderDeployConfig, "bucket"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), + }) + return deployer, err + + default: + break + } + } + + case domain.DeployProviderTypeUpyunCDN, domain.DeployProviderTypeUpyunFile: + { + access := domain.AccessConfigForUpyun{} + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { + return nil, fmt.Errorf("failed to populate provider access config: %w", err) + } + + switch options.Provider { + case domain.DeployProviderTypeUpyunCDN, domain.DeployProviderTypeUpyunFile: + deployer, err := pUpyunCDN.NewDeployer(&pUpyunCDN.DeployerConfig{ + Username: access.Username, + Password: access.Password, + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -778,7 +851,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { 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 { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } @@ -787,7 +860,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pVolcEngineCDN.NewDeployer(&pVolcEngineCDN.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.SecretAccessKey, - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -795,9 +868,9 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pVolcEngineCLB.NewDeployer(&pVolcEngineCLB.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.SecretAccessKey, - Region: maps.GetValueAsString(options.ProviderDeployConfig, "region"), - ResourceType: pVolcEngineCLB.ResourceType(maps.GetValueAsString(options.ProviderDeployConfig, "resourceType")), - ListenerId: maps.GetValueAsString(options.ProviderDeployConfig, "listenerId"), + Region: maputil.GetString(options.ProviderDeployConfig, "region"), + ResourceType: pVolcEngineCLB.ResourceType(maputil.GetString(options.ProviderDeployConfig, "resourceType")), + ListenerId: maputil.GetString(options.ProviderDeployConfig, "listenerId"), }) return deployer, err @@ -805,7 +878,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pVolcEngineDCDN.NewDeployer(&pVolcEngineDCDN.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.SecretAccessKey, - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -813,9 +886,9 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { 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"), + Region: maputil.GetString(options.ProviderDeployConfig, "region"), + ServiceId: maputil.GetString(options.ProviderDeployConfig, "serviceId"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -823,7 +896,7 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { deployer, err := pVolcEngineLive.NewDeployer(&pVolcEngineLive.DeployerConfig{ AccessKeyId: access.AccessKeyId, AccessKeySecret: access.SecretAccessKey, - Domain: maps.GetValueAsString(options.ProviderDeployConfig, "domain"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -831,9 +904,9 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { 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"), + Region: maputil.GetString(options.ProviderDeployConfig, "region"), + Bucket: maputil.GetString(options.ProviderDeployConfig, "bucket"), + Domain: maputil.GetString(options.ProviderDeployConfig, "domain"), }) return deployer, err @@ -845,13 +918,13 @@ func createDeployer(options *deployerOptions) (deployer.Deployer, error) { case domain.DeployProviderTypeWebhook: { access := domain.AccessConfigForWebhook{} - if err := maps.Populate(options.ProviderAccessConfig, &access); err != nil { + if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { return nil, fmt.Errorf("failed to populate provider access config: %w", err) } deployer, err := pWebhook.NewDeployer(&pWebhook.DeployerConfig{ WebhookUrl: access.Url, - WebhookData: maps.GetValueAsString(options.ProviderDeployConfig, "webhookData"), + WebhookData: maputil.GetString(options.ProviderDeployConfig, "webhookData"), AllowInsecureConnections: access.AllowInsecureConnections, }) return deployer, err diff --git a/internal/domain/access.go b/internal/domain/access.go index fc6a7eb1..f19a0871 100644 --- a/internal/domain/access.go +++ b/internal/domain/access.go @@ -108,6 +108,10 @@ type AccessConfigForDogeCloud struct { SecretKey string `json:"secretKey"` } +type AccessConfigForDynv6 struct { + HttpToken string `json:"httpToken"` +} + type AccessConfigForEdgio struct { ClientId string `json:"clientId"` ClientSecret string `json:"clientSecret"` @@ -201,6 +205,11 @@ type AccessConfigForUCloud struct { ProjectId string `json:"projectId,omitempty"` } +type AccessConfigForUpyun struct { + Username string `json:"username"` + Password string `json:"password"` +} + type AccessConfigForVolcEngine struct { AccessKeyId string `json:"accessKeyId"` SecretAccessKey string `json:"secretAccessKey"` diff --git a/internal/domain/certificate.go b/internal/domain/certificate.go index 29ca6292..489af550 100644 --- a/internal/domain/certificate.go +++ b/internal/domain/certificate.go @@ -8,7 +8,7 @@ import ( "strings" "time" - "github.com/usual2970/certimate/internal/pkg/utils/certs" + "github.com/usual2970/certimate/internal/pkg/utils/certutil" ) const CollectionNameCertificate = "certificate" @@ -105,10 +105,10 @@ func (c *Certificate) PopulateFromPEM(certPEM, privkeyPEM string) *Certificate { c.Certificate = certPEM c.PrivateKey = privkeyPEM - _, issuerCertPEM, _ := certs.ExtractCertificatesFromPEM(certPEM) + _, issuerCertPEM, _ := certutil.ExtractCertificatesFromPEM(certPEM) c.IssuerCertificate = issuerCertPEM - certX509, _ := certs.ParseCertificateFromPEM(certPEM) + certX509, _ := certutil.ParseCertificateFromPEM(certPEM) if certX509 != nil { c.PopulateFromX509(certX509) } diff --git a/internal/domain/provider.go b/internal/domain/provider.go index 78c79d4a..addb3c87 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -28,6 +28,7 @@ const ( AccessProviderTypeCUCCCloud = AccessProviderType("cucccloud") // 天翼云(预留) AccessProviderTypeDNSLA = AccessProviderType("dnsla") AccessProviderTypeDogeCloud = AccessProviderType("dogecloud") + AccessProviderTypeDynv6 = AccessProviderType("dynv6") AccessProviderTypeEdgio = AccessProviderType("edgio") AccessProviderTypeFastly = AccessProviderType("fastly") // Fastly(预留) AccessProviderTypeGname = AccessProviderType("gname") @@ -50,6 +51,7 @@ const ( AccessProviderTypeSSH = AccessProviderType("ssh") AccessProviderTypeTencentCloud = AccessProviderType("tencentcloud") AccessProviderTypeUCloud = AccessProviderType("ucloud") + AccessProviderTypeUpyun = AccessProviderType("upyun") AccessProviderTypeVolcEngine = AccessProviderType("volcengine") AccessProviderTypeWebhook = AccessProviderType("webhook") AccessProviderTypeWestcn = AccessProviderType("westcn") @@ -78,6 +80,7 @@ const ( ApplyDNSProviderTypeClouDNS = ApplyDNSProviderType("cloudns") ApplyDNSProviderTypeCMCCCloud = ApplyDNSProviderType("cmcccloud") ApplyDNSProviderTypeDNSLA = ApplyDNSProviderType("dnsla") + ApplyDNSProviderTypeDynv6 = ApplyDNSProviderType("dynv6") ApplyDNSProviderTypeGcore = ApplyDNSProviderType("gcore") ApplyDNSProviderTypeGname = ApplyDNSProviderType("gname") ApplyDNSProviderTypeGoDaddy = ApplyDNSProviderType("godaddy") @@ -111,6 +114,7 @@ const ( DeployProviderType1PanelConsole = DeployProviderType("1panel-console") DeployProviderType1PanelSite = DeployProviderType("1panel-site") DeployProviderTypeAliyunALB = DeployProviderType("aliyun-alb") + DeployProviderTypeAliyunCAS = DeployProviderType("aliyun-cas") DeployProviderTypeAliyunCASDeploy = DeployProviderType("aliyun-casdeploy") DeployProviderTypeAliyunCDN = DeployProviderType("aliyun-cdn") DeployProviderTypeAliyunCLB = DeployProviderType("aliyun-clb") @@ -122,7 +126,9 @@ const ( DeployProviderTypeAliyunOSS = DeployProviderType("aliyun-oss") DeployProviderTypeAliyunVOD = DeployProviderType("aliyun-vod") DeployProviderTypeAliyunWAF = DeployProviderType("aliyun-waf") + DeployProviderTypeAWSACM = DeployProviderType("aws-acm") DeployProviderTypeAWSCloudFront = DeployProviderType("aws-cloudfront") + DeployProviderTypeAzureKeyVault = DeployProviderType("azure-keyvault") DeployProviderTypeBaiduCloudCDN = DeployProviderType("baiducloud-cdn") DeployProviderTypeBaishanCDN = DeployProviderType("baishan-cdn") DeployProviderTypeBaotaPanelConsole = DeployProviderType("baotapanel-console") @@ -143,6 +149,7 @@ const ( DeployProviderTypeKubernetesSecret = DeployProviderType("k8s-secret") DeployProviderTypeLocal = DeployProviderType("local") DeployProviderTypeQiniuCDN = DeployProviderType("qiniu-cdn") + DeployProviderTypeQiniuKodo = DeployProviderType("qiniu-kodo") DeployProviderTypeQiniuPili = DeployProviderType("qiniu-pili") DeployProviderTypeSafeLine = DeployProviderType("safeline") DeployProviderTypeSSH = DeployProviderType("ssh") @@ -153,11 +160,14 @@ const ( DeployProviderTypeTencentCloudECDN = DeployProviderType("tencentcloud-ecdn") DeployProviderTypeTencentCloudEO = DeployProviderType("tencentcloud-eo") DeployProviderTypeTencentCloudSCF = DeployProviderType("tencentcloud-scf") + DeployProviderTypeTencentCloudSSL = DeployProviderType("tencentcloud-ssl") DeployProviderTypeTencentCloudSSLDeploy = DeployProviderType("tencentcloud-ssldeploy") DeployProviderTypeTencentCloudVOD = DeployProviderType("tencentcloud-vod") DeployProviderTypeTencentCloudWAF = DeployProviderType("tencentcloud-waf") DeployProviderTypeUCloudUCDN = DeployProviderType("ucloud-ucdn") DeployProviderTypeUCloudUS3 = DeployProviderType("ucloud-us3") + DeployProviderTypeUpyunCDN = DeployProviderType("upyun-cdn") + DeployProviderTypeUpyunFile = DeployProviderType("upyun-file") DeployProviderTypeVolcEngineCDN = DeployProviderType("volcengine-cdn") DeployProviderTypeVolcEngineCLB = DeployProviderType("volcengine-clb") DeployProviderTypeVolcEngineDCDN = DeployProviderType("volcengine-dcdn") diff --git a/internal/domain/settings.go b/internal/domain/settings.go index 9819ec43..ebe6b9d7 100644 --- a/internal/domain/settings.go +++ b/internal/domain/settings.go @@ -14,12 +14,10 @@ type Settings struct { } type NotifyTemplatesSettingsContent struct { - NotifyTemplates []NotifyTemplate `json:"notifyTemplates"` -} - -type NotifyTemplate struct { - Subject string `json:"subject"` - Message string `json:"message"` + NotifyTemplates []struct { + Subject string `json:"subject"` + Message string `json:"message"` + } `json:"notifyTemplates"` } type NotifyChannelsSettingsContent map[string]map[string]any @@ -37,3 +35,8 @@ func (s *Settings) GetNotifyChannelConfig(channel string) (map[string]any, error return v, nil } + +type PersistenceSettingsContent struct { + WorkflowRunsMaxDaysRetention int `json:"workflowRunsMaxDaysRetention"` + ExpiredCertificatesMaxDaysRetention int `json:"expiredCertificatesMaxDaysRetention"` +} diff --git a/internal/domain/workflow.go b/internal/domain/workflow.go index 9277e798..50069865 100644 --- a/internal/domain/workflow.go +++ b/internal/domain/workflow.go @@ -3,7 +3,7 @@ package domain import ( "time" - "github.com/usual2970/certimate/internal/pkg/utils/maps" + "github.com/usual2970/certimate/internal/pkg/utils/maputil" ) const CollectionNameWorkflow = "workflow" @@ -97,19 +97,19 @@ type WorkflowNodeConfigForNotify struct { Message string `json:"message"` // 通知内容 } -func (n *WorkflowNode) getConfigValueAsString(key string) string { - return maps.GetValueAsString(n.Config, key) +func (n *WorkflowNode) getConfigString(key string) string { + return maputil.GetString(n.Config, key) } -func (n *WorkflowNode) getConfigValueAsBool(key string) bool { - return maps.GetValueAsBool(n.Config, key) +func (n *WorkflowNode) getConfigBool(key string) bool { + return maputil.GetBool(n.Config, key) } -func (n *WorkflowNode) getConfigValueAsInt32(key string) int32 { - return maps.GetValueAsInt32(n.Config, key) +func (n *WorkflowNode) getConfigInt32(key string) int32 { + return maputil.GetInt32(n.Config, key) } -func (n *WorkflowNode) getConfigValueAsMap(key string) map[string]any { +func (n *WorkflowNode) getConfigMap(key string) map[string]any { if val, ok := n.Config[key]; ok { if result, ok := val.(map[string]any); ok { return result @@ -120,50 +120,50 @@ func (n *WorkflowNode) getConfigValueAsMap(key string) map[string]any { } func (n *WorkflowNode) GetConfigForApply() WorkflowNodeConfigForApply { - skipBeforeExpiryDays := n.getConfigValueAsInt32("skipBeforeExpiryDays") + skipBeforeExpiryDays := n.getConfigInt32("skipBeforeExpiryDays") if skipBeforeExpiryDays == 0 { skipBeforeExpiryDays = 30 } return WorkflowNodeConfigForApply{ - Domains: n.getConfigValueAsString("domains"), - ContactEmail: n.getConfigValueAsString("contactEmail"), - Provider: n.getConfigValueAsString("provider"), - ProviderAccessId: n.getConfigValueAsString("providerAccessId"), - ProviderConfig: n.getConfigValueAsMap("providerConfig"), - KeyAlgorithm: n.getConfigValueAsString("keyAlgorithm"), - Nameservers: n.getConfigValueAsString("nameservers"), - DnsPropagationTimeout: n.getConfigValueAsInt32("dnsPropagationTimeout"), - DnsTTL: n.getConfigValueAsInt32("dnsTTL"), - DisableFollowCNAME: n.getConfigValueAsBool("disableFollowCNAME"), - DisableARI: n.getConfigValueAsBool("disableARI"), + Domains: n.getConfigString("domains"), + ContactEmail: n.getConfigString("contactEmail"), + Provider: n.getConfigString("provider"), + ProviderAccessId: n.getConfigString("providerAccessId"), + ProviderConfig: n.getConfigMap("providerConfig"), + KeyAlgorithm: n.getConfigString("keyAlgorithm"), + Nameservers: n.getConfigString("nameservers"), + DnsPropagationTimeout: n.getConfigInt32("dnsPropagationTimeout"), + DnsTTL: n.getConfigInt32("dnsTTL"), + DisableFollowCNAME: n.getConfigBool("disableFollowCNAME"), + DisableARI: n.getConfigBool("disableARI"), SkipBeforeExpiryDays: skipBeforeExpiryDays, } } func (n *WorkflowNode) GetConfigForUpload() WorkflowNodeConfigForUpload { return WorkflowNodeConfigForUpload{ - Certificate: n.getConfigValueAsString("certificate"), - PrivateKey: n.getConfigValueAsString("privateKey"), - Domains: n.getConfigValueAsString("domains"), + Certificate: n.getConfigString("certificate"), + PrivateKey: n.getConfigString("privateKey"), + Domains: n.getConfigString("domains"), } } func (n *WorkflowNode) GetConfigForDeploy() WorkflowNodeConfigForDeploy { return WorkflowNodeConfigForDeploy{ - Certificate: n.getConfigValueAsString("certificate"), - Provider: n.getConfigValueAsString("provider"), - ProviderAccessId: n.getConfigValueAsString("providerAccessId"), - ProviderConfig: n.getConfigValueAsMap("providerConfig"), - SkipOnLastSucceeded: n.getConfigValueAsBool("skipOnLastSucceeded"), + Certificate: n.getConfigString("certificate"), + Provider: n.getConfigString("provider"), + ProviderAccessId: n.getConfigString("providerAccessId"), + ProviderConfig: n.getConfigMap("providerConfig"), + SkipOnLastSucceeded: n.getConfigBool("skipOnLastSucceeded"), } } func (n *WorkflowNode) GetConfigForNotify() WorkflowNodeConfigForNotify { return WorkflowNodeConfigForNotify{ - Channel: n.getConfigValueAsString("channel"), - Subject: n.getConfigValueAsString("subject"), - Message: n.getConfigValueAsString("message"), + Channel: n.getConfigString("channel"), + Subject: n.getConfigString("subject"), + Message: n.getConfigString("message"), } } diff --git a/internal/domain/workflow_log.go b/internal/domain/workflow_log.go new file mode 100644 index 00000000..05eef5a7 --- /dev/null +++ b/internal/domain/workflow_log.go @@ -0,0 +1,30 @@ +package domain + +import "strings" + +const CollectionNameWorkflowLog = "workflow_logs" + +type WorkflowLog struct { + Meta + WorkflowId string `json:"workflowId" db:"workflowId"` + RunId string `json:"workflorunIdwId" db:"runId"` + NodeId string `json:"nodeId" db:"nodeId"` + NodeName string `json:"nodeName" db:"nodeName"` + Timestamp int64 `json:"timestamp" db:"timestamp"` // 毫秒级时间戳 + Level string `json:"level" db:"level"` + Message string `json:"message" db:"message"` + Data map[string]any `json:"data" db:"data"` +} + +type WorkflowLogs []WorkflowLog + +func (r WorkflowLogs) ErrorString() string { + var builder strings.Builder + for _, log := range r { + if log.Level == "ERROR" { + builder.WriteString(log.Message) + builder.WriteString("\n") + } + } + return strings.TrimSpace(builder.String()) +} diff --git a/internal/domain/workflow_run.go b/internal/domain/workflow_run.go index ff5424c5..407afc73 100644 --- a/internal/domain/workflow_run.go +++ b/internal/domain/workflow_run.go @@ -1,7 +1,6 @@ package domain import ( - "strings" "time" ) @@ -14,7 +13,7 @@ type WorkflowRun struct { Trigger WorkflowTriggerType `json:"trigger" db:"trigger"` StartedAt time.Time `json:"startedAt" db:"startedAt"` EndedAt time.Time `json:"endedAt" db:"endedAt"` - Logs []WorkflowRunLog `json:"logs" db:"logs"` + Detail *WorkflowNode `json:"detail" db:"detail"` Error string `json:"error" db:"error"` } @@ -27,39 +26,3 @@ const ( WorkflowRunStatusTypeFailed WorkflowRunStatusType = "failed" WorkflowRunStatusTypeCanceled WorkflowRunStatusType = "canceled" ) - -type WorkflowRunLog struct { - NodeId string `json:"nodeId"` - NodeName string `json:"nodeName"` - Records []WorkflowRunLogRecord `json:"records"` - Error string `json:"error"` -} - -type WorkflowRunLogRecord struct { - Time string `json:"time"` - Level WorkflowRunLogLevel `json:"level"` - Content string `json:"content"` - Error string `json:"error"` -} - -type WorkflowRunLogLevel string - -const ( - WorkflowRunLogLevelDebug WorkflowRunLogLevel = "DEBUG" - WorkflowRunLogLevelInfo WorkflowRunLogLevel = "INFO" - WorkflowRunLogLevelWarn WorkflowRunLogLevel = "WARN" - WorkflowRunLogLevelError WorkflowRunLogLevel = "ERROR" -) - -type WorkflowRunLogs []WorkflowRunLog - -func (r WorkflowRunLogs) ErrorString() string { - var builder strings.Builder - for _, log := range r { - if log.Error != "" { - builder.WriteString(log.Error) - builder.WriteString("\n") - } - } - return builder.String() -} diff --git a/internal/notify/notify.go b/internal/notify/notify.go index f509630c..d4b42ec9 100644 --- a/internal/notify/notify.go +++ b/internal/notify/notify.go @@ -9,7 +9,7 @@ import ( "github.com/usual2970/certimate/internal/domain" "github.com/usual2970/certimate/internal/pkg/core/notifier" - "github.com/usual2970/certimate/internal/pkg/utils/maps" + "github.com/usual2970/certimate/internal/pkg/utils/maputil" "github.com/usual2970/certimate/internal/repository" ) @@ -62,7 +62,7 @@ func getEnabledNotifiers() ([]notifier.Notifier, error) { notifiers := make([]notifier.Notifier, 0) for k, v := range rs { - if !maps.GetValueAsBool(v, "enabled") { + if !maputil.GetBool(v, "enabled") { continue } diff --git a/internal/notify/providers.go b/internal/notify/providers.go index 9cd27439..66927390 100644 --- a/internal/notify/providers.go +++ b/internal/notify/providers.go @@ -13,7 +13,7 @@ import ( 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" + "github.com/usual2970/certimate/internal/pkg/utils/maputil" ) func createNotifier(channel domain.NotifyChannelType, channelConfig map[string]any) (notifier.Notifier, error) { @@ -24,52 +24,52 @@ func createNotifier(channel domain.NotifyChannelType, channelConfig map[string]a switch channel { case domain.NotifyChannelTypeBark: return pBark.NewNotifier(&pBark.NotifierConfig{ - DeviceKey: maps.GetValueAsString(channelConfig, "deviceKey"), - ServerUrl: maps.GetValueAsString(channelConfig, "serverUrl"), + DeviceKey: maputil.GetString(channelConfig, "deviceKey"), + ServerUrl: maputil.GetString(channelConfig, "serverUrl"), }) case domain.NotifyChannelTypeDingTalk: return pDingTalk.NewNotifier(&pDingTalk.NotifierConfig{ - AccessToken: maps.GetValueAsString(channelConfig, "accessToken"), - Secret: maps.GetValueAsString(channelConfig, "secret"), + AccessToken: maputil.GetString(channelConfig, "accessToken"), + Secret: maputil.GetString(channelConfig, "secret"), }) case domain.NotifyChannelTypeEmail: return pEmail.NewNotifier(&pEmail.NotifierConfig{ - SmtpHost: maps.GetValueAsString(channelConfig, "smtpHost"), - SmtpPort: maps.GetValueAsInt32(channelConfig, "smtpPort"), - SmtpTLS: maps.GetValueOrDefaultAsBool(channelConfig, "smtpTLS", true), - Username: maps.GetValueOrDefaultAsString(channelConfig, "username", maps.GetValueAsString(channelConfig, "senderAddress")), - Password: maps.GetValueAsString(channelConfig, "password"), - SenderAddress: maps.GetValueAsString(channelConfig, "senderAddress"), - ReceiverAddress: maps.GetValueAsString(channelConfig, "receiverAddress"), + SmtpHost: maputil.GetString(channelConfig, "smtpHost"), + SmtpPort: maputil.GetInt32(channelConfig, "smtpPort"), + SmtpTLS: maputil.GetOrDefaultBool(channelConfig, "smtpTLS", true), + Username: maputil.GetOrDefaultString(channelConfig, "username", maputil.GetString(channelConfig, "senderAddress")), + Password: maputil.GetString(channelConfig, "password"), + SenderAddress: maputil.GetString(channelConfig, "senderAddress"), + ReceiverAddress: maputil.GetString(channelConfig, "receiverAddress"), }) case domain.NotifyChannelTypeLark: return pLark.NewNotifier(&pLark.NotifierConfig{ - WebhookUrl: maps.GetValueAsString(channelConfig, "webhookUrl"), + WebhookUrl: maputil.GetString(channelConfig, "webhookUrl"), }) case domain.NotifyChannelTypeServerChan: return pServerChan.NewNotifier(&pServerChan.NotifierConfig{ - Url: maps.GetValueAsString(channelConfig, "url"), + Url: maputil.GetString(channelConfig, "url"), }) case domain.NotifyChannelTypeTelegram: return pTelegram.NewNotifier(&pTelegram.NotifierConfig{ - ApiToken: maps.GetValueAsString(channelConfig, "apiToken"), - ChatId: maps.GetValueAsInt64(channelConfig, "chatId"), + ApiToken: maputil.GetString(channelConfig, "apiToken"), + ChatId: maputil.GetInt64(channelConfig, "chatId"), }) case domain.NotifyChannelTypeWebhook: return pWebhook.NewNotifier(&pWebhook.NotifierConfig{ - Url: maps.GetValueAsString(channelConfig, "url"), - AllowInsecureConnections: maps.GetValueAsBool(channelConfig, "allowInsecureConnections"), + Url: maputil.GetString(channelConfig, "url"), + AllowInsecureConnections: maputil.GetBool(channelConfig, "allowInsecureConnections"), }) case domain.NotifyChannelTypeWeCom: return pWeCom.NewNotifier(&pWeCom.NotifierConfig{ - WebhookUrl: maps.GetValueAsString(channelConfig, "webhookUrl"), + WebhookUrl: maputil.GetString(channelConfig, "webhookUrl"), }) } diff --git a/internal/pkg/core/applicant/acme-dns-01/lego-providers/dynv6/dnsla.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/dynv6/dnsla.go new file mode 100644 index 00000000..e5a1ea3c --- /dev/null +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/dynv6/dnsla.go @@ -0,0 +1,37 @@ +package dynv6 + +import ( + "time" + + "github.com/go-acme/lego/v4/challenge" + + internal "github.com/usual2970/certimate/internal/pkg/core/applicant/acme-dns-01/lego-providers/dynv6/internal" +) + +type ChallengeProviderConfig struct { + HttpToken string `json:"httpToken"` + 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.HTTPToken = config.HttpToken + 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/dynv6/internal/lego.go b/internal/pkg/core/applicant/acme-dns-01/lego-providers/dynv6/internal/lego.go new file mode 100644 index 00000000..f83949a2 --- /dev/null +++ b/internal/pkg/core/applicant/acme-dns-01/lego-providers/dynv6/internal/lego.go @@ -0,0 +1,167 @@ +package lego_dynv6 + +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/go-acme/lego/v4/challenge" + "github.com/go-acme/lego/v4/challenge/dns01" + "github.com/go-acme/lego/v4/platform/config/env" + "github.com/libdns/dynv6" + "github.com/libdns/libdns" +) + +const ( + envNamespace = "DYNV6_" + + EnvHTTPToken = envNamespace + "HTTP_TOKEN" + + EnvTTL = envNamespace + "TTL" + EnvPropagationTimeout = envNamespace + "PROPAGATION_TIMEOUT" + EnvPollingInterval = envNamespace + "POLLING_INTERVAL" +) + +var _ challenge.ProviderTimeout = (*DNSProvider)(nil) + +type Config struct { + HTTPToken string + + PropagationTimeout time.Duration + PollingInterval time.Duration + TTL int +} + +type DNSProvider struct { + client *dynv6.Provider + config *Config +} + +func NewDefaultConfig() *Config { + return &Config{ + TTL: env.GetOrDefaultInt(EnvTTL, dns01.DefaultTTL), + PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 2*time.Minute), + PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, dns01.DefaultPollingInterval), + } +} + +func NewDNSProvider() (*DNSProvider, error) { + values, err := env.Get(EnvHTTPToken) + if err != nil { + return nil, fmt.Errorf("dynv6: %w", err) + } + + config := NewDefaultConfig() + config.HTTPToken = values[EnvHTTPToken] + + return NewDNSProviderConfig(config) +} + +func NewDNSProviderConfig(config *Config) (*DNSProvider, error) { + if config == nil { + return nil, errors.New("dynv6: the configuration of the DNS provider is nil") + } + + client := &dynv6.Provider{Token: config.HTTPToken} + + 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("dynv6: %w", err) + } + + subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone) + if err != nil { + return fmt.Errorf("dynv6: %w", err) + } + + if err := d.addOrUpdateDNSRecord(dns01.UnFqdn(authZone), subDomain, info.Value); err != nil { + return fmt.Errorf("dynv6: %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("dynv6: %w", err) + } + + subDomain, err := dns01.ExtractSubDomain(info.EffectiveFQDN, authZone) + if err != nil { + return fmt.Errorf("dynv6: %w", err) + } + + if err := d.removeDNSRecord(dns01.UnFqdn(authZone), subDomain); err != nil { + return fmt.Errorf("dynv6: %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) (*libdns.Record, error) { + records, err := d.client.GetRecords(context.Background(), zoneName) + if err != nil { + return nil, err + } + + for _, record := range records { + if record.Type == "TXT" && record.Name == subDomain { + return &record, nil + } + } + + 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 { + record = &libdns.Record{ + Type: "TXT", + Name: subDomain, + Value: value, + TTL: time.Duration(d.config.TTL) * time.Second, + } + _, err := d.client.AppendRecords(context.Background(), zoneName, []libdns.Record{*record}) + return err + } else { + record.Value = value + _, err := d.client.SetRecords(context.Background(), zoneName, []libdns.Record{*record}) + 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.DeleteRecords(context.Background(), zoneName, []libdns.Record{*record}) + return err + } +} diff --git a/internal/pkg/core/deployer/deployer.go b/internal/pkg/core/deployer/deployer.go index 78d7c7de..54b206bd 100644 --- a/internal/pkg/core/deployer/deployer.go +++ b/internal/pkg/core/deployer/deployer.go @@ -1,10 +1,15 @@ package deployer -import "context" +import ( + "context" + "log/slog" +) // 表示定义证书部署器的抽象类型接口。 // 注意与 `Uploader` 区分,“部署”通常为“上传”的后置操作。 type Deployer interface { + WithLogger(logger *slog.Logger) Deployer + // 部署证书。 // // 入参: diff --git a/internal/pkg/core/deployer/providers/1panel-console/1panel_console.go b/internal/pkg/core/deployer/providers/1panel-console/1panel_console.go index 512b5296..91143aa6 100644 --- a/internal/pkg/core/deployer/providers/1panel-console/1panel_console.go +++ b/internal/pkg/core/deployer/providers/1panel-console/1panel_console.go @@ -4,12 +4,12 @@ import ( "context" "crypto/tls" "errors" + "log/slog" "net/url" xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/pkg/core/deployer" - "github.com/usual2970/certimate/internal/pkg/core/logger" opsdk "github.com/usual2970/certimate/internal/pkg/vendors/1panel-sdk" ) @@ -26,7 +26,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *opsdk.Client } @@ -44,13 +44,17 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } return d } @@ -68,10 +72,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe updateSystemSSLReq.AutoRestart = "false" } updateSystemSSLResp, err := d.sdkClient.UpdateSystemSSL(updateSystemSSLReq) + d.logger.Debug("sdk request '1panel.UpdateSystemSSL'", slog.Any("request", updateSystemSSLReq), slog.Any("response", updateSystemSSLResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request '1panel.UpdateSystemSSL'") - } else { - d.logger.Logt("已设置面板 SSL 证书", updateSystemSSLResp) } return &deployer.DeployResult{}, nil diff --git a/internal/pkg/core/deployer/providers/1panel-site/1panel_site.go b/internal/pkg/core/deployer/providers/1panel-site/1panel_site.go index cdad354a..6aa34607 100644 --- a/internal/pkg/core/deployer/providers/1panel-site/1panel_site.go +++ b/internal/pkg/core/deployer/providers/1panel-site/1panel_site.go @@ -4,13 +4,13 @@ import ( "context" "crypto/tls" "errors" + "log/slog" "net/url" "strconv" 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/1panel-ssl" opsdk "github.com/usual2970/certimate/internal/pkg/vendors/1panel-sdk" @@ -29,7 +29,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *opsdk.Client sslUploader uploader.Uploader } @@ -56,14 +56,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -73,10 +78,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe WebsiteID: d.config.WebsiteId, } getHttpsConfResp, err := d.sdkClient.GetHttpsConf(getHttpsConfReq) + d.logger.Debug("sdk request '1panel.GetHttpsConf'", slog.Any("request", getHttpsConfReq), slog.Any("response", getHttpsConfResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request '1panel.GetHttpsConf'") - } else { - d.logger.Logt("已获取网站 HTTPS 配置", getHttpsConfResp) } // 上传证书到面板 @@ -84,7 +88,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") } else { - d.logger.Logt("certificate file uploaded", upres) + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } // 修改网站 HTTPS 配置 @@ -100,10 +104,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe Hsts: getHttpsConfResp.Data.Hsts, } updateHttpsConfResp, err := d.sdkClient.UpdateHttpsConf(updateHttpsConfReq) + d.logger.Debug("sdk request '1panel.UpdateHttpsConf'", slog.Any("request", updateHttpsConfReq), slog.Any("response", updateHttpsConfResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request '1panel.UpdateHttpsConf'") - } else { - d.logger.Logt("已获取网站 HTTPS 配置", updateHttpsConfResp) } return &deployer.DeployResult{}, nil 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 8c25bc25..ae088602 100644 --- a/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb.go +++ b/internal/pkg/core/deployer/providers/aliyun-alb/aliyun_alb.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "log/slog" "strconv" "strings" "time" @@ -16,7 +17,6 @@ import ( "golang.org/x/exp/slices" "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/aliyun-cas" ) @@ -43,7 +43,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClients *wSdkClients sslUploader uploader.Uploader } @@ -72,14 +72,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClients: clients, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -88,10 +93,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - // 根据部署资源类型决定部署方式 switch d.config.ResourceType { case RESOURCE_TYPE_LOADBALANCER: @@ -122,12 +127,11 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId LoadBalancerId: tea.String(d.config.LoadbalancerId), } getLoadBalancerAttributeResp, err := d.sdkClients.alb.GetLoadBalancerAttribute(getLoadBalancerAttributeReq) + d.logger.Debug("sdk request 'alb.GetLoadBalancerAttribute'", slog.Any("request", getLoadBalancerAttributeReq), slog.Any("response", getLoadBalancerAttributeResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'alb.GetLoadBalancerAttribute'") } - d.logger.Logt("已查询到 ALB 负载均衡实例", getLoadBalancerAttributeResp) - // 查询 HTTPS 监听列表 // REF: https://help.aliyun.com/zh/slb/application-load-balancer/developer-reference/api-alb-2020-06-16-listlisteners listenerIds := make([]string, 0) @@ -141,6 +145,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId ListenerProtocol: tea.String("HTTPS"), } listListenersResp, err := d.sdkClients.alb.ListListeners(listListenersReq) + d.logger.Debug("sdk request 'alb.ListListeners'", slog.Any("request", listListenersReq), slog.Any("response", listListenersResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'alb.ListListeners'") } @@ -158,8 +163,6 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId } } - d.logger.Logt("已查询到 ALB 负载均衡实例下的全部 HTTPS 监听", listenerIds) - // 查询 QUIC 监听列表 // REF: https://help.aliyun.com/zh/slb/application-load-balancer/developer-reference/api-alb-2020-06-16-listlisteners listListenersToken = nil @@ -171,6 +174,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId ListenerProtocol: tea.String("QUIC"), } listListenersResp, err := d.sdkClients.alb.ListListeners(listListenersReq) + d.logger.Debug("sdk request 'alb.ListListeners'", slog.Any("request", listListenersReq), slog.Any("response", listListenersResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'alb.ListListeners'") } @@ -188,13 +192,12 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId } } - d.logger.Logt("已查询到 ALB 负载均衡实例下的全部 QUIC 监听", listenerIds) - // 遍历更新监听证书 if len(listenerIds) == 0 { - return errors.New("listener not found") + d.logger.Info("no alb listeners to deploy") } else { var errs []error + d.logger.Info("found https/quic listeners to deploy", slog.Any("listenerIds", listenerIds)) for _, listenerId := range listenerIds { if err := d.updateListenerCertificate(ctx, listenerId, cloudCertId); err != nil { @@ -230,12 +233,11 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL ListenerId: tea.String(cloudListenerId), } getListenerAttributeResp, err := d.sdkClients.alb.GetListenerAttribute(getListenerAttributeReq) + d.logger.Debug("sdk request 'alb.GetListenerAttribute'", slog.Any("request", getListenerAttributeReq), slog.Any("response", getListenerAttributeResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'alb.GetListenerAttribute'") } - d.logger.Logt("已查询到 ALB 监听配置", getListenerAttributeResp) - if d.config.Domain == "" { // 未指定 SNI,只需部署到监听器 @@ -248,11 +250,10 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL }}, } updateListenerAttributeResp, err := d.sdkClients.alb.UpdateListenerAttribute(updateListenerAttributeReq) + d.logger.Debug("sdk request 'alb.UpdateListenerAttribute'", slog.Any("request", updateListenerAttributeReq), slog.Any("response", updateListenerAttributeResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'alb.UpdateListenerAttribute'") } - - d.logger.Logt("已更新 ALB 监听配置", updateListenerAttributeResp) } else { // 指定 SNI,需部署到扩展域名 @@ -269,6 +270,7 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL CertificateType: tea.String("Server"), } listListenerCertificatesResp, err := d.sdkClients.alb.ListListenerCertificates(listListenerCertificatesReq) + d.logger.Debug("sdk request 'alb.ListListenerCertificates'", slog.Any("request", listListenerCertificatesReq), slog.Any("response", listListenerCertificatesResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'alb.ListListenerCertificates'") } @@ -286,14 +288,13 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL } } - d.logger.Logt("已查询到 ALB 监听下全部证书", listenerCertificates) - // 遍历查询监听证书,并找出需要解除关联的证书 // REF: https://help.aliyun.com/zh/slb/application-load-balancer/developer-reference/api-alb-2020-06-16-listlistenercertificates // REF: https://help.aliyun.com/zh/ssl-certificate/developer-reference/api-cas-2020-04-07-getusercertificatedetail certificateIsAssociated := false certificateIdsExpired := make([]string, 0) if len(listenerCertificates) > 0 { + d.logger.Info("found listener certificates to deploy", slog.Any("listenerCertificates", listenerCertificates)) var errs []error for _, listenerCertificate := range listenerCertificates { @@ -318,6 +319,7 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL CertId: tea.Int64(certificateIdAsInt64), } getUserCertificateDetailResp, err := d.sdkClients.cas.GetUserCertificateDetail(getUserCertificateDetailReq) + d.logger.Debug("sdk request 'cas.GetUserCertificateDetail'", slog.Any("request", getUserCertificateDetailReq), slog.Any("response", getUserCertificateDetailResp)) if err != nil { errs = append(errs, xerrors.Wrap(err, "failed to execute sdk request 'cas.GetUserCertificateDetail'")) continue @@ -354,11 +356,10 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL }, } associateAdditionalCertificatesFromListenerResp, err := d.sdkClients.alb.AssociateAdditionalCertificatesWithListener(associateAdditionalCertificatesFromListenerReq) + d.logger.Debug("sdk request 'alb.AssociateAdditionalCertificatesWithListener'", slog.Any("request", associateAdditionalCertificatesFromListenerReq), slog.Any("response", associateAdditionalCertificatesFromListenerResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'alb.AssociateAdditionalCertificatesWithListener'") } - - d.logger.Logt("已关联 ALB 监听和扩展证书", associateAdditionalCertificatesFromListenerResp) } // 解除关联监听和扩展证书 @@ -376,11 +377,10 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL Certificates: dissociateAdditionalCertificates, } dissociateAdditionalCertificatesFromListenerResp, err := d.sdkClients.alb.DissociateAdditionalCertificatesFromListener(dissociateAdditionalCertificatesFromListenerReq) + d.logger.Debug("sdk request 'alb.DissociateAdditionalCertificatesFromListener'", slog.Any("request", dissociateAdditionalCertificatesFromListenerReq), slog.Any("response", dissociateAdditionalCertificatesFromListenerResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'alb.DissociateAdditionalCertificatesFromListener'") } - - d.logger.Logt("已解除关联 ALB 监听和扩展证书", dissociateAdditionalCertificatesFromListenerResp) } } 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 fa045521..7c53358d 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 @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "log/slog" "strings" "time" @@ -13,7 +14,6 @@ import ( 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/aliyun-cas" ) @@ -34,7 +34,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *aliyunCas.Client sslUploader uploader.Uploader } @@ -51,21 +51,30 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return nil, xerrors.Wrap(err, "failed to create sdk client") } - uploader, err := createSslUploader(config.AccessKeyId, config.AccessKeySecret, config.Region) + 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(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -78,10 +87,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - contactIds := d.config.ContactIds if len(contactIds) == 0 { // 获取联系人列表 @@ -90,6 +99,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe listContactReq.ShowSize = tea.Int32(1) listContactReq.CurrentPage = tea.Int32(1) listContactResp, err := d.sdkClient.ListContact(listContactReq) + d.logger.Debug("sdk request 'cas.ListContact'", slog.Any("request", listContactReq), slog.Any("response", listContactResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cas.ListContact'") } @@ -109,12 +119,11 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe ContactIds: tea.String(strings.Join(contactIds, ",")), } createDeploymentJobResp, err := d.sdkClient.CreateDeploymentJob(createDeploymentJobReq) + d.logger.Debug("sdk request 'cas.CreateDeploymentJob'", slog.Any("request", createDeploymentJobReq), slog.Any("response", createDeploymentJobResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cas.CreateDeploymentJob'") } - d.logger.Logt("已创建部署任务", createDeploymentJobResp) - // 循环获取部署任务详情,等待任务状态变更 // REF: https://help.aliyun.com/zh/ssl-certificate/developer-reference/api-cas-2020-04-07-describedeploymentjob for { @@ -126,20 +135,20 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe JobId: createDeploymentJobResp.Body.JobId, } describeDeploymentJobResp, err := d.sdkClient.DescribeDeploymentJob(describeDeploymentJobReq) + d.logger.Debug("sdk request 'cas.DescribeDeploymentJob'", slog.Any("request", describeDeploymentJobReq), slog.Any("response", describeDeploymentJobResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cas.DescribeDeploymentJob'") } if describeDeploymentJobResp.Body.Status == nil || *describeDeploymentJobResp.Body.Status == "editing" { - return nil, errors.New("部署任务状态异常") + return nil, errors.New("unexpected deployment job status") } if *describeDeploymentJobResp.Body.Status == "success" || *describeDeploymentJobResp.Body.Status == "error" { - d.logger.Logt("已获取部署任务详情", describeDeploymentJobResp) break } - d.logger.Logt("部署任务未完成 ...") + d.logger.Info("waiting for deployment job completion ...") time.Sleep(time.Second * 5) } @@ -173,12 +182,3 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunCas.Cl return client, nil } - -func createSslUploader(accessKeyId, accessKeySecret, region string) (uploader.Uploader, error) { - uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ - AccessKeyId: accessKeyId, - AccessKeySecret: accessKeySecret, - Region: region, - }) - return uploader, err -} diff --git a/internal/pkg/core/deployer/providers/aliyun-cas/aliyun_cas.go b/internal/pkg/core/deployer/providers/aliyun-cas/aliyun_cas.go new file mode 100644 index 00000000..e00d3788 --- /dev/null +++ b/internal/pkg/core/deployer/providers/aliyun-cas/aliyun_cas.go @@ -0,0 +1,72 @@ +package aliyuncas + +import ( + "context" + "log/slog" + + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/uploader" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aliyun-cas" +) + +type DeployerConfig struct { + // 阿里云 AccessKeyId。 + AccessKeyId string `json:"accessKeyId"` + // 阿里云 AccessKeySecret。 + AccessKeySecret string `json:"accessKeySecret"` + // 阿里云地域。 + Region string `json:"region"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger *slog.Logger + sslUploader uploader.Uploader +} + +var _ deployer.Deployer = (*DeployerProvider)(nil) + +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { + if config == nil { + panic("config is nil") + } + + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ + AccessKeyId: config.AccessKeyId, + AccessKeySecret: config.AccessKeySecret, + Region: config.Region, + }) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create ssl uploader") + } + + return &DeployerProvider{ + config: config, + logger: slog.Default(), + sslUploader: uploader, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(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 { + return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) + } + + return &deployer.DeployResult{}, nil +} 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 b0edd415..8f61837f 100644 --- a/internal/pkg/core/deployer/providers/aliyun-cdn/aliyun_cdn.go +++ b/internal/pkg/core/deployer/providers/aliyun-cdn/aliyun_cdn.go @@ -3,6 +3,7 @@ import ( "context" "fmt" + "log/slog" "strings" "time" @@ -12,7 +13,6 @@ import ( xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/pkg/core/deployer" - "github.com/usual2970/certimate/internal/pkg/core/logger" ) type DeployerConfig struct { @@ -26,7 +26,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *aliyunCdn.Client } @@ -44,13 +44,17 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } return d } @@ -69,12 +73,11 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe SSLPri: tea.String(privkeyPem), } setCdnDomainSSLCertificateResp, err := d.sdkClient.SetCdnDomainSSLCertificate(setCdnDomainSSLCertificateReq) + d.logger.Debug("sdk request 'cdn.SetCdnDomainSSLCertificate'", slog.Any("request", setCdnDomainSSLCertificateReq), slog.Any("response", setCdnDomainSSLCertificateResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.SetCdnDomainSSLCertificate'") } - d.logger.Logt("已设置 CDN 域名证书", setCdnDomainSSLCertificateResp) - return &deployer.DeployResult{}, nil } 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 304a7131..fe0d3a44 100644 --- a/internal/pkg/core/deployer/providers/aliyun-clb/aliyun_clb.go +++ b/internal/pkg/core/deployer/providers/aliyun-clb/aliyun_clb.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "log/slog" aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client" aliyunSlb "github.com/alibabacloud-go/slb-20140515/v4/client" @@ -11,7 +12,6 @@ import ( 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/aliyun-slb" ) @@ -38,7 +38,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *aliyunSlb.Client sslUploader uploader.Uploader } @@ -66,14 +66,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -82,10 +87,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - // 根据部署资源类型决定部署方式 switch d.config.ResourceType { case RESOURCE_TYPE_LOADBALANCER: @@ -117,12 +122,11 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId LoadBalancerId: tea.String(d.config.LoadbalancerId), } describeLoadBalancerAttributeResp, err := d.sdkClient.DescribeLoadBalancerAttribute(describeLoadBalancerAttributeReq) + d.logger.Debug("sdk request 'slb.DescribeLoadBalancerAttribute'", slog.Any("request", describeLoadBalancerAttributeReq), slog.Any("response", describeLoadBalancerAttributeResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'slb.DescribeLoadBalancerAttribute'") } - d.logger.Logt("已查询到 CLB 负载均衡实例", describeLoadBalancerAttributeResp) - // 查询 HTTPS 监听列表 // REF: https://help.aliyun.com/zh/slb/classic-load-balancer/developer-reference/api-slb-2014-05-15-describeloadbalancerlisteners listenerPorts := make([]int32, 0) @@ -137,6 +141,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId ListenerProtocol: tea.String("https"), } describeLoadBalancerListenersResp, err := d.sdkClient.DescribeLoadBalancerListeners(describeLoadBalancerListenersReq) + d.logger.Debug("sdk request 'slb.DescribeLoadBalancerListeners'", slog.Any("request", describeLoadBalancerListenersReq), slog.Any("response", describeLoadBalancerListenersResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'slb.DescribeLoadBalancerListeners'") } @@ -154,12 +159,11 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId } } - d.logger.Logt("已查询到 CLB 负载均衡实例下的全部 HTTPS 监听", listenerPorts) - // 遍历更新监听证书 if len(listenerPorts) == 0 { - return errors.New("listener not found") + d.logger.Info("no clb listeners to deploy") } else { + d.logger.Info("found https listeners to deploy", slog.Any("listenerPorts", listenerPorts)) var errs []error for _, listenerPort := range listenerPorts { @@ -200,12 +204,11 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL ListenerPort: tea.Int32(cloudListenerPort), } describeLoadBalancerHTTPSListenerAttributeResp, err := d.sdkClient.DescribeLoadBalancerHTTPSListenerAttribute(describeLoadBalancerHTTPSListenerAttributeReq) + d.logger.Debug("sdk request 'slb.DescribeLoadBalancerHTTPSListenerAttribute'", slog.Any("request", describeLoadBalancerHTTPSListenerAttributeReq), slog.Any("response", describeLoadBalancerHTTPSListenerAttributeResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'slb.DescribeLoadBalancerHTTPSListenerAttribute'") } - d.logger.Logt("已查询到 CLB HTTPS 监听配置", describeLoadBalancerHTTPSListenerAttributeResp) - if d.config.Domain == "" { // 未指定 SNI,只需部署到监听器 @@ -218,11 +221,10 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL ServerCertificateId: tea.String(cloudCertId), } setLoadBalancerHTTPSListenerAttributeResp, err := d.sdkClient.SetLoadBalancerHTTPSListenerAttribute(setLoadBalancerHTTPSListenerAttributeReq) + d.logger.Debug("sdk request 'slb.SetLoadBalancerHTTPSListenerAttribute'", slog.Any("request", setLoadBalancerHTTPSListenerAttributeReq), slog.Any("response", setLoadBalancerHTTPSListenerAttributeResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'slb.SetLoadBalancerHTTPSListenerAttribute'") } - - d.logger.Logt("已更新 CLB HTTPS 监听配置", setLoadBalancerHTTPSListenerAttributeResp) } else { // 指定 SNI,需部署到扩展域名 @@ -234,12 +236,11 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL ListenerPort: tea.Int32(cloudListenerPort), } describeDomainExtensionsResp, err := d.sdkClient.DescribeDomainExtensions(describeDomainExtensionsReq) + d.logger.Debug("sdk request 'slb.DescribeDomainExtensions'", slog.Any("request", describeDomainExtensionsReq), slog.Any("response", describeDomainExtensionsResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'slb.DescribeDomainExtensions'") } - d.logger.Logt("已查询到 CLB 扩展域名", describeDomainExtensionsResp) - // 遍历修改扩展域名 // REF: https://help.aliyun.com/zh/slb/classic-load-balancer/developer-reference/api-slb-2014-05-15-setdomainextensionattribute if describeDomainExtensionsResp.Body.DomainExtensions != nil && describeDomainExtensionsResp.Body.DomainExtensions.DomainExtension != nil { @@ -256,12 +257,11 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL ServerCertificateId: tea.String(cloudCertId), } setDomainExtensionAttributeResp, err := d.sdkClient.SetDomainExtensionAttribute(setDomainExtensionAttributeReq) + d.logger.Debug("sdk request 'slb.SetDomainExtensionAttribute'", slog.Any("request", setDomainExtensionAttributeReq), slog.Any("response", setDomainExtensionAttributeResp)) if err != nil { errs = append(errs, xerrors.Wrap(err, "failed to execute sdk request 'slb.SetDomainExtensionAttribute'")) continue } - - d.logger.Logt("已修改 CLB 扩展域名", setDomainExtensionAttributeResp) } if len(errs) > 0 { 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 bfa28e7b..0ca22a6e 100644 --- a/internal/pkg/core/deployer/providers/aliyun-dcdn/aliyun_dcdn.go +++ b/internal/pkg/core/deployer/providers/aliyun-dcdn/aliyun_dcdn.go @@ -3,6 +3,7 @@ import ( "context" "fmt" + "log/slog" "strings" "time" @@ -12,7 +13,6 @@ import ( xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/pkg/core/deployer" - "github.com/usual2970/certimate/internal/pkg/core/logger" ) type DeployerConfig struct { @@ -26,7 +26,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *aliyunDcdn.Client } @@ -44,13 +44,17 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } return d } @@ -69,12 +73,11 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe SSLPri: tea.String(privkeyPem), } setDcdnDomainSSLCertificateResp, err := d.sdkClient.SetDcdnDomainSSLCertificate(setDcdnDomainSSLCertificateReq) + d.logger.Debug("sdk request 'dcdn.SetDcdnDomainSSLCertificate'", slog.Any("request", setDcdnDomainSSLCertificateReq), slog.Any("response", setDcdnDomainSSLCertificateResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'dcdn.SetDcdnDomainSSLCertificate'") } - d.logger.Logt("已配置 DCDN 域名证书", setDcdnDomainSSLCertificateResp) - return &deployer.DeployResult{}, nil } 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 5134d115..aa7e60c1 100644 --- a/internal/pkg/core/deployer/providers/aliyun-esa/aliyun_esa.go +++ b/internal/pkg/core/deployer/providers/aliyun-esa/aliyun_esa.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "log/slog" "strconv" "strings" @@ -13,7 +14,6 @@ import ( 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/aliyun-cas" ) @@ -31,7 +31,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *aliyunEsa.Client sslUploader uploader.Uploader } @@ -55,14 +55,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -75,10 +80,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - // 配置站点证书 // REF: https://help.aliyun.com/zh/edge-security-acceleration/esa/api-esa-2024-09-10-setcertificate certId, _ := strconv.ParseInt(upres.CertId, 10, 64) @@ -88,12 +93,11 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe CasId: tea.Int64(certId), } setCertificateResp, err := d.sdkClient.SetCertificate(setCertificateReq) + d.logger.Debug("sdk request 'esa.SetCertificate'", slog.Any("request", setCertificateReq), slog.Any("response", setCertificateResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'esa.SetCertificate'") } - d.logger.Logt("已配置站点证书", setCertificateResp) - return &deployer.DeployResult{}, nil } 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 9a2c4ca0..0877d561 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 @@ -28,7 +28,7 @@ func init() { flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "") flag.StringVar(&fAccessKeySecret, argsPrefix+"ACCESSKEYSECRET", "", "") flag.StringVar(&fRegion, argsPrefix+"REGION", "", "") - flag.Int64Var(&fSiteId, argsPrefix+"SITEID", "", "") + flag.Int64Var(&fSiteId, argsPrefix+"SITEID", 0, "") } /* diff --git a/internal/pkg/core/deployer/providers/aliyun-fc/aliyun_fc.go b/internal/pkg/core/deployer/providers/aliyun-fc/aliyun_fc.go index e70931f8..d5450017 100644 --- a/internal/pkg/core/deployer/providers/aliyun-fc/aliyun_fc.go +++ b/internal/pkg/core/deployer/providers/aliyun-fc/aliyun_fc.go @@ -3,6 +3,7 @@ import ( "context" "fmt" + "log/slog" "time" aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client" @@ -12,7 +13,6 @@ import ( xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/pkg/core/deployer" - "github.com/usual2970/certimate/internal/pkg/core/logger" ) type DeployerConfig struct { @@ -23,7 +23,6 @@ type DeployerConfig struct { // 阿里云地域。 Region string `json:"region"` // 服务版本。 - // 零值时默认为 "3.0"。 ServiceVersion string `json:"serviceVersion"` // 自定义域名(不支持泛域名)。 Domain string `json:"domain"` @@ -31,7 +30,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClients *wSdkClients } @@ -54,24 +53,28 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClients: clients, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } return d } func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { switch d.config.ServiceVersion { - case "", "3.0": + case "3", "3.0": if err := d.deployToFC3(ctx, certPem, privkeyPem); err != nil { return nil, err } - case "2.0": + case "2", "2.0": if err := d.deployToFC2(ctx, certPem, privkeyPem); err != nil { return nil, err } @@ -87,10 +90,9 @@ func (d *DeployerProvider) deployToFC3(ctx context.Context, certPem string, priv // 获取自定义域名 // REF: https://help.aliyun.com/zh/functioncompute/fc-3-0/developer-reference/api-fc-2023-03-30-getcustomdomain getCustomDomainResp, err := d.sdkClients.fc3.GetCustomDomain(tea.String(d.config.Domain)) + d.logger.Debug("sdk request 'fc.GetCustomDomain'", slog.Any("response", getCustomDomainResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'fc.GetCustomDomain'") - } else { - d.logger.Logt("已获取自定义域名", getCustomDomainResp) } // 更新自定义域名 @@ -107,10 +109,9 @@ func (d *DeployerProvider) deployToFC3(ctx context.Context, certPem string, priv }, } updateCustomDomainResp, err := d.sdkClients.fc3.UpdateCustomDomain(tea.String(d.config.Domain), updateCustomDomainReq) + d.logger.Debug("sdk request 'fc.UpdateCustomDomain'", slog.Any("request", updateCustomDomainReq), slog.Any("response", updateCustomDomainResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'fc.UpdateCustomDomain'") - } else { - d.logger.Logt("已更新自定义域名", updateCustomDomainResp) } return nil @@ -120,10 +121,9 @@ func (d *DeployerProvider) deployToFC2(ctx context.Context, certPem string, priv // 获取自定义域名 // REF: https://help.aliyun.com/zh/functioncompute/fc-2-0/developer-reference/api-fc-open-2021-04-06-getcustomdomain getCustomDomainResp, err := d.sdkClients.fc2.GetCustomDomain(tea.String(d.config.Domain)) + d.logger.Debug("sdk request 'fc.GetCustomDomain'", slog.Any("response", getCustomDomainResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'fc.GetCustomDomain'") - } else { - d.logger.Logt("已获取自定义域名", getCustomDomainResp) } // 更新自定义域名 @@ -138,10 +138,9 @@ func (d *DeployerProvider) deployToFC2(ctx context.Context, certPem string, priv TlsConfig: getCustomDomainResp.Body.TlsConfig, } updateCustomDomainResp, err := d.sdkClients.fc2.UpdateCustomDomain(tea.String(d.config.Domain), updateCustomDomainReq) + d.logger.Debug("sdk request 'fc.UpdateCustomDomain'", slog.Any("request", updateCustomDomainReq), slog.Any("response", updateCustomDomainResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'fc.UpdateCustomDomain'") - } else { - d.logger.Logt("已更新自定义域名", updateCustomDomainResp) } return nil diff --git a/internal/pkg/core/deployer/providers/aliyun-fc/aliyun_fc_test.go b/internal/pkg/core/deployer/providers/aliyun-fc/aliyun_fc_test.go index a8780285..d83f2591 100644 --- a/internal/pkg/core/deployer/providers/aliyun-fc/aliyun_fc_test.go +++ b/internal/pkg/core/deployer/providers/aliyun-fc/aliyun_fc_test.go @@ -17,7 +17,7 @@ var ( fAccessKeyId string fAccessKeySecret string fRegion string - fSiteId int64 + fDomain string ) func init() { @@ -28,7 +28,7 @@ func init() { flag.StringVar(&fAccessKeyId, argsPrefix+"ACCESSKEYID", "", "") flag.StringVar(&fAccessKeySecret, argsPrefix+"ACCESSKEYSECRET", "", "") flag.StringVar(&fRegion, argsPrefix+"REGION", "", "") - flag.Int64Var(&fSiteId, argsPrefix+"SITEID", "", "") + flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "") } /* @@ -40,7 +40,7 @@ Shell command to run this test: --CERTIMATE_DEPLOYER_ALIYUNFC_ACCESSKEYID="your-access-key-id" \ --CERTIMATE_DEPLOYER_ALIYUNFC_ACCESSKEYSECRET="your-access-key-secret" \ --CERTIMATE_DEPLOYER_ALIYUNFC_REGION="cn-hangzhou" \ - --CERTIMATE_DEPLOYER_ALIYUNFC_SITEID="your-fc-site-id" + --CERTIMATE_DEPLOYER_ALIYUNFC_DOMAIN="example.com" */ func TestDeploy(t *testing.T) { flag.Parse() @@ -53,14 +53,14 @@ func TestDeploy(t *testing.T) { fmt.Sprintf("ACCESSKEYID: %v", fAccessKeyId), fmt.Sprintf("ACCESSKEYSECRET: %v", fAccessKeySecret), fmt.Sprintf("REGION: %v", fRegion), - fmt.Sprintf("SITEID: %v", fSiteId), + fmt.Sprintf("DOMAIN: %v", fDomain), }, "\n")) deployer, err := provider.NewDeployer(&provider.DeployerConfig{ AccessKeyId: fAccessKeyId, AccessKeySecret: fAccessKeySecret, Region: fRegion, - SiteId: fSiteId, + Domain: fDomain, }) if err != nil { t.Errorf("err: %+v", err) 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 99b06aca..4eacd077 100644 --- a/internal/pkg/core/deployer/providers/aliyun-live/aliyun_live.go +++ b/internal/pkg/core/deployer/providers/aliyun-live/aliyun_live.go @@ -3,6 +3,7 @@ import ( "context" "fmt" + "log/slog" "strings" "time" @@ -12,7 +13,6 @@ import ( xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/pkg/core/deployer" - "github.com/usual2970/certimate/internal/pkg/core/logger" ) type DeployerConfig struct { @@ -28,7 +28,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *aliyunLive.Client } @@ -46,13 +46,17 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } return d } @@ -71,12 +75,11 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe SSLPri: tea.String(privkeyPem), } setLiveDomainSSLCertificateResp, err := d.sdkClient.SetLiveDomainCertificate(setLiveDomainSSLCertificateReq) + d.logger.Debug("sdk request 'live.SetLiveDomainCertificate'", slog.Any("request", setLiveDomainSSLCertificateReq), slog.Any("response", setLiveDomainSSLCertificateResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'live.SetLiveDomainCertificate'") } - d.logger.Logt("已设置域名证书", setLiveDomainSSLCertificateResp) - return &deployer.DeployResult{}, 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 8dc1b2e3..98885d7d 100644 --- a/internal/pkg/core/deployer/providers/aliyun-nlb/aliyun_nlb.go +++ b/internal/pkg/core/deployer/providers/aliyun-nlb/aliyun_nlb.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "log/slog" "strings" aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client" @@ -12,7 +13,6 @@ import ( 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/aliyun-cas" ) @@ -36,7 +36,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *aliyunNlb.Client sslUploader uploader.Uploader } @@ -60,14 +60,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -76,10 +81,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - // 根据部署资源类型决定部署方式 switch d.config.ResourceType { case RESOURCE_TYPE_LOADBALANCER: @@ -110,12 +115,11 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId LoadBalancerId: tea.String(d.config.LoadbalancerId), } getLoadBalancerAttributeResp, err := d.sdkClient.GetLoadBalancerAttribute(getLoadBalancerAttributeReq) + d.logger.Debug("sdk request 'nlb.GetLoadBalancerAttribute'", slog.Any("request", getLoadBalancerAttributeReq), slog.Any("response", getLoadBalancerAttributeResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'nlb.GetLoadBalancerAttribute'") } - d.logger.Logt("已查询到 NLB 负载均衡实例", getLoadBalancerAttributeResp) - // 查询 TCPSSL 监听列表 // REF: https://help.aliyun.com/zh/slb/network-load-balancer/developer-reference/api-nlb-2022-04-30-listlisteners listenerIds := make([]string, 0) @@ -129,6 +133,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId ListenerProtocol: tea.String("TCPSSL"), } listListenersResp, err := d.sdkClient.ListListeners(listListenersReq) + d.logger.Debug("sdk request 'nlb.ListListeners'", slog.Any("request", listListenersReq), slog.Any("response", listListenersResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'nlb.ListListeners'") } @@ -146,12 +151,11 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId } } - d.logger.Logt("已查询到 NLB 负载均衡实例下的全部 TCPSSL 监听", listenerIds) - // 遍历更新监听证书 if len(listenerIds) == 0 { - return errors.New("listener not found") + d.logger.Info("no nlb listeners to deploy") } else { + d.logger.Info("found tcpssl listeners to deploy", slog.Any("listenerIds", listenerIds)) var errs []error for _, listenerId := range listenerIds { @@ -188,12 +192,11 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL ListenerId: tea.String(cloudListenerId), } getListenerAttributeResp, err := d.sdkClient.GetListenerAttribute(getListenerAttributeReq) + d.logger.Debug("sdk request 'nlb.GetListenerAttribute'", slog.Any("request", getListenerAttributeReq), slog.Any("response", getListenerAttributeResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'nlb.GetListenerAttribute'") } - d.logger.Logt("已查询到 NLB 监听配置", getListenerAttributeResp) - // 修改监听的属性 // REF: https://help.aliyun.com/zh/slb/network-load-balancer/developer-reference/api-nlb-2022-04-30-updatelistenerattribute updateListenerAttributeReq := &aliyunNlb.UpdateListenerAttributeRequest{ @@ -201,12 +204,11 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL CertificateIds: []*string{tea.String(cloudCertId)}, } updateListenerAttributeResp, err := d.sdkClient.UpdateListenerAttribute(updateListenerAttributeReq) + d.logger.Debug("sdk request 'nlb.UpdateListenerAttribute'", slog.Any("request", updateListenerAttributeReq), slog.Any("response", updateListenerAttributeResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'nlb.UpdateListenerAttribute'") } - d.logger.Logt("已更新 NLB 监听配置", updateListenerAttributeResp) - return nil } 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 3eba5c55..2f16b09d 100644 --- a/internal/pkg/core/deployer/providers/aliyun-oss/aliyun_oss.go +++ b/internal/pkg/core/deployer/providers/aliyun-oss/aliyun_oss.go @@ -4,12 +4,12 @@ import ( "context" "errors" "fmt" + "log/slog" "github.com/aliyun/aliyun-oss-go-sdk/oss" xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/pkg/core/deployer" - "github.com/usual2970/certimate/internal/pkg/core/logger" ) type DeployerConfig struct { @@ -27,7 +27,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *oss.Client } @@ -45,13 +45,17 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } return d } @@ -65,14 +69,16 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe // 为存储空间绑定自定义域名 // REF: https://help.aliyun.com/zh/oss/developer-reference/putcname - err := d.sdkClient.PutBucketCnameWithCertificate(d.config.Bucket, oss.PutBucketCname{ + putBucketCnameWithCertificateReq := oss.PutBucketCname{ Cname: d.config.Domain, CertificateConfiguration: &oss.CertificateConfiguration{ Certificate: certPem, PrivateKey: privkeyPem, Force: true, }, - }) + } + err := d.sdkClient.PutBucketCnameWithCertificate(d.config.Bucket, putBucketCnameWithCertificateReq) + d.logger.Debug("sdk request 'oss.PutBucketCnameWithCertificate'", slog.Any("bucket", d.config.Bucket), slog.Any("request", putBucketCnameWithCertificateReq)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'oss.PutBucketCnameWithCertificate'") } diff --git a/internal/pkg/core/deployer/providers/aliyun-vod/aliyun_vod.go b/internal/pkg/core/deployer/providers/aliyun-vod/aliyun_vod.go index 77c2ebf0..66dc188c 100644 --- a/internal/pkg/core/deployer/providers/aliyun-vod/aliyun_vod.go +++ b/internal/pkg/core/deployer/providers/aliyun-vod/aliyun_vod.go @@ -3,6 +3,7 @@ import ( "context" "fmt" + "log/slog" "time" aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client" @@ -11,7 +12,6 @@ import ( xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/pkg/core/deployer" - "github.com/usual2970/certimate/internal/pkg/core/logger" ) type DeployerConfig struct { @@ -27,7 +27,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *aliyunVod.Client } @@ -45,13 +45,17 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } return d } @@ -67,10 +71,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe SSLPri: tea.String(privkeyPem), } setVodDomainSSLCertificateResp, err := d.sdkClient.SetVodDomainSSLCertificate(setVodDomainSSLCertificateReq) + d.logger.Debug("sdk request 'live.SetVodDomainSSLCertificate'", slog.Any("request", setVodDomainSSLCertificateReq), slog.Any("response", setVodDomainSSLCertificateResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'live.SetVodDomainSSLCertificate'") - } else { - d.logger.Logt("已设置域名证书", setVodDomainSSLCertificateResp) } return &deployer.DeployResult{}, nil 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 928a0d56..998ee7e7 100644 --- a/internal/pkg/core/deployer/providers/aliyun-waf/aliyun_waf.go +++ b/internal/pkg/core/deployer/providers/aliyun-waf/aliyun_waf.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "log/slog" "strings" aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client" @@ -12,7 +13,6 @@ import ( 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/aliyun-cas" ) @@ -24,6 +24,8 @@ type DeployerConfig struct { AccessKeySecret string `json:"accessKeySecret"` // 阿里云地域。 Region string `json:"region"` + // 服务版本。 + ServiceVersion string `json:"serviceVersion"` // WAF 实例 ID。 InstanceId string `json:"instanceId"` // 接入域名(支持泛域名)。 @@ -32,7 +34,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *aliyunWaf.Client sslUploader uploader.Uploader } @@ -56,14 +58,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -72,12 +79,26 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe return nil, errors.New("config `instanceId` is required") } + switch d.config.ServiceVersion { + case "3", "3.0": + if err := d.deployToWAF3(ctx, certPem, privkeyPem); err != nil { + return nil, err + } + + default: + return nil, xerrors.Errorf("unsupported service version: %s", d.config.ServiceVersion) + } + + return &deployer.DeployResult{}, nil +} + +func (d *DeployerProvider) deployToWAF3(ctx context.Context, certPem string, privkeyPem string) error { // 上传证书到 CAS upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { - return nil, xerrors.Wrap(err, "failed to upload certificate file") + return xerrors.Wrap(err, "failed to upload certificate file") } else { - d.logger.Logt("certificate file uploaded", upres) + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } if d.config.Domain == "" { @@ -90,10 +111,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe RegionId: tea.String(d.config.Region), } describeDefaultHttpsResp, err := d.sdkClient.DescribeDefaultHttps(describeDefaultHttpsReq) + d.logger.Debug("sdk request 'waf.DescribeDefaultHttps'", slog.Any("request", describeDefaultHttpsReq), slog.Any("response", describeDefaultHttpsResp)) if err != nil { - return nil, xerrors.Wrap(err, "failed to execute sdk request 'waf.DescribeDefaultHttps'") - } else { - d.logger.Logt("已查询到默认 SSL/TLS 设置", describeDefaultHttpsResp) + return xerrors.Wrap(err, "failed to execute sdk request 'waf.DescribeDefaultHttps'") } // 修改默认 SSL/TLS 设置 @@ -110,10 +130,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe modifyDefaultHttpsReq.EnableTLSv3 = describeDefaultHttpsResp.Body.DefaultHttps.EnableTLSv3 } modifyDefaultHttpsResp, err := d.sdkClient.ModifyDefaultHttps(modifyDefaultHttpsReq) + d.logger.Debug("sdk request 'waf.ModifyDefaultHttps'", slog.Any("request", modifyDefaultHttpsReq), slog.Any("response", modifyDefaultHttpsResp)) if err != nil { - return nil, xerrors.Wrap(err, "failed to execute sdk request 'waf.ModifyDefaultHttps'") - } else { - d.logger.Logt("已修改默认 SSL/TLS 设置", modifyDefaultHttpsResp) + return xerrors.Wrap(err, "failed to execute sdk request 'waf.ModifyDefaultHttps'") } } else { // 指定接入域名 @@ -126,10 +145,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe Domain: tea.String(d.config.Domain), } describeDomainDetailResp, err := d.sdkClient.DescribeDomainDetail(describeDomainDetailReq) + d.logger.Debug("sdk request 'waf.DescribeDomainDetail'", slog.Any("request", describeDomainDetailReq), slog.Any("response", describeDomainDetailResp)) if err != nil { - return nil, xerrors.Wrap(err, "failed to execute sdk request 'waf.DescribeDomainDetail'") - } else { - d.logger.Logt("已查询到 CNAME 接入详情", describeDomainDetailResp) + return xerrors.Wrap(err, "failed to execute sdk request 'waf.DescribeDomainDetail'") } // 修改 CNAME 接入资源 @@ -143,22 +161,29 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe TLSVersion: tea.String("tlsv1"), EnableTLSv3: tea.Bool(false), }, - Redirect: &aliyunWaf.ModifyDomainRequestRedirect{}, + Redirect: &aliyunWaf.ModifyDomainRequestRedirect{ + Loadbalance: tea.String("iphash"), + }, } if describeDomainDetailResp.Body != nil && describeDomainDetailResp.Body.Listen != nil { modifyDomainReq.Listen.TLSVersion = describeDomainDetailResp.Body.Listen.TLSVersion modifyDomainReq.Listen.EnableTLSv3 = describeDomainDetailResp.Body.Listen.EnableTLSv3 modifyDomainReq.Listen.FocusHttps = describeDomainDetailResp.Body.Listen.FocusHttps } + if describeDomainDetailResp.Body != nil && describeDomainDetailResp.Body.Redirect != nil { + modifyDomainReq.Redirect.Loadbalance = describeDomainDetailResp.Body.Redirect.Loadbalance + modifyDomainReq.Redirect.FocusHttpBackend = describeDomainDetailResp.Body.Redirect.FocusHttpBackend + modifyDomainReq.Redirect.SniEnabled = describeDomainDetailResp.Body.Redirect.SniEnabled + modifyDomainReq.Redirect.SniHost = describeDomainDetailResp.Body.Redirect.SniHost + } modifyDomainResp, err := d.sdkClient.ModifyDomain(modifyDomainReq) + d.logger.Debug("sdk request 'waf.ModifyDomain'", slog.Any("request", modifyDomainReq), slog.Any("response", modifyDomainResp)) if err != nil { - return nil, xerrors.Wrap(err, "failed to execute sdk request 'waf.ModifyDomain'") - } else { - d.logger.Logt("已修改 CNAME 接入资源", modifyDomainResp) + return xerrors.Wrap(err, "failed to execute sdk request 'waf.ModifyDomain'") } } - return &deployer.DeployResult{}, nil + return nil } func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunWaf.Client, error) { diff --git a/internal/pkg/core/deployer/providers/aws-acm/aws_acm.go b/internal/pkg/core/deployer/providers/aws-acm/aws_acm.go new file mode 100644 index 00000000..88482de3 --- /dev/null +++ b/internal/pkg/core/deployer/providers/aws-acm/aws_acm.go @@ -0,0 +1,72 @@ +package awsacm + +import ( + "context" + "log/slog" + + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/uploader" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/aws-acm" +) + +type DeployerConfig struct { + // AWS AccessKeyId。 + AccessKeyId string `json:"accessKeyId"` + // AWS SecretAccessKey。 + SecretAccessKey string `json:"secretAccessKey"` + // AWS 区域。 + Region string `json:"region"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger *slog.Logger + sslUploader uploader.Uploader +} + +var _ deployer.Deployer = (*DeployerProvider)(nil) + +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { + if config == nil { + panic("config is nil") + } + + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ + AccessKeyId: config.AccessKeyId, + SecretAccessKey: config.SecretAccessKey, + Region: config.Region, + }) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create ssl uploader") + } + + return &DeployerProvider{ + config: config, + logger: slog.Default(), + sslUploader: uploader, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { + // 上传证书到 ACM + upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) + if err != nil { + return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) + } + + return &deployer.DeployResult{}, nil +} 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 2e8e09ee..456799bd 100644 --- a/internal/pkg/core/deployer/providers/aws-cloudfront/aws_cloudfront.go +++ b/internal/pkg/core/deployer/providers/aws-cloudfront/aws_cloudfront.go @@ -3,6 +3,7 @@ import ( "context" "errors" + "log/slog" aws "github.com/aws/aws-sdk-go-v2/aws" awsCfg "github.com/aws/aws-sdk-go-v2/config" @@ -12,7 +13,6 @@ import ( 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/aws-acm" ) @@ -30,7 +30,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *awsCf.Client sslUploader uploader.Uploader } @@ -58,14 +58,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -78,22 +83,21 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - // 获取分配配置 // REF: https://docs.aws.amazon.com/en_us/cloudfront/latest/APIReference/API_GetDistributionConfig.html getDistributionConfigReq := &awsCf.GetDistributionConfigInput{ Id: aws.String(d.config.DistributionId), } getDistributionConfigResp, err := d.sdkClient.GetDistributionConfig(context.TODO(), getDistributionConfigReq) + d.logger.Debug("sdk request 'cloudfront.GetDistributionConfig'", slog.Any("request", getDistributionConfigReq), slog.Any("response", getDistributionConfigResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cloudfront.GetDistributionConfig'") } - d.logger.Logt("已获取分配配置", getDistributionConfigResp) - // 更新分配配置 // REF: https://docs.aws.amazon.com/zh_cn/cloudfront/latest/APIReference/API_UpdateDistribution.html updateDistributionReq := &awsCf.UpdateDistributionInput{ @@ -107,12 +111,11 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe updateDistributionReq.DistributionConfig.ViewerCertificate.CloudFrontDefaultCertificate = aws.Bool(false) updateDistributionReq.DistributionConfig.ViewerCertificate.ACMCertificateArn = aws.String(upres.CertId) updateDistributionResp, err := d.sdkClient.UpdateDistribution(context.TODO(), updateDistributionReq) + d.logger.Debug("sdk request 'cloudfront.UpdateDistribution'", slog.Any("request", updateDistributionReq), slog.Any("response", updateDistributionResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cloudfront.UpdateDistribution'") } - d.logger.Logt("已更新分配配置", updateDistributionResp) - return &deployer.DeployResult{}, nil } diff --git a/internal/pkg/core/deployer/providers/azure-keyvault/azure_keyvault.go b/internal/pkg/core/deployer/providers/azure-keyvault/azure_keyvault.go new file mode 100644 index 00000000..4439aa68 --- /dev/null +++ b/internal/pkg/core/deployer/providers/azure-keyvault/azure_keyvault.go @@ -0,0 +1,78 @@ +package azurekeyvault + +import ( + "context" + "log/slog" + + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/uploader" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/azure-keyvault" +) + +type DeployerConfig struct { + // Azure TenantId。 + TenantId string `json:"tenantId"` + // Azure ClientId。 + ClientId string `json:"clientId"` + // Azure ClientSecret。 + ClientSecret string `json:"clientSecret"` + // Azure 主权云环境。 + CloudName string `json:"cloudName,omitempty"` + // Key Vault 名称。 + KeyVaultName string `json:"keyvaultName"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger *slog.Logger + sslUploader uploader.Uploader +} + +var _ deployer.Deployer = (*DeployerProvider)(nil) + +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { + if config == nil { + panic("config is nil") + } + + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ + TenantId: config.TenantId, + ClientId: config.ClientId, + ClientSecret: config.ClientSecret, + CloudName: config.CloudName, + KeyVaultName: config.KeyVaultName, + }) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create ssl uploader") + } + + return &DeployerProvider{ + config: config, + logger: slog.Default(), + sslUploader: uploader, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { + // 上传证书到 KeyVault + upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) + if err != nil { + return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) + } + + return &deployer.DeployResult{}, nil +} 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 df57ea1d..a31a21ec 100644 --- a/internal/pkg/core/deployer/providers/baiducloud-cdn/baiducloud_cdn.go +++ b/internal/pkg/core/deployer/providers/baiducloud-cdn/baiducloud_cdn.go @@ -3,6 +3,7 @@ import ( "context" "fmt" + "log/slog" "time" bceCdn "github.com/baidubce/bce-sdk-go/services/cdn" @@ -10,7 +11,6 @@ import ( xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/pkg/core/deployer" - "github.com/usual2970/certimate/internal/pkg/core/logger" ) type DeployerConfig struct { @@ -24,7 +24,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *bceCdn.Client } @@ -42,13 +42,17 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } return d } @@ -64,12 +68,11 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe }, "ON", ) + d.logger.Debug("sdk request 'cdn.PutCert'", slog.String("request.domain", d.config.Domain), slog.Any("response", putCertResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.PutCert'") } - d.logger.Logt("已修改域名证书", putCertResp) - return &deployer.DeployResult{}, nil } diff --git a/internal/pkg/core/deployer/providers/baishan-cdn/baishan_cdn.go b/internal/pkg/core/deployer/providers/baishan-cdn/baishan_cdn.go index efb3353e..3435b26e 100644 --- a/internal/pkg/core/deployer/providers/baishan-cdn/baishan_cdn.go +++ b/internal/pkg/core/deployer/providers/baishan-cdn/baishan_cdn.go @@ -4,12 +4,12 @@ import ( "context" "errors" "fmt" + "log/slog" "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" ) @@ -22,7 +22,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *bssdk.Client } @@ -40,13 +40,17 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } return d } @@ -59,15 +63,14 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe // REF: https://portal.baishancloud.com/track/document/api/1/1065 getDomainConfigReq := &bssdk.GetDomainConfigRequest{ Domains: d.config.Domain, - Config: "https", + Config: []string{"https"}, } getDomainConfigResp, err := d.sdkClient.GetDomainConfig(getDomainConfigReq) + d.logger.Debug("sdk request 'baishan.GetDomainConfig'", slog.Any("request", getDomainConfigReq), slog.Any("response", getDomainConfigResp)) 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) } // 新增证书 @@ -78,10 +81,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe Name: fmt.Sprintf("certimate_%d", time.Now().UnixMilli()), } createCertificateResp, err := d.sdkClient.CreateCertificate(createCertificateReq) + d.logger.Debug("sdk request 'baishan.CreateCertificate'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'baishan.CreateCertificate'") - } else { - d.logger.Logt("已新增证书", createCertificateResp) } // 设置域名配置 @@ -98,10 +100,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe }, } setDomainConfigResp, err := d.sdkClient.SetDomainConfig(setDomainConfigReq) + d.logger.Debug("sdk request 'baishan.SetDomainConfig'", slog.Any("request", setDomainConfigReq), slog.Any("response", setDomainConfigResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'baishan.SetDomainConfig'") - } else { - d.logger.Logt("已设置域名配置", setDomainConfigResp) } return &deployer.DeployResult{}, nil diff --git a/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console.go b/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console.go index ff09dc26..57e37f05 100644 --- a/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console.go +++ b/internal/pkg/core/deployer/providers/baotapanel-console/baotapanel_console.go @@ -4,12 +4,12 @@ import ( "context" "crypto/tls" "errors" + "log/slog" "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" ) @@ -26,7 +26,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *btsdk.Client } @@ -44,13 +44,17 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } return d } @@ -61,10 +65,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe Certificate: certPem, } configSavePanelSSLResp, err := d.sdkClient.ConfigSavePanelSSL(configSavePanelSSLReq) + d.logger.Debug("sdk request 'bt.ConfigSavePanelSSL'", slog.Any("request", configSavePanelSSLReq), slog.Any("response", configSavePanelSSLResp)) 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 { @@ -73,7 +76,8 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe Name: "nginx", Type: "restart", } - d.sdkClient.SystemServiceAdmin(systemServiceAdminReq) + systemServiceAdminResp, _ := d.sdkClient.SystemServiceAdmin(systemServiceAdminReq) + d.logger.Debug("sdk request 'bt.SystemServiceAdmin'", slog.Any("request", systemServiceAdminReq), slog.Any("response", systemServiceAdminResp)) } return &deployer.DeployResult{}, nil 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 c6bf4966..082b57b7 100644 --- a/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site.go +++ b/internal/pkg/core/deployer/providers/baotapanel-site/baotapanel_site.go @@ -5,13 +5,13 @@ import ( "crypto/tls" "errors" "fmt" + "log/slog" "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" + "github.com/usual2970/certimate/internal/pkg/utils/sliceutil" btsdk "github.com/usual2970/certimate/internal/pkg/vendors/btpanel-sdk" ) @@ -32,7 +32,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *btsdk.Client } @@ -50,13 +50,17 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } return d } @@ -76,10 +80,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe PrivateKey: privkeyPem, } siteSetSSLResp, err := d.sdkClient.SiteSetSSL(siteSetSSLReq) + d.logger.Debug("sdk request 'bt.SiteSetSSL'", slog.Any("request", siteSetSSLReq), slog.Any("response", siteSetSSLResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'bt.SiteSetSSL'") - } else { - d.logger.Logt("已设置站点证书", siteSetSSLResp) } } @@ -95,15 +98,14 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe PrivateKey: privkeyPem, } sslCertSaveCertResp, err := d.sdkClient.SSLCertSaveCert(sslCertSaveCertReq) + d.logger.Debug("sdk request 'bt.SSLCertSaveCert'", slog.Any("request", sslCertSaveCertReq), slog.Any("response", sslCertSaveCertResp)) 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 { + BatchInfo: sliceutil.Map(d.config.SiteNames, func(siteName string) *btsdk.SSLSetBatchCertToSiteRequestBatchInfo { return &btsdk.SSLSetBatchCertToSiteRequestBatchInfo{ SiteName: siteName, SSLHash: sslCertSaveCertResp.SSLHash, @@ -111,10 +113,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe }), } sslSetBatchCertToSiteResp, err := d.sdkClient.SSLSetBatchCertToSite(sslSetBatchCertToSiteReq) + d.logger.Debug("sdk request 'bt.SSLSetBatchCertToSite'", slog.Any("request", sslSetBatchCertToSiteReq), slog.Any("response", sslSetBatchCertToSiteResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'bt.SSLSetBatchCertToSite'") - } else { - d.logger.Logt("已设置站点证书", sslSetBatchCertToSiteResp) } } 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 909a2e7d..b8bd8856 100644 --- a/internal/pkg/core/deployer/providers/byteplus-cdn/byteplus_cdn.go +++ b/internal/pkg/core/deployer/providers/byteplus-cdn/byteplus_cdn.go @@ -3,14 +3,13 @@ import ( "context" "errors" - "fmt" + "log/slog" "strings" bpCdn "github.com/byteplus-sdk/byteplus-sdk-golang/service/cdn" 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/byteplus-cdn" ) @@ -26,7 +25,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *bpCdn.CDN sslUploader uploader.Uploader } @@ -52,14 +51,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -68,10 +72,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - domains := make([]string, 0) if strings.HasPrefix(d.config.Domain, "*.") { // 获取指定证书可关联的域名 @@ -80,6 +84,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe CertId: upres.CertId, } describeCertConfigResp, err := d.sdkClient.DescribeCertConfig(describeCertConfigReq) + d.logger.Debug("sdk request 'cdn.DescribeCertConfig'", slog.Any("request", describeCertConfigReq), slog.Any("response", describeCertConfigResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.DescribeCertConfig'") } @@ -99,6 +104,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe if len(domains) == 0 { if len(describeCertConfigResp.Result.SpecifiedCertConfig) > 0 { // 所有可关联的域名都配置了该证书,跳过部署 + d.logger.Info("no domains to deploy") } else { return nil, errors.New("domain not found") } @@ -118,10 +124,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe Domain: domain, } batchDeployCertResp, err := d.sdkClient.BatchDeployCert(batchDeployCertReq) + d.logger.Debug("sdk request 'cdn.BatchDeployCert'", slog.Any("request", batchDeployCertReq), slog.Any("response", batchDeployCertResp)) if err != nil { errs = append(errs, err) - } else { - d.logger.Logt(fmt.Sprintf("已关联证书到域名 %s", domain), batchDeployCertResp) } } diff --git a/internal/pkg/core/deployer/providers/cachefly/cachefly.go b/internal/pkg/core/deployer/providers/cachefly/cachefly.go index 8c6f129d..63bb4e95 100644 --- a/internal/pkg/core/deployer/providers/cachefly/cachefly.go +++ b/internal/pkg/core/deployer/providers/cachefly/cachefly.go @@ -3,11 +3,11 @@ import ( "context" "errors" + "log/slog" 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" ) @@ -18,7 +18,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *cfsdk.Client } @@ -36,13 +36,17 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } return d } @@ -53,10 +57,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe CertificateKey: privkeyPem, } createCertificateResp, err := d.sdkClient.CreateCertificate(createCertificateReq) + d.logger.Debug("sdk request 'cachefly.CreateCertificate'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cachefly.CreateCertificate'") - } else { - d.logger.Logt("已上传证书", createCertificateResp) } return &deployer.DeployResult{}, nil diff --git a/internal/pkg/core/deployer/providers/cdnfly/cdnfly.go b/internal/pkg/core/deployer/providers/cdnfly/cdnfly.go index c98d9ae4..ec2c1883 100644 --- a/internal/pkg/core/deployer/providers/cdnfly/cdnfly.go +++ b/internal/pkg/core/deployer/providers/cdnfly/cdnfly.go @@ -5,13 +5,13 @@ import ( "encoding/json" "errors" "fmt" + "log/slog" "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" ) @@ -34,7 +34,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *cfsdk.Client } @@ -52,13 +52,17 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } return d } @@ -93,10 +97,9 @@ func (d *DeployerProvider) deployToSite(ctx context.Context, certPem string, pri Id: d.config.SiteId, } getSiteResp, err := d.sdkClient.GetSite(getSiteReq) + d.logger.Debug("sdk request 'cdnfly.GetSite'", slog.Any("request", getSiteReq), slog.Any("response", getSiteResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'cdnfly.GetSite'") - } else { - d.logger.Logt("已获取网站详情", getSiteResp) } // 添加单个证书 @@ -108,10 +111,9 @@ func (d *DeployerProvider) deployToSite(ctx context.Context, certPem string, pri Key: privkeyPem, } createCertificateResp, err := d.sdkClient.CreateCertificate(createCertificateReq) + d.logger.Debug("sdk request 'cdnfly.CreateCertificate'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'cdnfly.CreateCertificate'") - } else { - d.logger.Logt("已添加证书", createCertificateResp) } // 修改单个网站 @@ -126,10 +128,9 @@ func (d *DeployerProvider) deployToSite(ctx context.Context, certPem string, pri HttpsListen: &updateSiteHttpsListen, } updateSiteResp, err := d.sdkClient.UpdateSite(updateSiteReq) + d.logger.Debug("sdk request 'cdnfly.UpdateSite'", slog.Any("request", updateSiteReq), slog.Any("response", updateSiteResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'cdnfly.UpdateSite'") - } else { - d.logger.Logt("已修改网站", updateSiteResp) } return nil @@ -150,10 +151,9 @@ func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPem stri Key: &privkeyPem, } updateCertificateResp, err := d.sdkClient.UpdateCertificate(updateCertificateReq) + d.logger.Debug("sdk request 'cdnfly.UpdateCertificate'", slog.Any("request", updateCertificateReq), slog.Any("response", updateCertificateResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'cdnfly.UpdateCertificate'") - } else { - d.logger.Logt("已修改证书", updateCertificateResp) } return nil 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 4743b7cd..94368998 100644 --- a/internal/pkg/core/deployer/providers/dogecloud-cdn/dogecloud_cdn.go +++ b/internal/pkg/core/deployer/providers/dogecloud-cdn/dogecloud_cdn.go @@ -2,12 +2,12 @@ import ( "context" + "log/slog" "strconv" 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/dogecloud" dogesdk "github.com/usual2970/certimate/internal/pkg/vendors/dogecloud-sdk" @@ -24,7 +24,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *dogesdk.Client sslUploader uploader.Uploader } @@ -48,14 +48,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -64,19 +69,18 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - // 绑定证书 // REF: https://docs.dogecloud.com/cdn/api-cert-bind bindCdnCertId, _ := strconv.ParseInt(upres.CertId, 10, 64) bindCdnCertResp, err := d.sdkClient.BindCdnCertWithDomain(bindCdnCertId, d.config.Domain) + d.logger.Debug("sdk request 'cdn.BindCdnCert'", slog.Int64("request.certId", bindCdnCertId), slog.String("request.domain", d.config.Domain), slog.Any("response", bindCdnCertResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.BindCdnCert'") } - d.logger.Logt("已绑定证书", bindCdnCertResp) - return &deployer.DeployResult{}, nil } 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 890cfdf3..6e21444c 100644 --- a/internal/pkg/core/deployer/providers/edgio-applications/edgio_applications.go +++ b/internal/pkg/core/deployer/providers/edgio-applications/edgio_applications.go @@ -2,12 +2,12 @@ import ( "context" + "log/slog" 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/certs" + "github.com/usual2970/certimate/internal/pkg/utils/certutil" edgsdk "github.com/usual2970/certimate/internal/pkg/vendors/edgio-sdk/applications/v7" edgsdkDtos "github.com/usual2970/certimate/internal/pkg/vendors/edgio-sdk/applications/v7/dtos" ) @@ -23,7 +23,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *edgsdk.EdgioClient } @@ -41,19 +41,23 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + 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) + privateCertPem, intermediateCertPem, err := certutil.ExtractCertificatesFromPEM(certPem) if err != nil { return nil, err } @@ -67,12 +71,11 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe PrivateKey: privkeyPem, } uploadTlsCertResp, err := d.sdkClient.UploadTlsCert(uploadTlsCertReq) + d.logger.Debug("sdk request 'edgio.UploadTlsCert'", slog.Any("request", uploadTlsCertReq), slog.Any("response", uploadTlsCertResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'edgio.UploadTlsCert'") } - d.logger.Logt("已上传 TLS 证书", uploadTlsCertResp) - return &deployer.DeployResult{}, nil } diff --git a/internal/pkg/core/deployer/providers/gcore-cdn/gcore_cdn.go b/internal/pkg/core/deployer/providers/gcore-cdn/gcore_cdn.go index e1598a5d..a4d1c33e 100644 --- a/internal/pkg/core/deployer/providers/gcore-cdn/gcore_cdn.go +++ b/internal/pkg/core/deployer/providers/gcore-cdn/gcore_cdn.go @@ -3,6 +3,7 @@ import ( "context" "errors" + "log/slog" "strconv" gprovider "github.com/G-Core/gcorelabscdn-go/gcore/provider" @@ -10,7 +11,6 @@ import ( 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" @@ -25,7 +25,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *gresources.Service sslUploader uploader.Uploader } @@ -51,14 +51,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -72,16 +77,15 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") } else { - d.logger.Logt("certificate file uploaded", upres) + d.logger.Info("ssl certificate uploaded", slog.Any("result", 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) + d.logger.Debug("sdk request 'resources.Get'", slog.Any("resourceId", d.config.ResourceId), slog.Any("response", getResourceResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'resources.Get'") - } else { - d.logger.Logt("已获取 CDN 资源详情", getResourceResp) } // 更新 CDN 资源详情 @@ -101,10 +105,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe Options: getResourceResp.Options, } updateResourceResp, err := d.sdkClient.Update(context.TODO(), d.config.ResourceId, updateResourceReq) + d.logger.Debug("sdk request 'resources.Update'", slog.Int64("resourceId", d.config.ResourceId), slog.Any("request", updateResourceReq), slog.Any("response", updateResourceResp)) 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 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 4a40fbc1..d05d6503 100644 --- a/internal/pkg/core/deployer/providers/huaweicloud-cdn/huaweicloud_cdn.go +++ b/internal/pkg/core/deployer/providers/huaweicloud-cdn/huaweicloud_cdn.go @@ -2,6 +2,7 @@ import ( "context" + "log/slog" "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/global" hcCdn "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/cdn/v2" @@ -10,7 +11,6 @@ import ( 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-scm" hwsdk "github.com/usual2970/certimate/internal/pkg/vendors/huaweicloud-sdk" @@ -29,7 +29,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *hcCdn.CdnClient sslUploader uploader.Uploader } @@ -60,14 +60,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -76,22 +81,21 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - // 查询加速域名配置 // REF: https://support.huaweicloud.com/api-cdn/ShowDomainFullConfig.html showDomainFullConfigReq := &hcCdnModel.ShowDomainFullConfigRequest{ DomainName: d.config.Domain, } showDomainFullConfigResp, err := d.sdkClient.ShowDomainFullConfig(showDomainFullConfigReq) + d.logger.Debug("sdk request 'cdn.ShowDomainFullConfig'", slog.Any("request", showDomainFullConfigReq), slog.Any("response", showDomainFullConfigResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.ShowDomainFullConfig'") } - d.logger.Logt("已查询到加速域名配置", showDomainFullConfigResp) - // 更新加速域名配置 // REF: https://support.huaweicloud.com/api-cdn/UpdateDomainMultiCertificates.html // REF: https://support.huaweicloud.com/usermanual-cdn/cdn_01_0306.html @@ -108,12 +112,11 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe }, } updateDomainMultiCertificatesResp, err := d.sdkClient.UpdateDomainMultiCertificates(updateDomainMultiCertificatesReq) + d.logger.Debug("sdk request 'cdn.UploadDomainMultiCertificates'", slog.Any("request", updateDomainMultiCertificatesReq), slog.Any("response", updateDomainMultiCertificatesResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.UploadDomainMultiCertificates'") } - d.logger.Logt("已更新加速域名配置", updateDomainMultiCertificatesResp) - return &deployer.DeployResult{}, nil } 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 17bc178b..618af762 100644 --- a/internal/pkg/core/deployer/providers/huaweicloud-elb/huaweicloud_elb.go +++ b/internal/pkg/core/deployer/providers/huaweicloud-elb/huaweicloud_elb.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "log/slog" "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic" "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/global" @@ -17,7 +18,6 @@ import ( "golang.org/x/exp/slices" "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-elb" hwsdk "github.com/usual2970/certimate/internal/pkg/vendors/huaweicloud-sdk" @@ -45,7 +45,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *hcElb.ElbClient sslUploader uploader.Uploader } @@ -73,26 +73,23 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(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 { - return nil, xerrors.Wrap(err, "failed to upload certificate file") - } - - d.logger.Logt("certificate file uploaded", upres) - // 根据部署资源类型决定部署方式 switch d.config.ResourceType { case RESOURCE_TYPE_CERTIFICATE: @@ -134,12 +131,11 @@ func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPem stri }, } updateCertificateResp, err := d.sdkClient.UpdateCertificate(updateCertificateReq) + d.logger.Debug("sdk request 'elb.UpdateCertificate'", slog.Any("request", updateCertificateReq), slog.Any("response", updateCertificateResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'elb.UpdateCertificate'") } - d.logger.Logt("已更新 ELB 证书", updateCertificateResp) - return nil } @@ -154,12 +150,11 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, certPem str LoadbalancerId: d.config.LoadbalancerId, } showLoadBalancerResp, err := d.sdkClient.ShowLoadBalancer(showLoadBalancerReq) + d.logger.Debug("sdk request 'elb.ShowLoadBalancer'", slog.Any("request", showLoadBalancerReq), slog.Any("response", showLoadBalancerResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'elb.ShowLoadBalancer'") } - d.logger.Logt("已查询到 ELB 负载均衡器", showLoadBalancerResp) - // 查询监听器列表 // REF: https://support.huaweicloud.com/api-elb/ListListeners.html listenerIds := make([]string, 0) @@ -173,6 +168,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, certPem str LoadbalancerId: &[]string{showLoadBalancerResp.Loadbalancer.Id}, } listListenersResp, err := d.sdkClient.ListListeners(listListenersReq) + d.logger.Debug("sdk request 'elb.ListListeners'", slog.Any("request", listListenersReq), slog.Any("response", listListenersResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'elb.ListListeners'") } @@ -190,20 +186,19 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, certPem str } } - d.logger.Logt("已查询到 ELB 负载均衡器下的监听器", listenerIds) - // 上传证书到 SCM upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - // 遍历更新监听器证书 if len(listenerIds) == 0 { - return errors.New("listener not found") + d.logger.Info("no listeners to deploy") } else { + d.logger.Info("found https listeners to deploy", slog.Any("listenerIds", listenerIds)) var errs []error for _, listenerId := range listenerIds { @@ -229,10 +224,10 @@ func (d *DeployerProvider) deployToListener(ctx context.Context, certPem string, upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - // 更新监听器证书 if err := d.modifyListenerCertificate(ctx, d.config.ListenerId, upres.CertId); err != nil { return err @@ -248,12 +243,11 @@ func (d *DeployerProvider) modifyListenerCertificate(ctx context.Context, cloudL ListenerId: cloudListenerId, } showListenerResp, err := d.sdkClient.ShowListener(showListenerReq) + d.logger.Debug("sdk request 'elb.ShowListener'", slog.Any("request", showListenerReq), slog.Any("response", showListenerResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'elb.ShowListener'") } - d.logger.Logt("已查询到 ELB 监听器", showListenerResp) - // 更新监听器 // REF: https://support.huaweicloud.com/api-elb/UpdateListener.html updateListenerReq := &hcElbModel.UpdateListenerRequest{ @@ -274,6 +268,7 @@ func (d *DeployerProvider) modifyListenerCertificate(ctx context.Context, cloudL Id: &showListenerResp.Listener.SniContainerRefs, } listOldCertificateResp, err := d.sdkClient.ListCertificates(listOldCertificateReq) + d.logger.Debug("sdk request 'elb.ListCertificates'", slog.Any("request", listOldCertificateReq), slog.Any("response", listOldCertificateResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'elb.ListCertificates'") } @@ -282,6 +277,7 @@ func (d *DeployerProvider) modifyListenerCertificate(ctx context.Context, cloudL CertificateId: cloudCertId, } showNewCertificateResp, err := d.sdkClient.ShowCertificate(showNewCertificateReq) + d.logger.Debug("sdk request 'elb.ShowCertificate'", slog.Any("request", showNewCertificateReq), slog.Any("response", showNewCertificateResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'elb.ShowCertificate'") } @@ -311,12 +307,11 @@ func (d *DeployerProvider) modifyListenerCertificate(ctx context.Context, cloudL } } updateListenerResp, err := d.sdkClient.UpdateListener(updateListenerReq) + d.logger.Debug("sdk request 'elb.UpdateListener'", slog.Any("request", updateListenerReq), slog.Any("response", updateListenerResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'elb.UpdateListener'") } - d.logger.Logt("已更新 ELB 监听器", updateListenerResp) - return nil } diff --git a/internal/pkg/core/deployer/providers/huaweicloud-waf/huaweicloud_waf.go b/internal/pkg/core/deployer/providers/huaweicloud-waf/huaweicloud_waf.go index 2342edfa..9d124191 100644 --- a/internal/pkg/core/deployer/providers/huaweicloud-waf/huaweicloud_waf.go +++ b/internal/pkg/core/deployer/providers/huaweicloud-waf/huaweicloud_waf.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "log/slog" "strings" "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic" @@ -17,7 +18,6 @@ import ( 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" @@ -42,7 +42,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *hcWaf.WafClient sslUploader uploader.Uploader } @@ -70,14 +70,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -87,7 +92,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") } else { - d.logger.Logt("certificate file uploaded", upres) + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } // 根据部署资源类型决定部署方式 @@ -125,10 +130,9 @@ func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPem stri CertificateId: d.config.CertificateId, } showCertificateResp, err := d.sdkClient.ShowCertificate(showCertificateReq) + d.logger.Debug("sdk request 'waf.ShowCertificate'", slog.Any("request", showCertificateReq), slog.Any("response", showCertificateResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'waf.ShowCertificate'") - } else { - d.logger.Logt("已获取 WAF 证书", showCertificateResp) } // 更新证书 @@ -142,10 +146,9 @@ func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPem stri }, } updateCertificateResp, err := d.sdkClient.UpdateCertificate(updateCertificateReq) + d.logger.Debug("sdk request 'waf.UpdateCertificate'", slog.Any("request", updateCertificateReq), slog.Any("response", updateCertificateResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'waf.UpdateCertificate'") - } else { - d.logger.Logt("已更新 WAF 证书", updateCertificateResp) } return nil @@ -161,7 +164,7 @@ func (d *DeployerProvider) deployToCloudServer(ctx context.Context, certPem stri if err != nil { return xerrors.Wrap(err, "failed to upload certificate file") } else { - d.logger.Logt("certificate file uploaded", upres) + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } // 遍历查询云模式防护域名列表,获取防护域名 ID @@ -176,6 +179,7 @@ func (d *DeployerProvider) deployToCloudServer(ctx context.Context, certPem stri Pagesize: hwsdk.Int32Ptr(listHostPageSize), } listHostResp, err := d.sdkClient.ListHost(listHostReq) + d.logger.Debug("sdk request 'waf.ListHost'", slog.Any("request", listHostReq), slog.Any("response", listHostResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'waf.ListHost'") } @@ -209,10 +213,9 @@ func (d *DeployerProvider) deployToCloudServer(ctx context.Context, certPem stri }, } updateHostResp, err := d.sdkClient.UpdateHost(updateHostReq) + d.logger.Debug("sdk request 'waf.UpdateHost'", slog.Any("request", updateHostReq), slog.Any("response", updateHostResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'waf.UpdateHost'") - } else { - d.logger.Logt("已更新云模式防护域名的配置", updateHostResp) } return nil @@ -228,7 +231,7 @@ func (d *DeployerProvider) deployToPremiumHost(ctx context.Context, certPem stri if err != nil { return xerrors.Wrap(err, "failed to upload certificate file") } else { - d.logger.Logt("certificate file uploaded", upres) + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } // 遍历查询独享模式域名列表,获取防护域名 ID @@ -243,6 +246,7 @@ func (d *DeployerProvider) deployToPremiumHost(ctx context.Context, certPem stri Pagesize: hwsdk.StringPtr(fmt.Sprintf("%d", listPremiumHostPageSize)), } listPremiumHostResp, err := d.sdkClient.ListPremiumHost(listPremiumHostReq) + d.logger.Debug("sdk request 'waf.ListPremiumHost'", slog.Any("request", listPremiumHostReq), slog.Any("response", listPremiumHostResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'waf.ListPremiumHost'") } @@ -276,10 +280,9 @@ func (d *DeployerProvider) deployToPremiumHost(ctx context.Context, certPem stri }, } updatePremiumHostResp, err := d.sdkClient.UpdatePremiumHost(updatePremiumHostReq) + d.logger.Debug("sdk request 'waf.UpdatePremiumHost'", slog.Any("request", updatePremiumHostReq), slog.Any("response", updatePremiumHostResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'waf.UpdatePremiumHost'") - } else { - d.logger.Logt("已修改独享模式域名配置", updatePremiumHostResp) } return nil diff --git a/internal/pkg/core/deployer/providers/jdcloud-alb/jdcloud_alb.go b/internal/pkg/core/deployer/providers/jdcloud-alb/jdcloud_alb.go index 41625b64..b1ab981f 100644 --- a/internal/pkg/core/deployer/providers/jdcloud-alb/jdcloud_alb.go +++ b/internal/pkg/core/deployer/providers/jdcloud-alb/jdcloud_alb.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "log/slog" "strings" jdCore "github.com/jdcloud-api/jdcloud-sdk-go/core" @@ -14,10 +15,9 @@ import ( 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" + "github.com/usual2970/certimate/internal/pkg/utils/sliceutil" ) type DeployerConfig struct { @@ -42,7 +42,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *jdLbClient.LbClient sslUploader uploader.Uploader } @@ -69,14 +69,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -86,7 +91,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") } else { - d.logger.Logt("certificate file uploaded", upres) + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } // 根据部署资源类型决定部署方式 @@ -117,10 +122,9 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId // 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) + d.logger.Debug("sdk request 'lb.DescribeLoadBalancer'", slog.Any("request", describeLoadBalancerReq), slog.Any("response", describeLoadBalancerResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'lb.DescribeLoadBalancer'") - } else { - d.logger.Logt("已查询到负载均衡器详情", describeLoadBalancerResp) } // 查询监听器列表 @@ -134,6 +138,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId describeListenersReq.SetPageSize(describeListenersPageNumber) describeListenersReq.SetPageSize(describeListenersPageSize) describeListenersResp, err := d.sdkClient.DescribeListeners(describeListenersReq) + d.logger.Debug("sdk request 'lb.DescribeListeners'", slog.Any("request", describeListenersReq), slog.Any("response", describeListenersResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'lb.DescribeListeners'") } @@ -153,9 +158,9 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId // 遍历更新监听器证书 if len(listenerIds) == 0 { - return errors.New("listener not found") + d.logger.Info("no listeners to deploy") } else { - d.logger.Logt("已查询到负载均衡器下的全部 HTTPS/TLS 监听器", listenerIds) + d.logger.Info("found https/tls listeners to deploy", slog.Any("listenerIds", listenerIds)) var errs []error @@ -191,10 +196,9 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL // REF: https://docs.jdcloud.com/cn/load-balancer/api/describelistener describeListenerReq := jdLbApi.NewDescribeListenerRequest(d.config.RegionId, cloudListenerId) describeListenerResp, err := d.sdkClient.DescribeListener(describeListenerReq) + d.logger.Debug("sdk request 'lb.DescribeListener'", slog.Any("request", describeListenerReq), slog.Any("response", describeListenerResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'lb.DescribeListener'") - } else { - d.logger.Logt("已查询到监听器详情", describeListenerResp) } if d.config.Domain == "" { @@ -205,15 +209,14 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL updateListenerReq := jdLbApi.NewUpdateListenerRequest(d.config.RegionId, cloudListenerId) updateListenerReq.SetCertificateSpecs([]jdLbModel.CertificateSpec{{CertificateId: cloudCertId}}) updateListenerResp, err := d.sdkClient.UpdateListener(updateListenerReq) + d.logger.Debug("sdk request 'lb.UpdateListener'", slog.Any("request", updateListenerReq), slog.Any("response", updateListenerResp)) 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 { + extCertSpecs := sliceutil.Filter(describeListenerResp.Result.Listener.ExtensionCertificateSpecs, func(extCertSpec jdLbModel.ExtensionCertificateSpec) bool { return extCertSpec.Domain == d.config.Domain }) if len(extCertSpecs) == 0 { @@ -225,7 +228,7 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL updateListenerCertificatesReq := jdLbApi.NewUpdateListenerCertificatesRequest( d.config.RegionId, cloudListenerId, - slices.Map(extCertSpecs, func(extCertSpec jdLbModel.ExtensionCertificateSpec) jdLbModel.ExtCertificateUpdateSpec { + sliceutil.Map(extCertSpecs, func(extCertSpec jdLbModel.ExtensionCertificateSpec) jdLbModel.ExtCertificateUpdateSpec { return jdLbModel.ExtCertificateUpdateSpec{ CertificateBindId: extCertSpec.CertificateBindId, CertificateId: &cloudCertId, @@ -234,10 +237,9 @@ func (d *DeployerProvider) updateListenerCertificate(ctx context.Context, cloudL }), ) updateListenerCertificatesResp, err := d.sdkClient.UpdateListenerCertificates(updateListenerCertificatesReq) + d.logger.Debug("sdk request 'lb.UpdateListenerCertificates'", slog.Any("request", updateListenerCertificatesReq), slog.Any("response", updateListenerCertificatesResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'lb.UpdateListenerCertificates'") - } else { - d.logger.Logt("已批量修改扩展证书", updateListenerCertificatesResp) } } diff --git a/internal/pkg/core/deployer/providers/jdcloud-cdn/jdcloud_cdn.go b/internal/pkg/core/deployer/providers/jdcloud-cdn/jdcloud_cdn.go index d5bdae4f..3c473961 100644 --- a/internal/pkg/core/deployer/providers/jdcloud-cdn/jdcloud_cdn.go +++ b/internal/pkg/core/deployer/providers/jdcloud-cdn/jdcloud_cdn.go @@ -2,6 +2,7 @@ import ( "context" + "log/slog" jdCore "github.com/jdcloud-api/jdcloud-sdk-go/core" jdCdnApi "github.com/jdcloud-api/jdcloud-sdk-go/services/cdn/apis" @@ -9,7 +10,6 @@ import ( 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" ) @@ -25,7 +25,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *jdCdnClient.CdnClient sslUploader uploader.Uploader } @@ -52,14 +52,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -68,10 +73,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe // REF: https://docs.jdcloud.com/cn/cdn/api/querydomainconfig queryDomainConfigReq := jdCdnApi.NewQueryDomainConfigRequest(d.config.Domain) queryDomainConfigResp, err := d.sdkClient.QueryDomainConfig(queryDomainConfigReq) + d.logger.Debug("sdk request 'cdn.QueryDomainConfig'", slog.Any("request", queryDomainConfigReq), slog.Any("response", queryDomainConfigResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.QueryDomainConfig'") - } else { - d.logger.Logt("已查询到域名配置信息", queryDomainConfigResp) } // 上传证书到 SSL @@ -79,7 +83,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") } else { - d.logger.Logt("certificate file uploaded", upres) + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } // 设置通讯协议 @@ -92,10 +96,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe setHttpTypeReq.SetSslCertId(upres.CertId) setHttpTypeReq.SetJumpType(queryDomainConfigResp.Result.HttpsJumpType) setHttpTypeResp, err := d.sdkClient.SetHttpType(setHttpTypeReq) + d.logger.Debug("sdk request 'cdn.QueryDomainConfig'", slog.Any("request", setHttpTypeReq), slog.Any("response", setHttpTypeResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.SetHttpType'") - } else { - d.logger.Logt("已设置通讯协议", setHttpTypeResp) } return &deployer.DeployResult{}, nil diff --git a/internal/pkg/core/deployer/providers/jdcloud-live/jdcloud_live.go b/internal/pkg/core/deployer/providers/jdcloud-live/jdcloud_live.go index 7998fb16..ea125408 100644 --- a/internal/pkg/core/deployer/providers/jdcloud-live/jdcloud_live.go +++ b/internal/pkg/core/deployer/providers/jdcloud-live/jdcloud_live.go @@ -2,6 +2,7 @@ import ( "context" + "log/slog" jdCore "github.com/jdcloud-api/jdcloud-sdk-go/core" jdLiveApi "github.com/jdcloud-api/jdcloud-sdk-go/services/live/apis" @@ -9,7 +10,6 @@ import ( xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/pkg/core/deployer" - "github.com/usual2970/certimate/internal/pkg/core/logger" ) type DeployerConfig struct { @@ -23,7 +23,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *jdLiveClient.LiveClient } @@ -41,13 +41,17 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } return d } @@ -58,10 +62,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe setLiveDomainCertificateReq.SetCert(certPem) setLiveDomainCertificateReq.SetKey(privkeyPem) setLiveDomainCertificateResp, err := d.sdkClient.SetLiveDomainCertificate(setLiveDomainCertificateReq) + d.logger.Debug("sdk request 'live.SetLiveDomainCertificate'", slog.Any("request", setLiveDomainCertificateReq), slog.Any("response", setLiveDomainCertificateResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'live.SetLiveDomainCertificate'") - } else { - d.logger.Logt("已设置直播证书", setLiveDomainCertificateResp) } return &deployer.DeployResult{}, nil diff --git a/internal/pkg/core/deployer/providers/jdcloud-vod/jdcloud_vod.go b/internal/pkg/core/deployer/providers/jdcloud-vod/jdcloud_vod.go index b83fd430..69410c78 100644 --- a/internal/pkg/core/deployer/providers/jdcloud-vod/jdcloud_vod.go +++ b/internal/pkg/core/deployer/providers/jdcloud-vod/jdcloud_vod.go @@ -3,6 +3,7 @@ import ( "context" "fmt" + "log/slog" "strconv" "time" @@ -12,7 +13,6 @@ import ( xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/pkg/core/deployer" - "github.com/usual2970/certimate/internal/pkg/core/logger" ) type DeployerConfig struct { @@ -26,7 +26,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *jdVodClient.VodClient } @@ -44,13 +44,17 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } return d } @@ -65,6 +69,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe listDomainsReq.SetPageNumber(1) listDomainsReq.SetPageSize(100) listDomainsResp, err := d.sdkClient.ListDomains(listDomainsReq) + d.logger.Debug("sdk request 'vod.ListDomains'", slog.Any("request", listDomainsReq), slog.Any("response", listDomainsResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'vod.ListDomains'") } @@ -90,10 +95,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe // REF: https://docs.jdcloud.com/cn/video-on-demand/api/gethttpssl getHttpSslReq := jdVodApi.NewGetHttpSslRequest(domainId) getHttpSslResp, err := d.sdkClient.GetHttpSsl(getHttpSslReq) + d.logger.Debug("sdk request 'vod.GetHttpSsl'", slog.Any("request", getHttpSslReq), slog.Any("response", getHttpSslResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'vod.GetHttpSsl'") - } else { - d.logger.Logt("已查询到域名 SSL 配置", getHttpSslResp) } // 设置域名 SSL 配置 @@ -106,10 +110,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe setHttpSslReq.SetJumpType(getHttpSslResp.Result.JumpType) setHttpSslReq.SetEnabled(true) setHttpSslResp, err := d.sdkClient.SetHttpSsl(setHttpSslReq) + d.logger.Debug("sdk request 'vod.SetHttpSsl'", slog.Any("request", setHttpSslReq), slog.Any("response", setHttpSslResp)) 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 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 c97e4386..7ca92e41 100644 --- a/internal/pkg/core/deployer/providers/k8s-secret/k8s_secret.go +++ b/internal/pkg/core/deployer/providers/k8s-secret/k8s_secret.go @@ -1,8 +1,9 @@ -package k8ssecret +package k8ssecret import ( "context" "errors" + "log/slog" "strings" xerrors "github.com/pkg/errors" @@ -13,8 +14,7 @@ import ( "k8s.io/client-go/tools/clientcmd" "github.com/usual2970/certimate/internal/pkg/core/deployer" - "github.com/usual2970/certimate/internal/pkg/core/logger" - "github.com/usual2970/certimate/internal/pkg/utils/certs" + "github.com/usual2970/certimate/internal/pkg/utils/certutil" ) type DeployerConfig struct { @@ -34,7 +34,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger } var _ deployer.Deployer = (*DeployerProvider)(nil) @@ -45,13 +45,17 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { } return &DeployerProvider{ - logger: logger.NewNilLogger(), + logger: slog.Default(), config: config, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } return d } @@ -72,7 +76,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe return nil, errors.New("config `secretDataKeyForKey` is required") } - certX509, err := certs.ParseCertificateFromPEM(certPem) + certX509, err := certutil.ParseCertificateFromPEM(certPem) if err != nil { return nil, err } @@ -110,11 +114,11 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe secretPayload.Data[d.config.SecretDataKeyForCrt] = []byte(certPem) secretPayload.Data[d.config.SecretDataKeyForKey] = []byte(privkeyPem) - _, err = client.CoreV1().Secrets(d.config.Namespace).Create(context.TODO(), secretPayload, k8sMeta.CreateOptions{}) + secretPayload, err = client.CoreV1().Secrets(d.config.Namespace).Create(context.TODO(), secretPayload, k8sMeta.CreateOptions{}) + d.logger.Debug("k8s operate 'Secrets.Create'", slog.String("namespace", d.config.Namespace), slog.Any("secret", secretPayload)) if err != nil { return nil, xerrors.Wrap(err, "failed to create k8s secret") } else { - d.logger.Logf("k8s secret created", secretPayload) return &deployer.DeployResult{}, nil } } @@ -134,12 +138,11 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe secretPayload.Data[d.config.SecretDataKeyForCrt] = []byte(certPem) secretPayload.Data[d.config.SecretDataKeyForKey] = []byte(privkeyPem) secretPayload, err = client.CoreV1().Secrets(d.config.Namespace).Update(context.TODO(), secretPayload, k8sMeta.UpdateOptions{}) + d.logger.Debug("k8s operate 'Secrets.Update'", slog.String("namespace", d.config.Namespace), slog.Any("secret", secretPayload)) if err != nil { return nil, xerrors.Wrap(err, "failed to update k8s secret") } - d.logger.Logf("k8s secret updated", secretPayload) - return &deployer.DeployResult{}, nil } diff --git a/internal/pkg/core/deployer/providers/local/local.go b/internal/pkg/core/deployer/providers/local/local.go index 7952f63c..b4d07711 100644 --- a/internal/pkg/core/deployer/providers/local/local.go +++ b/internal/pkg/core/deployer/providers/local/local.go @@ -1,18 +1,18 @@ -package local +package local import ( "bytes" "context" "fmt" + "log/slog" "os/exec" "runtime" 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/certs" - "github.com/usual2970/certimate/internal/pkg/utils/files" + "github.com/usual2970/certimate/internal/pkg/utils/certutil" + "github.com/usual2970/certimate/internal/pkg/utils/fileutil" ) type DeployerConfig struct { @@ -45,7 +45,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger } var _ deployer.Deployer = (*DeployerProvider)(nil) @@ -57,12 +57,16 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } return d } @@ -70,55 +74,48 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe // 执行前置命令 if d.config.PreCommand != "" { stdout, stderr, err := execCommand(d.config.ShellEnv, d.config.PreCommand) + d.logger.Debug("run pre-command", slog.String("stdout", stdout), slog.String("stderr", stderr)) if err != nil { return nil, xerrors.Wrapf(err, "failed to execute pre-command, stdout: %s, stderr: %s", stdout, stderr) } - - d.logger.Logt("pre-command executed", stdout) } // 写入证书和私钥文件 switch d.config.OutputFormat { case OUTPUT_FORMAT_PEM: - if err := files.WriteString(d.config.OutputCertPath, certPem); err != nil { + if err := fileutil.WriteString(d.config.OutputCertPath, certPem); err != nil { return nil, xerrors.Wrap(err, "failed to save certificate file") } + d.logger.Info("ssl certificate file saved", slog.String("path", d.config.OutputCertPath)) - d.logger.Logt("certificate file saved") - - if err := files.WriteString(d.config.OutputKeyPath, privkeyPem); err != nil { + if err := fileutil.WriteString(d.config.OutputKeyPath, privkeyPem); err != nil { return nil, xerrors.Wrap(err, "failed to save private key file") } - - d.logger.Logt("private key file saved") + d.logger.Info("ssl private key file saved", slog.String("path", d.config.OutputKeyPath)) case OUTPUT_FORMAT_PFX: - pfxData, err := certs.TransformCertificateFromPEMToPFX(certPem, privkeyPem, d.config.PfxPassword) + pfxData, err := certutil.TransformCertificateFromPEMToPFX(certPem, privkeyPem, d.config.PfxPassword) if err != nil { return nil, xerrors.Wrap(err, "failed to transform certificate to PFX") } + d.logger.Info("ssl certificate transformed to pfx") - d.logger.Logt("certificate transformed to PFX") - - if err := files.Write(d.config.OutputCertPath, pfxData); err != nil { + if err := fileutil.Write(d.config.OutputCertPath, pfxData); err != nil { return nil, xerrors.Wrap(err, "failed to save certificate file") } - - d.logger.Logt("certificate file saved") + d.logger.Info("ssl certificate file saved", slog.String("path", d.config.OutputCertPath)) case OUTPUT_FORMAT_JKS: - jksData, err := certs.TransformCertificateFromPEMToJKS(certPem, privkeyPem, d.config.JksAlias, d.config.JksKeypass, d.config.JksStorepass) + jksData, err := certutil.TransformCertificateFromPEMToJKS(certPem, privkeyPem, d.config.JksAlias, d.config.JksKeypass, d.config.JksStorepass) if err != nil { return nil, xerrors.Wrap(err, "failed to transform certificate to JKS") } + d.logger.Info("ssl certificate transformed to jks") - d.logger.Logt("certificate transformed to JKS") - - if err := files.Write(d.config.OutputCertPath, jksData); err != nil { + if err := fileutil.Write(d.config.OutputCertPath, jksData); err != nil { return nil, xerrors.Wrap(err, "failed to save certificate file") } - - d.logger.Logt("certificate file uploaded") + d.logger.Info("ssl certificate file saved", slog.String("path", d.config.OutputCertPath)) default: return nil, fmt.Errorf("unsupported output format: %s", d.config.OutputFormat) @@ -127,11 +124,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe // 执行后置命令 if d.config.PostCommand != "" { stdout, stderr, err := execCommand(d.config.ShellEnv, d.config.PostCommand) + d.logger.Debug("run post-command", slog.String("stdout", stdout), slog.String("stderr", stderr)) if err != nil { return nil, xerrors.Wrapf(err, "failed to execute post-command, stdout: %s, stderr: %s", stdout, stderr) } - - d.logger.Logt("post-command executed", stdout) } return &deployer.DeployResult{}, nil 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 cdb62b8c..e8166afd 100644 --- a/internal/pkg/core/deployer/providers/qiniu-cdn/qiniu_cdn.go +++ b/internal/pkg/core/deployer/providers/qiniu-cdn/qiniu_cdn.go @@ -2,13 +2,13 @@ import ( "context" + "log/slog" "strings" xerrors "github.com/pkg/errors" "github.com/qiniu/go-sdk/v7/auth" "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/qiniu-sslcert" qiniusdk "github.com/usual2970/certimate/internal/pkg/vendors/qiniu-sdk" @@ -25,7 +25,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *qiniusdk.Client sslUploader uploader.Uploader } @@ -49,14 +49,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -65,38 +70,35 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - // "*.example.com" → ".example.com",适配七牛云 CDN 要求的泛域名格式 domain := strings.TrimPrefix(d.config.Domain, "*") // 获取域名信息 // REF: https://developer.qiniu.com/fusion/4246/the-domain-name getDomainInfoResp, err := d.sdkClient.GetDomainInfo(context.TODO(), domain) + d.logger.Debug("sdk request 'cdn.GetDomainInfo'", slog.String("request.domain", domain), slog.Any("response", getDomainInfoResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.GetDomainInfo'") } - d.logger.Logt("已获取域名信息", getDomainInfoResp) - // 判断域名是否已启用 HTTPS。如果已启用,修改域名证书;否则,启用 HTTPS // REF: https://developer.qiniu.com/fusion/4246/the-domain-name - if getDomainInfoResp.Https != nil && getDomainInfoResp.Https.CertID != "" { - modifyDomainHttpsConfResp, err := d.sdkClient.ModifyDomainHttpsConf(context.TODO(), domain, upres.CertId, getDomainInfoResp.Https.ForceHttps, getDomainInfoResp.Https.Http2Enable) - if err != nil { - return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.ModifyDomainHttpsConf'") - } - - d.logger.Logt("已修改域名证书", modifyDomainHttpsConfResp) - } else { + if getDomainInfoResp.Https == nil || getDomainInfoResp.Https.CertID == "" { enableDomainHttpsResp, err := d.sdkClient.EnableDomainHttps(context.TODO(), domain, upres.CertId, true, true) + d.logger.Debug("sdk request 'cdn.EnableDomainHttps'", slog.String("request.domain", domain), slog.String("request.certId", upres.CertId), slog.Any("response", enableDomainHttpsResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.EnableDomainHttps'") } - - d.logger.Logt("已将域名升级为 HTTPS", enableDomainHttpsResp) + } else if getDomainInfoResp.Https.CertID != upres.CertId { + modifyDomainHttpsConfResp, err := d.sdkClient.ModifyDomainHttpsConf(context.TODO(), domain, upres.CertId, getDomainInfoResp.Https.ForceHttps, getDomainInfoResp.Https.Http2Enable) + d.logger.Debug("sdk request 'cdn.ModifyDomainHttpsConf'", slog.String("request.domain", domain), slog.String("request.certId", upres.CertId), slog.Any("response", modifyDomainHttpsConfResp)) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.ModifyDomainHttpsConf'") + } } return &deployer.DeployResult{}, nil 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 b9121694..f684253b 100644 --- a/internal/pkg/core/deployer/providers/qiniu-pili/qiniu_pili.go +++ b/internal/pkg/core/deployer/providers/qiniu-pili/qiniu_pili.go @@ -2,12 +2,12 @@ import ( "context" + "log/slog" xerrors "github.com/pkg/errors" "github.com/qiniu/go-sdk/v7/pili" "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/qiniu-sslcert" ) @@ -25,7 +25,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *pili.Manager sslUploader uploader.Uploader } @@ -49,14 +49,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: manager, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -65,10 +70,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - // 修改域名证书配置 // REF: https://developer.qiniu.com/pili/9910/pili-service-sdk#66 setDomainCertReq := pili.SetDomainCertRequest{ @@ -77,11 +82,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe CertName: upres.CertName, } err = d.sdkClient.SetDomainCert(context.TODO(), setDomainCertReq) + d.logger.Debug("sdk request 'pili.SetDomainCert'", slog.Any("request", setDomainCertReq)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'pili.SetDomainCert'") } - d.logger.Logt("已修改域名证书配置") - return &deployer.DeployResult{}, nil } diff --git a/internal/pkg/core/deployer/providers/safeline/safeline.go b/internal/pkg/core/deployer/providers/safeline/safeline.go index d0186100..8079027f 100644 --- a/internal/pkg/core/deployer/providers/safeline/safeline.go +++ b/internal/pkg/core/deployer/providers/safeline/safeline.go @@ -5,12 +5,12 @@ import ( "crypto/tls" "errors" "fmt" + "log/slog" "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" ) @@ -30,7 +30,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *safelinesdk.Client } @@ -48,13 +48,17 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } return d } @@ -88,10 +92,9 @@ func (d *DeployerProvider) deployToCertificate(ctx context.Context, certPem stri }, } updateCertificateResp, err := d.sdkClient.UpdateCertificate(updateCertificateReq) + d.logger.Debug("sdk request 'safeline.UpdateCertificate'", slog.Any("request", updateCertificateReq), slog.Any("response", updateCertificateResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'safeline.UpdateCertificate'") - } else { - d.logger.Logt("已更新证书", updateCertificateResp) } return nil diff --git a/internal/pkg/core/deployer/providers/ssh/ssh.go b/internal/pkg/core/deployer/providers/ssh/ssh.go index a1617327..8fba9490 100644 --- a/internal/pkg/core/deployer/providers/ssh/ssh.go +++ b/internal/pkg/core/deployer/providers/ssh/ssh.go @@ -1,9 +1,10 @@ -package ssh +package ssh import ( "bytes" "context" "fmt" + "log/slog" "os" "path/filepath" @@ -13,8 +14,7 @@ import ( "golang.org/x/crypto/ssh" "github.com/usual2970/certimate/internal/pkg/core/deployer" - "github.com/usual2970/certimate/internal/pkg/core/logger" - "github.com/usual2970/certimate/internal/pkg/utils/certs" + "github.com/usual2970/certimate/internal/pkg/utils/certutil" ) type DeployerConfig struct { @@ -60,7 +60,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger } var _ deployer.Deployer = (*DeployerProvider)(nil) @@ -72,12 +72,16 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } return d } @@ -96,16 +100,15 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe } defer client.Close() - d.logger.Logt("SSH connected") + d.logger.Info("ssh connected") // 执行前置命令 if d.config.PreCommand != "" { stdout, stderr, err := execSshCommand(client, d.config.PreCommand) + d.logger.Debug("run pre-command", slog.String("stdout", stdout), slog.String("stderr", stderr)) if err != nil { return nil, xerrors.Wrapf(err, "failed to execute pre-command: stdout: %s, stderr: %s", stdout, stderr) } - - d.logger.Logt("SSH pre-command executed", stdout) } // 上传证书和私钥文件 @@ -114,42 +117,36 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe if err := writeFileString(client, d.config.UseSCP, d.config.OutputCertPath, certPem); err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") } - - d.logger.Logt("certificate file uploaded") + d.logger.Info("ssl certificate file uploaded", slog.String("path", d.config.OutputCertPath)) if err := writeFileString(client, d.config.UseSCP, d.config.OutputKeyPath, privkeyPem); err != nil { return nil, xerrors.Wrap(err, "failed to upload private key file") } - - d.logger.Logt("private key file uploaded") + d.logger.Info("ssl private key file uploaded", slog.String("path", d.config.OutputKeyPath)) case OUTPUT_FORMAT_PFX: - pfxData, err := certs.TransformCertificateFromPEMToPFX(certPem, privkeyPem, d.config.PfxPassword) + pfxData, err := certutil.TransformCertificateFromPEMToPFX(certPem, privkeyPem, d.config.PfxPassword) if err != nil { return nil, xerrors.Wrap(err, "failed to transform certificate to PFX") } - - d.logger.Logt("certificate transformed to PFX") + d.logger.Info("ssl certificate transformed to pfx") if err := writeFile(client, d.config.UseSCP, d.config.OutputCertPath, pfxData); err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") } - - d.logger.Logt("certificate file uploaded") + d.logger.Info("ssl certificate file uploaded", slog.String("path", d.config.OutputCertPath)) case OUTPUT_FORMAT_JKS: - jksData, err := certs.TransformCertificateFromPEMToJKS(certPem, privkeyPem, d.config.JksAlias, d.config.JksKeypass, d.config.JksStorepass) + jksData, err := certutil.TransformCertificateFromPEMToJKS(certPem, privkeyPem, d.config.JksAlias, d.config.JksKeypass, d.config.JksStorepass) if err != nil { return nil, xerrors.Wrap(err, "failed to transform certificate to JKS") } - - d.logger.Logt("certificate transformed to JKS") + d.logger.Info("ssl certificate transformed to jks") if err := writeFile(client, d.config.UseSCP, d.config.OutputCertPath, jksData); err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") } - - d.logger.Logt("certificate file uploaded") + d.logger.Info("ssl certificate file uploaded", slog.String("path", d.config.OutputCertPath)) default: return nil, fmt.Errorf("unsupported output format: %s", d.config.OutputFormat) @@ -158,11 +155,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe // 执行后置命令 if d.config.PostCommand != "" { stdout, stderr, err := execSshCommand(client, d.config.PostCommand) + d.logger.Debug("run post-command", slog.String("stdout", stdout), slog.String("stderr", stderr)) if err != nil { return nil, xerrors.Wrapf(err, "failed to execute post-command, stdout: %s, stderr: %s", stdout, stderr) } - - d.logger.Logt("SSH post-command executed", stdout) } return &deployer.DeployResult{}, nil 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 1784354d..da76c955 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-cdn/tencentcloud_cdn.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-cdn/tencentcloud_cdn.go @@ -2,6 +2,7 @@ import ( "context" + "log/slog" "strings" xerrors "github.com/pkg/errors" @@ -12,7 +13,6 @@ import ( "golang.org/x/exp/slices" "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" ) @@ -28,7 +28,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClients *wSdkClients sslUploader uploader.Uploader } @@ -60,14 +60,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClients: clients, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -76,10 +81,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - // 获取待部署的 CDN 实例 // 如果是泛域名,根据证书匹配 CDN 实例 instanceIds := make([]string, 0) @@ -111,8 +116,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe } if len(instanceIds) == 0 { - d.logger.Logt("已部署过或没有要部署的 CDN 实例") + d.logger.Info("no cdn instances to deploy") } else { + d.logger.Info("found cdn instances to deploy", slog.Any("instanceIds", instanceIds)) + // 证书部署到 CDN 实例 // REF: https://cloud.tencent.com/document/product/400/91667 deployCertificateInstanceReq := tcSsl.NewDeployCertificateInstanceRequest() @@ -121,11 +128,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe deployCertificateInstanceReq.Status = common.Int64Ptr(1) deployCertificateInstanceReq.InstanceIdList = common.StringPtrs(instanceIds) deployCertificateInstanceResp, err := d.sdkClients.ssl.DeployCertificateInstance(deployCertificateInstanceReq) + d.logger.Debug("sdk request 'ssl.DeployCertificateInstance'", slog.Any("request", deployCertificateInstanceReq), slog.Any("response", deployCertificateInstanceResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'ssl.DeployCertificateInstance'") } - - d.logger.Logt("已部署证书到云资源实例", deployCertificateInstanceResp.Response) } return &deployer.DeployResult{}, nil @@ -138,6 +144,7 @@ func (d *DeployerProvider) getDomainsByCertificateId(cloudCertId string) ([]stri describeCertDomainsReq.CertId = common.StringPtr(cloudCertId) describeCertDomainsReq.Product = common.StringPtr("cdn") describeCertDomainsResp, err := d.sdkClients.cdn.DescribeCertDomains(describeCertDomainsReq) + d.logger.Debug("sdk request 'cdn.DescribeCertDomains'", slog.Any("request", describeCertDomainsReq), slog.Any("response", describeCertDomainsResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.DescribeCertDomains'") } @@ -159,6 +166,7 @@ func (d *DeployerProvider) getDeployedDomainsByCertificateId(cloudCertId string) describeDeployedResourcesReq.CertificateIds = common.StringPtrs([]string{cloudCertId}) describeDeployedResourcesReq.ResourceType = common.StringPtr("cdn") describeDeployedResourcesResp, err := d.sdkClients.ssl.DescribeDeployedResources(describeDeployedResourcesReq) + d.logger.Debug("sdk request 'cdn.DescribeDeployedResources'", slog.Any("request", describeDeployedResourcesReq), slog.Any("response", describeDeployedResourcesResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.DescribeDeployedResources'") } 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 521f3e34..3f4e6600 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-clb/tencentcloud_clb.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-clb/tencentcloud_clb.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "log/slog" xerrors "github.com/pkg/errors" tcClb "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb/v20180317" @@ -12,7 +13,6 @@ import ( tcSsl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205" "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" ) @@ -39,7 +39,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClients *wSdkClients sslUploader uploader.Uploader } @@ -71,14 +71,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClients: clients, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -87,10 +92,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - // 根据部署资源类型决定部署方式 switch d.config.ResourceType { case RESOURCE_TYPE_VIA_SSLDEPLOY: @@ -142,12 +147,11 @@ func (d *DeployerProvider) deployViaSslService(ctx context.Context, cloudCertId 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) + d.logger.Debug("sdk request 'ssl.DeployCertificateInstance'", slog.Any("request", deployCertificateInstanceReq), slog.Any("response", deployCertificateInstanceResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'ssl.DeployCertificateInstance'") } - d.logger.Logt("已部署证书到云资源实例", deployCertificateInstanceResp.Response) - return nil } @@ -162,6 +166,7 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId describeListenersReq := tcClb.NewDescribeListenersRequest() describeListenersReq.LoadBalancerId = common.StringPtr(d.config.LoadbalancerId) describeListenersResp, err := d.sdkClients.clb.DescribeListeners(describeListenersReq) + d.logger.Debug("sdk request 'clb.DescribeListeners'", slog.Any("request", describeListenersReq), slog.Any("response", describeListenersResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'clb.DescribeListeners'") } else { @@ -176,12 +181,11 @@ func (d *DeployerProvider) deployToLoadbalancer(ctx context.Context, cloudCertId } } - d.logger.Logt("已查询到负载均衡器下的监听器", listenerIds) - // 遍历更新监听器证书 if len(listenerIds) == 0 { - return errors.New("listener not found") + d.logger.Info("no clb listeners to deploy") } else { + d.logger.Info("found https/tcpssl/quic listeners to deploy", slog.Any("listenerIds", listenerIds)) var errs []error for _, listenerId := range listenerIds { @@ -236,12 +240,11 @@ func (d *DeployerProvider) deployToRuleDomain(ctx context.Context, cloudCertId s CertId: common.StringPtr(cloudCertId), } modifyDomainAttributesResp, err := d.sdkClients.clb.ModifyDomainAttributes(modifyDomainAttributesReq) + d.logger.Debug("sdk request 'clb.ModifyDomainAttributes'", slog.Any("request", modifyDomainAttributesReq), slog.Any("response", modifyDomainAttributesResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'clb.ModifyDomainAttributes'") } - d.logger.Logt("已修改七层监听器转发规则的域名级别属性", modifyDomainAttributesResp.Response) - return nil } @@ -252,15 +255,13 @@ func (d *DeployerProvider) modifyListenerCertificate(ctx context.Context, cloudL describeListenersReq.LoadBalancerId = common.StringPtr(cloudLoadbalancerId) describeListenersReq.ListenerIds = common.StringPtrs([]string{cloudListenerId}) describeListenersResp, err := d.sdkClients.clb.DescribeListeners(describeListenersReq) + d.logger.Debug("sdk request 'clb.DescribeListeners'", slog.Any("request", describeListenersReq), slog.Any("response", describeListenersResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'clb.DescribeListeners'") - } - if len(describeListenersResp.Response.Listeners) == 0 { + } else if len(describeListenersResp.Response.Listeners) == 0 { return errors.New("listener not found") } - d.logger.Logt("已查询到监听器属性", describeListenersResp.Response) - // 修改监听器属性 // REF: https://cloud.tencent.com/document/product/214/30681 modifyListenerReq := tcClb.NewModifyListenerRequest() @@ -274,12 +275,11 @@ func (d *DeployerProvider) modifyListenerCertificate(ctx context.Context, cloudL modifyListenerReq.Certificate.SSLMode = common.StringPtr("UNIDIRECTIONAL") } modifyListenerResp, err := d.sdkClients.clb.ModifyListener(modifyListenerReq) + d.logger.Debug("sdk request 'clb.ModifyListener'", slog.Any("request", modifyListenerReq), slog.Any("response", modifyListenerResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'clb.ModifyListener'") } - d.logger.Logt("已修改监听器属性", modifyListenerResp.Response) - return nil } 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 becceab6..6bfa5976 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-cos/tencentcloud_cos.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-cos/tencentcloud_cos.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "log/slog" xerrors "github.com/pkg/errors" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" @@ -11,7 +12,6 @@ import ( tcSsl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205" "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" ) @@ -31,7 +31,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *tcSsl.Client sslUploader uploader.Uploader } @@ -58,14 +58,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -81,10 +86,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - // 证书部署到 COS 实例 // REF: https://cloud.tencent.com/document/product/400/91667 deployCertificateInstanceReq := tcSsl.NewDeployCertificateInstanceRequest() @@ -93,12 +98,11 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe deployCertificateInstanceReq.Status = common.Int64Ptr(1) deployCertificateInstanceReq.InstanceIdList = common.StringPtrs([]string{fmt.Sprintf("%s#%s#%s", d.config.Region, d.config.Bucket, d.config.Domain)}) deployCertificateInstanceResp, err := d.sdkClient.DeployCertificateInstance(deployCertificateInstanceReq) + d.logger.Debug("sdk request 'ssl.DeployCertificateInstance'", slog.Any("request", deployCertificateInstanceReq), slog.Any("response", deployCertificateInstanceResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'ssl.DeployCertificateInstance'") } - d.logger.Logt("已部署证书到云资源实例", deployCertificateInstanceResp.Response) - return &deployer.DeployResult{}, nil } 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 ad5dbed5..66c6d57d 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-css/tencentcloud_css.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-css/tencentcloud_css.go @@ -2,6 +2,7 @@ import ( "context" + "log/slog" xerrors "github.com/pkg/errors" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" @@ -9,7 +10,6 @@ import ( tcLive "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live/v20180801" "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" ) @@ -25,7 +25,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *tcLive.Client sslUploader uploader.Uploader } @@ -52,14 +52,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -68,10 +73,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - // 绑定证书对应的播放域名 // REF: https://cloud.tencent.com/document/product/267/78655 modifyLiveDomainCertBindingsReq := &tcLive.ModifyLiveDomainCertBindingsRequest{ @@ -84,12 +89,11 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe CloudCertId: common.StringPtr(upres.CertId), } modifyLiveDomainCertBindingsResp, err := d.sdkClient.ModifyLiveDomainCertBindings(modifyLiveDomainCertBindingsReq) + d.logger.Debug("sdk request 'live.ModifyLiveDomainCertBindings'", slog.Any("request", modifyLiveDomainCertBindingsReq), slog.Any("response", modifyLiveDomainCertBindingsResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'live.ModifyLiveDomainCertBindings'") } - d.logger.Logt("已部署证书到云资源实例", modifyLiveDomainCertBindingsResp.Response) - return &deployer.DeployResult{}, nil } 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 e9438898..3cfe70ff 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-ecdn/tencentcloud_ecdn.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-ecdn/tencentcloud_ecdn.go @@ -2,6 +2,7 @@ import ( "context" + "log/slog" "strings" xerrors "github.com/pkg/errors" @@ -11,7 +12,6 @@ import ( tcSsl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205" "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" ) @@ -27,7 +27,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClients *wSdkClients sslUploader uploader.Uploader } @@ -59,14 +59,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClients: clients, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -75,10 +80,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - // 获取待部署的 CDN 实例 // 如果是泛域名,根据证书匹配 CDN 实例 instanceIds := make([]string, 0) @@ -94,8 +99,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe } if len(instanceIds) == 0 { - d.logger.Logt("已部署过或没有要部署的 ECDN 实例") + d.logger.Info("no ecdn instances to deploy") } else { + d.logger.Info("found ecdn instances to deploy", slog.Any("instanceIds", instanceIds)) + // 证书部署到 ECDN 实例 // REF: https://cloud.tencent.com/document/product/400/91667 deployCertificateInstanceReq := tcSsl.NewDeployCertificateInstanceRequest() @@ -104,11 +111,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe deployCertificateInstanceReq.Status = common.Int64Ptr(1) deployCertificateInstanceReq.InstanceIdList = common.StringPtrs(instanceIds) deployCertificateInstanceResp, err := d.sdkClients.ssl.DeployCertificateInstance(deployCertificateInstanceReq) + d.logger.Debug("sdk request 'ssl.DeployCertificateInstance'", slog.Any("request", deployCertificateInstanceReq), slog.Any("response", deployCertificateInstanceResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'ssl.DeployCertificateInstance'") } - - d.logger.Logt("已部署证书到云资源实例", deployCertificateInstanceResp.Response) } return &deployer.DeployResult{}, nil @@ -121,6 +127,7 @@ func (d *DeployerProvider) getDomainsByCertificateId(cloudCertId string) ([]stri describeCertDomainsReq.CertId = common.StringPtr(cloudCertId) describeCertDomainsReq.Product = common.StringPtr("ecdn") describeCertDomainsResp, err := d.sdkClients.cdn.DescribeCertDomains(describeCertDomainsReq) + d.logger.Debug("sdk request 'cdn.DescribeCertDomains'", slog.Any("request", describeCertDomainsReq), slog.Any("response", describeCertDomainsResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.DescribeCertDomains'") } 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 99669038..d28c7f5a 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-eo/tencentcloud_eo.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-eo/tencentcloud_eo.go @@ -3,6 +3,7 @@ import ( "context" "errors" + "log/slog" xerrors "github.com/pkg/errors" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" @@ -11,7 +12,6 @@ import ( tcTeo "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo/v20220901" "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" ) @@ -29,7 +29,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClients *wSdkClients sslUploader uploader.Uploader } @@ -61,14 +61,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClients: clients, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -81,10 +86,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - // 配置域名证书 // REF: https://cloud.tencent.com/document/product/1552/80764 modifyHostsCertificateReq := tcTeo.NewModifyHostsCertificateRequest() @@ -93,12 +98,11 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe modifyHostsCertificateReq.Hosts = common.StringPtrs([]string{d.config.Domain}) modifyHostsCertificateReq.ServerCertInfo = []*tcTeo.ServerCertInfo{{CertId: common.StringPtr(upres.CertId)}} modifyHostsCertificateResp, err := d.sdkClients.teo.ModifyHostsCertificate(modifyHostsCertificateReq) + d.logger.Debug("sdk request 'teo.ModifyHostsCertificate'", slog.Any("request", modifyHostsCertificateReq), slog.Any("response", modifyHostsCertificateResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'teo.ModifyHostsCertificate'") } - d.logger.Logt("已配置域名证书", modifyHostsCertificateResp.Response) - return &deployer.DeployResult{}, nil } diff --git a/internal/pkg/core/deployer/providers/tencentcloud-scf/tencentcloud_scf.go b/internal/pkg/core/deployer/providers/tencentcloud-scf/tencentcloud_scf.go index 3a3aeb82..f136fa53 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-scf/tencentcloud_scf.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-scf/tencentcloud_scf.go @@ -2,6 +2,7 @@ import ( "context" + "log/slog" xerrors "github.com/pkg/errors" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" @@ -9,7 +10,6 @@ import ( tcScf "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf/v20180416" "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" ) @@ -27,7 +27,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *tcScf.Client sslUploader uploader.Uploader } @@ -54,14 +54,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -71,10 +76,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe getCustomDomainReq := tcScf.NewGetCustomDomainRequest() getCustomDomainReq.Domain = common.StringPtr(d.config.Domain) getCustomDomainResp, err := d.sdkClient.GetCustomDomain(getCustomDomainReq) + d.logger.Debug("sdk request 'scf.GetCustomDomain'", slog.Any("request", getCustomDomainReq), slog.Any("response", getCustomDomainResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'scf.GetCustomDomain'") - } else { - d.logger.Logt("已查看云函数自定义域名详情", getCustomDomainResp.Response) } // 上传证书到 SSL @@ -82,7 +86,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") } else { - d.logger.Logt("certificate file uploaded", upres) + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } // 更新云函数自定义域名 @@ -94,10 +98,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe } updateCustomDomainReq.Protocol = getCustomDomainResp.Response.Protocol updateCustomDomainResp, err := d.sdkClient.UpdateCustomDomain(updateCustomDomainReq) + d.logger.Debug("sdk request 'scf.UpdateCustomDomain'", slog.Any("request", updateCustomDomainReq), slog.Any("response", updateCustomDomainResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'scf.UpdateCustomDomain'") - } else { - d.logger.Logt("已设置点播域名 HTTPS 证书", updateCustomDomainResp.Response) } return &deployer.DeployResult{}, nil 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 f943ad6e..acebc43e 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 @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "log/slog" "time" xerrors "github.com/pkg/errors" @@ -12,7 +13,6 @@ import ( tcSsl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205" "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" ) @@ -32,7 +32,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *tcSsl.Client sslUploader uploader.Uploader } @@ -59,14 +59,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -82,10 +87,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - // 证书部署到云资源实例列表 // REF: https://cloud.tencent.com/document/product/400/91667 deployCertificateInstanceReq := tcSsl.NewDeployCertificateInstanceRequest() @@ -94,14 +99,13 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe deployCertificateInstanceReq.InstanceIdList = common.StringPtrs(d.config.ResourceIds) deployCertificateInstanceReq.Status = common.Int64Ptr(1) deployCertificateInstanceResp, err := d.sdkClient.DeployCertificateInstance(deployCertificateInstanceReq) + d.logger.Debug("sdk request 'ssl.DeployCertificateInstance'", slog.Any("request", deployCertificateInstanceReq), slog.Any("response", deployCertificateInstanceResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'ssl.DeployCertificateInstance'") } else if deployCertificateInstanceResp.Response == nil || deployCertificateInstanceResp.Response.DeployRecordId == nil { return nil, errors.New("failed to create deploy record") } - d.logger.Logt("已部署证书到云资源实例", deployCertificateInstanceResp.Response) - // 循环获取部署任务详情,等待任务状态变更 // REF: https://cloud.tencent.com.cn/document/api/400/91658 for { @@ -113,12 +117,13 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe describeHostDeployRecordDetailReq.DeployRecordId = common.StringPtr(fmt.Sprintf("%d", *deployCertificateInstanceResp.Response.DeployRecordId)) describeHostDeployRecordDetailReq.Limit = common.Uint64Ptr(100) describeHostDeployRecordDetailResp, err := d.sdkClient.DescribeHostDeployRecordDetail(describeHostDeployRecordDetailReq) + d.logger.Debug("sdk request 'ssl.DescribeHostDeployRecordDetail'", slog.Any("request", describeHostDeployRecordDetailReq), slog.Any("response", describeHostDeployRecordDetailResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'ssl.DescribeHostDeployRecordDetail'") } if describeHostDeployRecordDetailResp.Response.TotalCount == nil { - return nil, errors.New("部署任务状态异常") + return nil, errors.New("unexpected deployment job status") } else { acc := int64(0) if describeHostDeployRecordDetailResp.Response.SuccessTotalCount != nil { @@ -129,12 +134,11 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe } if acc == *describeHostDeployRecordDetailResp.Response.TotalCount { - d.logger.Logt("已获取部署任务详情", describeHostDeployRecordDetailResp) break } } - d.logger.Logt("部署任务未完成 ...") + d.logger.Info("waiting for deployment job completion ...") time.Sleep(time.Second * 5) } diff --git a/internal/pkg/core/deployer/providers/tencentcloud-ssl/tencentcloud_ssl.go b/internal/pkg/core/deployer/providers/tencentcloud-ssl/tencentcloud_ssl.go new file mode 100644 index 00000000..8f8676de --- /dev/null +++ b/internal/pkg/core/deployer/providers/tencentcloud-ssl/tencentcloud_ssl.go @@ -0,0 +1,69 @@ +package tencentcloudssl + +import ( + "context" + "log/slog" + + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/uploader" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl" +) + +type DeployerConfig struct { + // 腾讯云 SecretId。 + SecretId string `json:"secretId"` + // 腾讯云 SecretKey。 + SecretKey string `json:"secretKey"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger *slog.Logger + sslUploader uploader.Uploader +} + +var _ deployer.Deployer = (*DeployerProvider)(nil) + +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { + if config == nil { + panic("config is nil") + } + + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ + SecretId: config.SecretId, + SecretKey: config.SecretKey, + }) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create ssl uploader") + } + + return &DeployerProvider{ + config: config, + logger: slog.Default(), + sslUploader: uploader, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(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.Info("ssl certificate uploaded", slog.Any("result", upres)) + } + + return &deployer.DeployResult{}, nil +} diff --git a/internal/pkg/core/deployer/providers/tencentcloud-vod/tencentcloud_vod.go b/internal/pkg/core/deployer/providers/tencentcloud-vod/tencentcloud_vod.go index 77177469..92469390 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-vod/tencentcloud_vod.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-vod/tencentcloud_vod.go @@ -2,6 +2,7 @@ import ( "context" + "log/slog" xerrors "github.com/pkg/errors" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" @@ -9,7 +10,6 @@ import ( 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" ) @@ -27,7 +27,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *tcVod.Client sslUploader uploader.Uploader } @@ -54,14 +54,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -71,7 +76,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") } else { - d.logger.Logt("certificate file uploaded", upres) + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } // 设置点播域名 HTTPS 证书 @@ -84,10 +89,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe setVodDomainCertificateReq.SubAppId = common.Uint64Ptr(uint64(d.config.SubAppId)) } setVodDomainCertificateResp, err := d.sdkClient.SetVodDomainCertificate(setVodDomainCertificateReq) + d.logger.Debug("sdk request 'vod.SetVodDomainCertificate'", slog.Any("request", setVodDomainCertificateReq), slog.Any("response", setVodDomainCertificateResp)) 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 diff --git a/internal/pkg/core/deployer/providers/tencentcloud-waf/tencentcloud_waf.go b/internal/pkg/core/deployer/providers/tencentcloud-waf/tencentcloud_waf.go index c84067ce..400b96b8 100644 --- a/internal/pkg/core/deployer/providers/tencentcloud-waf/tencentcloud_waf.go +++ b/internal/pkg/core/deployer/providers/tencentcloud-waf/tencentcloud_waf.go @@ -3,6 +3,7 @@ import ( "context" "errors" + "log/slog" xerrors "github.com/pkg/errors" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" @@ -10,7 +11,6 @@ import ( 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" ) @@ -32,7 +32,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *tcWaf.Client sslUploader uploader.Uploader } @@ -59,14 +59,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -86,7 +91,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") } else { - d.logger.Logt("certificate file uploaded", upres) + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } // 查询单个 SaaS 型 WAF 域名详情 @@ -96,10 +101,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe describeDomainDetailsSaasReq.DomainId = common.StringPtr(d.config.DomainId) describeDomainDetailsSaasReq.InstanceId = common.StringPtr(d.config.InstanceId) describeDomainDetailsSaasResp, err := d.sdkClient.DescribeDomainDetailsSaas(describeDomainDetailsSaasReq) + d.logger.Debug("sdk request 'waf.DescribeDomainDetailsSaas'", slog.Any("request", describeDomainDetailsSaasReq), slog.Any("response", describeDomainDetailsSaasResp)) 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 域名 @@ -111,10 +115,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe modifySpartaProtectionReq.CertType = common.Int64Ptr(2) modifySpartaProtectionReq.SSLId = common.StringPtr(upres.CertId) modifySpartaProtectionResp, err := d.sdkClient.ModifySpartaProtection(modifySpartaProtectionReq) + d.logger.Debug("sdk request 'waf.ModifySpartaProtection'", slog.Any("request", modifySpartaProtectionReq), slog.Any("response", modifySpartaProtectionResp)) 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 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 8c19621b..117cf9fb 100644 --- a/internal/pkg/core/deployer/providers/ucloud-ucdn/ucloud_ucdn.go +++ b/internal/pkg/core/deployer/providers/ucloud-ucdn/ucloud_ucdn.go @@ -3,6 +3,7 @@ import ( "context" "errors" + "log/slog" "strconv" xerrors "github.com/pkg/errors" @@ -11,7 +12,6 @@ import ( uAuth "github.com/ucloud/ucloud-sdk-go/ucloud/auth" "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/ucloud-ussl" ) @@ -29,7 +29,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *uCdn.UCDNClient sslUploader uploader.Uploader } @@ -57,14 +57,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -73,10 +78,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - // 获取加速域名配置 // REF: https://docs.ucloud.cn/api/ucdn-api/get_ucdn_domain_config getUcdnDomainConfigReq := d.sdkClient.NewGetUcdnDomainConfigRequest() @@ -85,14 +90,13 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe getUcdnDomainConfigReq.ProjectId = usdk.String(d.config.ProjectId) } getUcdnDomainConfigResp, err := d.sdkClient.GetUcdnDomainConfig(getUcdnDomainConfigReq) + d.logger.Debug("sdk request 'ucdn.GetUcdnDomainConfig'", slog.Any("request", getUcdnDomainConfigReq), slog.Any("response", getUcdnDomainConfigResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'ucdn.GetUcdnDomainConfig'") } else if len(getUcdnDomainConfigResp.DomainList) == 0 { return nil, errors.New("no domain found") } - d.logger.Logt("已查询到加速域名配置", getUcdnDomainConfigResp) - // 更新 HTTPS 加速配置 // REF: https://docs.ucloud.cn/api/ucdn-api/update_ucdn_domain_https_config_v2 certId, _ := strconv.Atoi(upres.CertId) @@ -108,12 +112,11 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe updateUcdnDomainHttpsConfigV2Req.ProjectId = usdk.String(d.config.ProjectId) } updateUcdnDomainHttpsConfigV2Resp, err := d.sdkClient.UpdateUcdnDomainHttpsConfigV2(updateUcdnDomainHttpsConfigV2Req) + d.logger.Debug("sdk request 'ucdn.UpdateUcdnDomainHttpsConfigV2'", slog.Any("request", updateUcdnDomainHttpsConfigV2Req), slog.Any("response", updateUcdnDomainHttpsConfigV2Resp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'ucdn.UpdateUcdnDomainHttpsConfigV2'") } - d.logger.Logt("已更新 HTTPS 加速配置", updateUcdnDomainHttpsConfigV2Resp) - return &deployer.DeployResult{}, nil } 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 592a1cf6..2d043a5d 100644 --- a/internal/pkg/core/deployer/providers/ucloud-us3/ucloud_us3.go +++ b/internal/pkg/core/deployer/providers/ucloud-us3/ucloud_us3.go @@ -2,13 +2,13 @@ import ( "context" + "log/slog" xerrors "github.com/pkg/errors" usdk "github.com/ucloud/ucloud-sdk-go/ucloud" uAuth "github.com/ucloud/ucloud-sdk-go/ucloud/auth" "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/ucloud-ussl" usdkFile "github.com/usual2970/certimate/internal/pkg/vendors/ucloud-sdk/ufile" @@ -31,7 +31,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *usdkFile.UFileClient sslUploader uploader.Uploader } @@ -59,14 +59,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -75,10 +80,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - // 添加 SSL 证书 // REF: https://docs.ucloud.cn/api/ufile-api/add_ufile_ssl_cert addUFileSSLCertReq := d.sdkClient.NewAddUFileSSLCertRequest() @@ -90,12 +95,11 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe addUFileSSLCertReq.ProjectId = usdk.String(d.config.ProjectId) } addUFileSSLCertResp, err := d.sdkClient.AddUFileSSLCert(addUFileSSLCertReq) + d.logger.Debug("sdk request 'us3.AddUFileSSLCert'", slog.Any("request", addUFileSSLCertReq), slog.Any("response", addUFileSSLCertResp)) if err != nil { - return nil, xerrors.Wrap(err, "failed to execute sdk request 'ucdn.AddUFileSSLCert'") + return nil, xerrors.Wrap(err, "failed to execute sdk request 'us3.AddUFileSSLCert'") } - d.logger.Logt("添加 SSL 证书", addUFileSSLCertResp) - return &deployer.DeployResult{}, nil } diff --git a/internal/pkg/core/deployer/providers/upyun-cdn/upyun_cdn.go b/internal/pkg/core/deployer/providers/upyun-cdn/upyun_cdn.go new file mode 100644 index 00000000..84d6cafb --- /dev/null +++ b/internal/pkg/core/deployer/providers/upyun-cdn/upyun_cdn.go @@ -0,0 +1,129 @@ +package upyuncdn + +import ( + "context" + "errors" + "log/slog" + + xerrors "github.com/pkg/errors" + "golang.org/x/exp/slices" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/uploader" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/upyun-ssl" + upyunsdk "github.com/usual2970/certimate/internal/pkg/vendors/upyun-sdk/console" +) + +type DeployerConfig struct { + // 又拍云账号用户名。 + Username string `json:"username"` + // 又拍云账号密码。 + Password string `json:"password"` + // 加速域名(支持泛域名)。 + Domain string `json:"domain"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger *slog.Logger + sdkClient *upyunsdk.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.Username, config.Password) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ + Username: config.Username, + Password: config.Password, + }) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create ssl uploader") + } + + return &DeployerProvider{ + config: config, + logger: slog.Default(), + sdkClient: client, + sslUploader: uploader, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(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.Info("ssl certificate uploaded", slog.Any("result", upres)) + } + + // 获取域名证书配置 + getHttpsServiceManagerResp, err := d.sdkClient.GetHttpsServiceManager(d.config.Domain) + d.logger.Debug("sdk request 'console.GetHttpsServiceManager'", slog.String("request.domain", d.config.Domain), slog.Any("response", getHttpsServiceManagerResp)) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'console.GetHttpsServiceManager'") + } + + // 判断域名是否已启用 HTTPS。如果已启用,迁移域名证书;否则,设置新证书 + lastCertIndex := slices.IndexFunc(getHttpsServiceManagerResp.Data.Domains, func(item upyunsdk.HttpsServiceManagerDomain) bool { + return item.Https + }) + if lastCertIndex == -1 { + updateHttpsCertificateManagerReq := &upyunsdk.UpdateHttpsCertificateManagerRequest{ + CertificateId: upres.CertId, + Domain: d.config.Domain, + Https: true, + ForceHttps: true, + } + updateHttpsCertificateManagerResp, err := d.sdkClient.UpdateHttpsCertificateManager(updateHttpsCertificateManagerReq) + d.logger.Debug("sdk request 'console.EnableDomainHttps'", slog.Any("request", updateHttpsCertificateManagerReq), slog.Any("response", updateHttpsCertificateManagerResp)) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'console.UpdateHttpsCertificateManager'") + } + } else if getHttpsServiceManagerResp.Data.Domains[lastCertIndex].CertificateId != upres.CertId { + migrateHttpsDomainReq := &upyunsdk.MigrateHttpsDomainRequest{ + CertificateId: upres.CertId, + Domain: d.config.Domain, + } + migrateHttpsDomainResp, err := d.sdkClient.MigrateHttpsDomain(migrateHttpsDomainReq) + d.logger.Debug("sdk request 'console.MigrateHttpsDomain'", slog.Any("request", migrateHttpsDomainReq), slog.Any("response", migrateHttpsDomainResp)) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'console.MigrateHttpsDomain'") + } + } + + return &deployer.DeployResult{}, nil +} + +func createSdkClient(username, password string) (*upyunsdk.Client, error) { + if username == "" { + return nil, errors.New("invalid upyun username") + } + + if password == "" { + return nil, errors.New("invalid upyun password") + } + + client := upyunsdk.NewClient(username, password) + return client, nil +} diff --git a/internal/pkg/core/deployer/providers/upyun-cdn/upyun_cdn_test.go b/internal/pkg/core/deployer/providers/upyun-cdn/upyun_cdn_test.go new file mode 100644 index 00000000..8a7b4485 --- /dev/null +++ b/internal/pkg/core/deployer/providers/upyun-cdn/upyun_cdn_test.go @@ -0,0 +1,75 @@ +package upyuncdn_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/upyun-cdn" +) + +var ( + fInputCertPath string + fInputKeyPath string + fUsername string + fPassword string + fDomain string +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_UPYUNCDN_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fUsername, argsPrefix+"USERNAME", "", "") + flag.StringVar(&fPassword, argsPrefix+"PASSWORD", "", "") + flag.StringVar(&fDomain, argsPrefix+"DOMAIN", "", "") +} + +/* +Shell command to run this test: + + go test -v ./upyun_cdn_test.go -args \ + --CERTIMATE_DEPLOYER_UPYUNCDN_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_UPYUNCDN_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_UPYUNCDN_USERNAME="your-username" \ + --CERTIMATE_DEPLOYER_UPYUNCDN_PASSWORD="your-password" \ + --CERTIMATE_DEPLOYER_UPYUNCDN_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("USERNAME: %v", fUsername), + fmt.Sprintf("PASSWORD: %v", fPassword), + fmt.Sprintf("DOMAIN: %v", fDomain), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + Username: fUsername, + Password: fPassword, + 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-cdn/volcengine_cdn.go b/internal/pkg/core/deployer/providers/volcengine-cdn/volcengine_cdn.go index 229c3c01..88f05415 100644 --- a/internal/pkg/core/deployer/providers/volcengine-cdn/volcengine_cdn.go +++ b/internal/pkg/core/deployer/providers/volcengine-cdn/volcengine_cdn.go @@ -3,14 +3,13 @@ import ( "context" "errors" - "fmt" + "log/slog" "strings" xerrors "github.com/pkg/errors" veCdn "github.com/volcengine/volc-sdk-golang/service/cdn" "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-cdn" ) @@ -26,7 +25,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *veCdn.CDN sslUploader uploader.Uploader } @@ -52,14 +51,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -68,10 +72,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - domains := make([]string, 0) if strings.HasPrefix(d.config.Domain, "*.") { // 获取指定证书可关联的域名 @@ -80,6 +84,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe CertId: upres.CertId, } describeCertConfigResp, err := d.sdkClient.DescribeCertConfig(describeCertConfigReq) + d.logger.Debug("sdk request 'cdn.DescribeCertConfig'", slog.Any("request", describeCertConfigReq), slog.Any("response", describeCertConfigResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.DescribeCertConfig'") } @@ -99,6 +104,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe if len(domains) == 0 { if len(describeCertConfigResp.Result.SpecifiedCertConfig) > 0 { // 所有可关联的域名都配置了该证书,跳过部署 + d.logger.Info("no domains to deploy") } else { return nil, errors.New("domain not found") } @@ -118,10 +124,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe Domain: domain, } batchDeployCertResp, err := d.sdkClient.BatchDeployCert(batchDeployCertReq) + d.logger.Debug("sdk request 'cdn.BatchDeployCert'", slog.Any("request", batchDeployCertReq), slog.Any("response", batchDeployCertResp)) if err != nil { errs = append(errs, err) - } else { - d.logger.Logt(fmt.Sprintf("已关联证书到域名 %s", domain), batchDeployCertResp) } } 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 2b248adc..b3ba7241 100644 --- a/internal/pkg/core/deployer/providers/volcengine-clb/volcengine_clb.go +++ b/internal/pkg/core/deployer/providers/volcengine-clb/volcengine_clb.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "log/slog" xerrors "github.com/pkg/errors" veClb "github.com/volcengine/volcengine-go-sdk/service/clb" @@ -11,7 +12,6 @@ import ( veSession "github.com/volcengine/volcengine-go-sdk/volcengine/session" "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" ) @@ -32,7 +32,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *veClb.CLB sslUploader uploader.Uploader } @@ -60,14 +60,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -76,10 +81,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - // 根据部署资源类型决定部署方式 switch d.config.ResourceType { case RESOURCE_TYPE_LISTENER: @@ -107,10 +112,9 @@ func (d *DeployerProvider) deployToListener(ctx context.Context, cloudCertId str CertCenterCertificateId: ve.String(cloudCertId), } modifyListenerAttributesResp, err := d.sdkClient.ModifyListenerAttributes(modifyListenerAttributesReq) + d.logger.Debug("sdk request 'clb.ModifyListenerAttributes'", slog.Any("request", modifyListenerAttributesReq), slog.Any("response", modifyListenerAttributesResp)) if err != nil { return xerrors.Wrap(err, "failed to execute sdk request 'clb.ModifyListenerAttributes'") - } else { - d.logger.Logt("已修改监听器", modifyListenerAttributesResp) } return 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 835eae4b..0b9de8a7 100644 --- a/internal/pkg/core/deployer/providers/volcengine-dcdn/volcengine_dcdn.go +++ b/internal/pkg/core/deployer/providers/volcengine-dcdn/volcengine_dcdn.go @@ -2,6 +2,7 @@ import ( "context" + "log/slog" "strings" xerrors "github.com/pkg/errors" @@ -10,7 +11,6 @@ import ( veSession "github.com/volcengine/volcengine-go-sdk/volcengine/session" "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" ) @@ -28,7 +28,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *veDcdn.DCDN sslUploader uploader.Uploader } @@ -56,14 +56,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -72,10 +77,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - // "*.example.com" → ".example.com",适配火山引擎 DCDN 要求的泛域名格式 domain := strings.TrimPrefix(d.config.Domain, "*") @@ -87,10 +92,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe DomainNames: ve.StringSlice([]string{domain}), } createCertBindResp, err := d.sdkClient.CreateCertBind(createCertBindReq) + d.logger.Debug("sdk request 'dcdn.CreateCertBind'", slog.Any("request", createCertBindReq), slog.Any("response", createCertBindResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'dcdn.CreateCertBind'") - } else { - d.logger.Logt("已绑定证书", createCertBindResp) } return &deployer.DeployResult{}, nil diff --git a/internal/pkg/core/deployer/providers/volcengine-imagex/volcengine_imagex.go b/internal/pkg/core/deployer/providers/volcengine-imagex/volcengine_imagex.go index 1bd6d109..f3ac68bf 100644 --- a/internal/pkg/core/deployer/providers/volcengine-imagex/volcengine_imagex.go +++ b/internal/pkg/core/deployer/providers/volcengine-imagex/volcengine_imagex.go @@ -3,13 +3,13 @@ import ( "context" "errors" + "log/slog" 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" ) @@ -29,7 +29,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *veImageX.Imagex sslUploader uploader.Uploader } @@ -57,14 +57,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -81,7 +86,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") } else { - d.logger.Logt("certificate file uploaded", upres) + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } // 获取域名配置 @@ -91,10 +96,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe DomainName: d.config.Domain, } getDomainConfigResp, err := d.sdkClient.GetDomainConfig(context.TODO(), getDomainConfigReq) + d.logger.Debug("sdk request 'imagex.GetDomainConfig'", slog.Any("request", getDomainConfigReq), slog.Any("response", getDomainConfigResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'imagex.GetDomainConfig'") - } else { - d.logger.Logt("已获取域名配置", getDomainConfigResp) } // 更新 HTTPS 配置 @@ -121,10 +125,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe updateHttpsReq.UpdateHTTPSBody.HTTPS.ForceRedirectCode = getDomainConfigResp.Result.HTTPSConfig.ForceRedirectCode } updateHttpsResp, err := d.sdkClient.UpdateHTTPS(context.TODO(), updateHttpsReq) + d.logger.Debug("sdk request 'imagex.UpdateHttps'", slog.Any("request", updateHttpsReq), slog.Any("response", updateHttpsResp)) 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 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 240e5c9c..15073743 100644 --- a/internal/pkg/core/deployer/providers/volcengine-live/volcengine_live.go +++ b/internal/pkg/core/deployer/providers/volcengine-live/volcengine_live.go @@ -3,7 +3,7 @@ import ( "context" "errors" - "fmt" + "log/slog" "strings" xerrors "github.com/pkg/errors" @@ -11,7 +11,6 @@ import ( ve "github.com/volcengine/volcengine-go-sdk/volcengine" "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-live" ) @@ -27,7 +26,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *veLive.Live sslUploader uploader.Uploader } @@ -53,14 +52,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -69,10 +73,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - domains := make([]string, 0) if strings.HasPrefix(d.config.Domain, "*.") { listDomainDetailPageNum := int32(1) @@ -86,6 +90,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe PageSize: listDomainDetailPageSize, } listDomainDetailResp, err := d.sdkClient.ListDomainDetail(ctx, listDomainDetailReq) + d.logger.Debug("sdk request 'live.ListDomainDetail'", slog.Any("request", listDomainDetailReq), slog.Any("response", listDomainDetailResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'live.ListDomainDetail'") } @@ -110,7 +115,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe } if len(domains) == 0 { - return nil, xerrors.Errorf("未查询到匹配的域名: %s", d.config.Domain) + return nil, errors.New("domain not found") } } else { domains = append(domains, d.config.Domain) @@ -128,10 +133,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe HTTPS: ve.Bool(true), } bindCertResp, err := d.sdkClient.BindCert(ctx, bindCertReq) + d.logger.Debug("sdk request 'live.BindCert'", slog.Any("request", bindCertReq), slog.Any("response", bindCertResp)) if err != nil { errs = append(errs, err) - } else { - d.logger.Logt(fmt.Sprintf("已绑定证书到域名 %s", domain), bindCertResp) } } 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 142a8b9f..d4bd6e59 100644 --- a/internal/pkg/core/deployer/providers/volcengine-tos/volcengine_tos.go +++ b/internal/pkg/core/deployer/providers/volcengine-tos/volcengine_tos.go @@ -4,12 +4,12 @@ import ( "context" "errors" "fmt" + "log/slog" xerrors "github.com/pkg/errors" veTos "github.com/volcengine/ve-tos-golang-sdk/v2/tos" "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" ) @@ -29,7 +29,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger sdkClient *veTos.ClientV2 sslUploader uploader.Uploader } @@ -57,14 +57,19 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), sdkClient: client, sslUploader: uploader, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) return d } @@ -80,10 +85,10 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) if err != nil { return nil, xerrors.Wrap(err, "failed to upload certificate file") + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) } - d.logger.Logt("certificate file uploaded", upres) - // 设置自定义域名 // REF: https://www.volcengine.com/docs/6559/1250189 putBucketCustomDomainReq := &veTos.PutBucketCustomDomainInput{ @@ -94,10 +99,9 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe }, } putBucketCustomDomainResp, err := d.sdkClient.PutBucketCustomDomain(context.TODO(), putBucketCustomDomainReq) + d.logger.Debug("sdk request 'tos.PutBucketCustomDomain'", slog.Any("request", putBucketCustomDomainReq), slog.Any("response", putBucketCustomDomainResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'tos.PutBucketCustomDomain'") - } else { - d.logger.Logt("已设置自定义域名", putBucketCustomDomainResp) } return &deployer.DeployResult{}, nil diff --git a/internal/pkg/core/deployer/providers/webhook/webhook.go b/internal/pkg/core/deployer/providers/webhook/webhook.go index 6a1e8a21..0afc60f0 100644 --- a/internal/pkg/core/deployer/providers/webhook/webhook.go +++ b/internal/pkg/core/deployer/providers/webhook/webhook.go @@ -4,6 +4,7 @@ import ( "context" "crypto/tls" "encoding/json" + "log/slog" "strings" "time" @@ -11,8 +12,7 @@ import ( 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/certs" + "github.com/usual2970/certimate/internal/pkg/utils/certutil" ) type DeployerConfig struct { @@ -26,7 +26,7 @@ type DeployerConfig struct { type DeployerProvider struct { config *DeployerConfig - logger logger.Logger + logger *slog.Logger httpClient *resty.Client } @@ -47,18 +47,22 @@ func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { return &DeployerProvider{ config: config, - logger: logger.NewNilLogger(), + logger: slog.Default(), httpClient: client, }, nil } -func (d *DeployerProvider) WithLogger(logger logger.Logger) *DeployerProvider { - d.logger = logger +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.Default() + } else { + d.logger = logger + } return d } func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { - certX509, err := certs.ParseCertificateFromPEM(certPem) + certX509, err := certutil.ParseCertificateFromPEM(certPem) if err != nil { return nil, xerrors.Wrap(err, "failed to parse x509") } @@ -86,18 +90,18 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe return nil, xerrors.Errorf("unexpected webhook response status code: %d", resp.StatusCode()) } - d.logger.Logt("Webhook request sent", resp.String()) + d.logger.Debug("webhook responded", slog.Any("response", resp.String())) return &deployer.DeployResult{}, nil } func replaceJsonValueRecursively(data interface{}, oldStr, newStr string) interface{} { switch v := data.(type) { - case map[string]interface{}: + case map[string]any: for k, val := range v { v[k] = replaceJsonValueRecursively(val, oldStr, newStr) } - case []interface{}: + case []any: for i, val := range v { v[i] = replaceJsonValueRecursively(val, oldStr, newStr) } diff --git a/internal/pkg/core/logger/builtin.go b/internal/pkg/core/logger/builtin.go deleted file mode 100644 index fa8932dc..00000000 --- a/internal/pkg/core/logger/builtin.go +++ /dev/null @@ -1,94 +0,0 @@ -package logger - -import ( - "encoding/json" - "fmt" - "reflect" - "strings" - - "github.com/usual2970/certimate/internal/pkg/utils/types" -) - -// 表示默认的日志记录器类型。 -type DefaultLogger struct { - records []string -} - -var _ Logger = (*DefaultLogger)(nil) - -func (l *DefaultLogger) Logt(tag string, data ...any) { - l.ensureInitialized() - - temp := make([]string, len(data)+1) - temp[0] = tag - for i, v := range data { - s := "" - if types.IsNil(v) { - s = "" - } else { - switch reflect.ValueOf(v).Kind() { - case reflect.String: - s = v.(string) - case reflect.Bool, - reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, - reflect.Float32, reflect.Float64: - s = fmt.Sprintf("%v", v) - default: - jbytes, _ := json.Marshal(v) - s = string(jbytes) - } - } - - temp[i+1] = s - } - - l.records = append(l.records, strings.Join(temp, ": ")) -} - -func (l *DefaultLogger) Logf(format string, args ...any) { - l.ensureInitialized() - - l.records = append(l.records, fmt.Sprintf(format, args...)) -} - -func (l *DefaultLogger) GetRecords() []string { - l.ensureInitialized() - - temp := make([]string, len(l.records)) - copy(temp, l.records) - return temp -} - -func (l *DefaultLogger) FlushRecords() { - l.records = make([]string, 0) -} - -func (l *DefaultLogger) ensureInitialized() { - if l.records == nil { - l.records = make([]string, 0) - } -} - -func NewDefaultLogger() *DefaultLogger { - return &DefaultLogger{ - records: make([]string, 0), - } -} - -// 表示空的日志记录器类型。 -// 该日志记录器不会执行任何操作。 -type NilLogger struct{} - -var _ Logger = (*NilLogger)(nil) - -func (l *NilLogger) Logt(string, ...any) {} -func (l *NilLogger) Logf(string, ...any) {} -func (l *NilLogger) GetRecords() []string { - return make([]string, 0) -} -func (l *NilLogger) FlushRecords() {} - -func NewNilLogger() *NilLogger { - return &NilLogger{} -} diff --git a/internal/pkg/core/logger/logger.go b/internal/pkg/core/logger/logger.go deleted file mode 100644 index cc6284cd..00000000 --- a/internal/pkg/core/logger/logger.go +++ /dev/null @@ -1,27 +0,0 @@ -package logger - -// 表示定义日志记录器的抽象类型接口。 -type Logger interface { - // 追加一条日志记录。 - // 该方法会将 `data` 以 JSON 序列化后拼接到 `tag` 结尾。 - // - // 入参: - // - tag:标签。 - // - data:数据。 - Logt(tag string, data ...any) - - // 追加一条日志记录。 - // 该方法会将 `args` 以 `format` 格式化。 - // - // 入参: - // - format:格式化字符串。 - // - args:格式化参数。 - Logf(format string, args ...any) - - // 获取所有日志记录。 - // TODO: 记录时间 - GetRecords() []string - - // 清空所有日志记录。 - FlushRecords() -} diff --git a/internal/pkg/core/logger/logger_test.go b/internal/pkg/core/logger/logger_test.go deleted file mode 100644 index e131a7b1..00000000 --- a/internal/pkg/core/logger/logger_test.go +++ /dev/null @@ -1,56 +0,0 @@ -package logger_test - -import ( - "testing" - - "github.com/usual2970/certimate/internal/pkg/core/logger" -) - -/* -Shell command to run this test: - - go test -v ./logger_test.go -*/ -func TestLogger(t *testing.T) { - t.Run("Logger_Appendt", func(t *testing.T) { - logger := logger.NewDefaultLogger() - - logger.Logt("test") - logger.Logt("test_nil", nil) - logger.Logt("test_int", 1024) - logger.Logt("test_string", "certimate") - logger.Logt("test_map", map[string]interface{}{"key": "value"}) - logger.Logt("test_struct", struct{ Name string }{Name: "certimate"}) - logger.Logt("test_slice", []string{"certimate"}) - t.Log(logger.GetRecords()) - if len(logger.GetRecords()) != 7 { - t.Errorf("expected 7 records, got %d", len(logger.GetRecords())) - } - - logger.FlushRecords() - if len(logger.GetRecords()) != 0 { - t.Errorf("expected 0 records, got %d", len(logger.GetRecords())) - } - }) - - t.Run("Logger_Appendf", func(t *testing.T) { - logger := logger.NewDefaultLogger() - - logger.Logf("test") - logger.Logf("test_nil: %v", nil) - logger.Logf("test_int: %v", 1024) - logger.Logf("test_string: %v", "certimate") - logger.Logf("test_map: %v", map[string]interface{}{"key": "value"}) - logger.Logf("test_struct: %v", struct{ Name string }{Name: "certimate"}) - logger.Logf("test_slice: %v", []string{"certimate"}) - t.Log(logger.GetRecords()) - if len(logger.GetRecords()) != 7 { - t.Errorf("expected 7 records, got %d", len(logger.GetRecords())) - } - - logger.FlushRecords() - if len(logger.GetRecords()) != 0 { - t.Errorf("expected 0 records, got %d", len(logger.GetRecords())) - } - }) -} diff --git a/internal/pkg/core/notifier/notifier.go b/internal/pkg/core/notifier/notifier.go index 22fc8574..97485215 100644 --- a/internal/pkg/core/notifier/notifier.go +++ b/internal/pkg/core/notifier/notifier.go @@ -1,9 +1,14 @@ package notifier -import "context" +import ( + "context" + "log/slog" +) // 表示定义消息通知器的抽象类型接口。 type Notifier interface { + WithLogger(logger *slog.Logger) Notifier + // 发送通知。 // // 入参: diff --git a/internal/pkg/core/notifier/providers/bark/bark.go b/internal/pkg/core/notifier/providers/bark/bark.go index f9589096..a6833ae1 100644 --- a/internal/pkg/core/notifier/providers/bark/bark.go +++ b/internal/pkg/core/notifier/providers/bark/bark.go @@ -2,6 +2,7 @@ import ( "context" + "log/slog" "github.com/nikoksr/notify" "github.com/nikoksr/notify/service/bark" @@ -19,6 +20,7 @@ type NotifierConfig struct { type NotifierProvider struct { config *NotifierConfig + logger *slog.Logger } var _ notifier.Notifier = (*NotifierProvider)(nil) @@ -33,6 +35,15 @@ func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { }, nil } +func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier { + if logger == nil { + n.logger = slog.Default() + } else { + n.logger = logger + } + return n +} + func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { var srv notify.Notifier if n.config.ServerUrl == "" { diff --git a/internal/pkg/core/notifier/providers/dingtalk/dingtalk.go b/internal/pkg/core/notifier/providers/dingtalk/dingtalk.go index f8eba8a7..f0ab4741 100644 --- a/internal/pkg/core/notifier/providers/dingtalk/dingtalk.go +++ b/internal/pkg/core/notifier/providers/dingtalk/dingtalk.go @@ -2,6 +2,7 @@ import ( "context" + "log/slog" "github.com/nikoksr/notify/service/dingding" @@ -17,6 +18,7 @@ type NotifierConfig struct { type NotifierProvider struct { config *NotifierConfig + logger *slog.Logger } var _ notifier.Notifier = (*NotifierProvider)(nil) @@ -31,6 +33,15 @@ func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { }, nil } +func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier { + if logger == nil { + n.logger = slog.Default() + } else { + n.logger = logger + } + return n +} + 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, diff --git a/internal/pkg/core/notifier/providers/email/email.go b/internal/pkg/core/notifier/providers/email/email.go index 4a69d50a..ebf2d150 100644 --- a/internal/pkg/core/notifier/providers/email/email.go +++ b/internal/pkg/core/notifier/providers/email/email.go @@ -4,6 +4,7 @@ import ( "context" "crypto/tls" "fmt" + "log/slog" "net/smtp" "github.com/domodwyer/mailyak/v3" @@ -31,6 +32,7 @@ type NotifierConfig struct { type NotifierProvider struct { config *NotifierConfig + logger *slog.Logger } var _ notifier.Notifier = (*NotifierProvider)(nil) @@ -45,6 +47,15 @@ func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { }, nil } +func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier { + if logger == nil { + n.logger = slog.Default() + } else { + n.logger = logger + } + return n +} + 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 != "" { diff --git a/internal/pkg/core/notifier/providers/lark/lark.go b/internal/pkg/core/notifier/providers/lark/lark.go index 9c92691a..150f4e04 100644 --- a/internal/pkg/core/notifier/providers/lark/lark.go +++ b/internal/pkg/core/notifier/providers/lark/lark.go @@ -2,6 +2,7 @@ import ( "context" + "log/slog" "github.com/nikoksr/notify/service/lark" @@ -15,6 +16,7 @@ type NotifierConfig struct { type NotifierProvider struct { config *NotifierConfig + logger *slog.Logger } var _ notifier.Notifier = (*NotifierProvider)(nil) @@ -29,6 +31,15 @@ func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { }, nil } +func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier { + if logger == nil { + n.logger = slog.Default() + } else { + n.logger = logger + } + return n +} + func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { srv := lark.NewWebhookService(n.config.WebhookUrl) diff --git a/internal/pkg/core/notifier/providers/serverchan/serverchan.go b/internal/pkg/core/notifier/providers/serverchan/serverchan.go index 51df0893..ac4d9fe6 100644 --- a/internal/pkg/core/notifier/providers/serverchan/serverchan.go +++ b/internal/pkg/core/notifier/providers/serverchan/serverchan.go @@ -2,6 +2,7 @@ import ( "context" + "log/slog" "net/http" notifyHttp "github.com/nikoksr/notify/service/http" @@ -16,6 +17,7 @@ type NotifierConfig struct { type NotifierProvider struct { config *NotifierConfig + logger *slog.Logger } var _ notifier.Notifier = (*NotifierProvider)(nil) @@ -30,6 +32,15 @@ func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { }, nil } +func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier { + if logger == nil { + n.logger = slog.Default() + } else { + n.logger = logger + } + return n +} + func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { srv := notifyHttp.New() diff --git a/internal/pkg/core/notifier/providers/telegram/telegram.go b/internal/pkg/core/notifier/providers/telegram/telegram.go index 6a1889b3..c3a2e973 100644 --- a/internal/pkg/core/notifier/providers/telegram/telegram.go +++ b/internal/pkg/core/notifier/providers/telegram/telegram.go @@ -2,6 +2,7 @@ import ( "context" + "log/slog" "github.com/nikoksr/notify/service/telegram" @@ -17,6 +18,7 @@ type NotifierConfig struct { type NotifierProvider struct { config *NotifierConfig + logger *slog.Logger } var _ notifier.Notifier = (*NotifierProvider)(nil) @@ -31,6 +33,15 @@ func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { }, nil } +func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier { + if logger == nil { + n.logger = slog.Default() + } else { + n.logger = logger + } + return n +} + 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 { diff --git a/internal/pkg/core/notifier/providers/webhook/webhook.go b/internal/pkg/core/notifier/providers/webhook/webhook.go index f753645a..e11e5487 100644 --- a/internal/pkg/core/notifier/providers/webhook/webhook.go +++ b/internal/pkg/core/notifier/providers/webhook/webhook.go @@ -3,6 +3,7 @@ import ( "context" "crypto/tls" + "log/slog" "net/http" webhook "github.com/nikoksr/notify/service/http" @@ -19,6 +20,7 @@ type NotifierConfig struct { type NotifierProvider struct { config *NotifierConfig + logger *slog.Logger } var _ notifier.Notifier = (*NotifierProvider)(nil) @@ -33,6 +35,15 @@ func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { }, nil } +func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier { + if logger == nil { + n.logger = slog.Default() + } else { + n.logger = logger + } + return n +} + func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { srv := webhook.New() srv.AddReceiversURLs(n.config.Url) diff --git a/internal/pkg/core/notifier/providers/wecom/wecom.go b/internal/pkg/core/notifier/providers/wecom/wecom.go index 63342cb5..ef76e97f 100644 --- a/internal/pkg/core/notifier/providers/wecom/wecom.go +++ b/internal/pkg/core/notifier/providers/wecom/wecom.go @@ -2,6 +2,7 @@ import ( "context" + "log/slog" "net/http" notifyHttp "github.com/nikoksr/notify/service/http" @@ -16,6 +17,7 @@ type NotifierConfig struct { type NotifierProvider struct { config *NotifierConfig + logger *slog.Logger } var _ notifier.Notifier = (*NotifierProvider)(nil) @@ -30,6 +32,15 @@ func NewNotifier(config *NotifierConfig) (*NotifierProvider, error) { }, nil } +func (n *NotifierProvider) WithLogger(logger *slog.Logger) notifier.Notifier { + if logger == nil { + n.logger = slog.Default() + } else { + n.logger = logger + } + return n +} + func (n *NotifierProvider) Notify(ctx context.Context, subject string, message string) (res *notifier.NotifyResult, err error) { srv := notifyHttp.New() diff --git a/internal/pkg/core/uploader/providers/1panel-ssl/1panel_ssl.go b/internal/pkg/core/uploader/providers/1panel-ssl/1panel_ssl.go index bb612bec..ee00c06a 100644 --- a/internal/pkg/core/uploader/providers/1panel-ssl/1panel_ssl.go +++ b/internal/pkg/core/uploader/providers/1panel-ssl/1panel_ssl.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "log/slog" "net/url" "strings" "time" @@ -23,6 +24,7 @@ type UploaderConfig struct { type UploaderProvider struct { config *UploaderConfig + logger *slog.Logger sdkClient *opsdk.Client } @@ -40,15 +42,26 @@ func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { return &UploaderProvider{ config: config, + logger: slog.Default(), sdkClient: client, }, nil } +func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader { + if logger == nil { + u.logger = slog.Default() + } else { + u.logger = logger + } + return u +} + func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 遍历证书列表,避免重复上传 if res, err := u.getExistCert(ctx, certPem, privkeyPem); err != nil { return nil, err } else if res != nil { + u.logger.Info("ssl certificate already exists") return res, nil } @@ -63,6 +76,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe PrivateKey: privkeyPem, } uploadWebsiteSSLResp, err := u.sdkClient.UploadWebsiteSSL(uploadWebsiteSSLReq) + u.logger.Debug("sdk request '1panel.UploadWebsiteSSL'", slog.Any("request", uploadWebsiteSSLReq), slog.Any("response", uploadWebsiteSSLResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request '1panel.UploadWebsiteSSL'") } @@ -86,6 +100,7 @@ func (u *UploaderProvider) getExistCert(ctx context.Context, certPem string, pri PageSize: searchWebsiteSSLPageSize, } searchWebsiteSSLResp, err := u.sdkClient.SearchWebsiteSSL(searchWebsiteSSLReq) + u.logger.Debug("sdk request '1panel.SearchWebsiteSSL'", slog.Any("request", searchWebsiteSSLReq), slog.Any("response", searchWebsiteSSLResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request '1panel.SearchWebsiteSSL'") } @@ -93,7 +108,7 @@ func (u *UploaderProvider) getExistCert(ctx context.Context, certPem string, pri for _, sslItem := range searchWebsiteSSLResp.Data.Items { if strings.TrimSpace(sslItem.PEM) == strings.TrimSpace(certPem) && strings.TrimSpace(sslItem.PrivateKey) == strings.TrimSpace(privkeyPem) { - // 如果已存在相同证书,直接返回已有的证书信息 + // 如果已存在相同证书,直接返回 return &uploader.UploadResult{ CertId: fmt.Sprintf("%d", sslItem.ID), CertName: sslItem.Description, 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 2b582409..f7633cce 100644 --- a/internal/pkg/core/uploader/providers/aliyun-cas/aliyun_cas.go +++ b/internal/pkg/core/uploader/providers/aliyun-cas/aliyun_cas.go @@ -3,16 +3,17 @@ import ( "context" "fmt" + "log/slog" "strings" "time" - aliyunCas "github.com/alibabacloud-go/cas-20200407/v3/client" - aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client" + alicas "github.com/alibabacloud-go/cas-20200407/v3/client" + aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client" "github.com/alibabacloud-go/tea/tea" xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/pkg/core/uploader" - "github.com/usual2970/certimate/internal/pkg/utils/certs" + "github.com/usual2970/certimate/internal/pkg/utils/certutil" ) type UploaderConfig struct { @@ -26,7 +27,8 @@ type UploaderConfig struct { type UploaderProvider struct { config *UploaderConfig - sdkClient *aliyunCas.Client + logger *slog.Logger + sdkClient *alicas.Client } var _ uploader.Uploader = (*UploaderProvider)(nil) @@ -36,24 +38,30 @@ func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { panic("config is nil") } - client, err := createSdkClient( - config.AccessKeyId, - config.AccessKeySecret, - config.Region, - ) + client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region) if err != nil { return nil, xerrors.Wrap(err, "failed to create sdk client") } return &UploaderProvider{ config: config, + logger: slog.Default(), sdkClient: client, }, nil } +func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader { + if logger == nil { + u.logger = slog.Default() + } else { + u.logger = logger + } + return u +} + func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 解析证书内容 - certX509, err := certs.ParseCertificateFromPEM(certPem) + certX509, err := certutil.ParseCertificateFromPEM(certPem) if err != nil { return nil, err } @@ -64,12 +72,13 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe listUserCertificateOrderPage := int64(1) listUserCertificateOrderLimit := int64(50) for { - listUserCertificateOrderReq := &aliyunCas.ListUserCertificateOrderRequest{ + listUserCertificateOrderReq := &alicas.ListUserCertificateOrderRequest{ CurrentPage: tea.Int64(listUserCertificateOrderPage), ShowSize: tea.Int64(listUserCertificateOrderLimit), OrderType: tea.String("CERT"), } listUserCertificateOrderResp, err := u.sdkClient.ListUserCertificateOrder(listUserCertificateOrderReq) + u.logger.Debug("sdk request 'cas.ListUserCertificateOrder'", slog.Any("request", listUserCertificateOrderReq), slog.Any("response", listUserCertificateOrderResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cas.ListUserCertificateOrder'") } @@ -77,10 +86,11 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe if listUserCertificateOrderResp.Body.CertificateOrderList != nil { for _, certDetail := range listUserCertificateOrderResp.Body.CertificateOrderList { if strings.EqualFold(certX509.SerialNumber.Text(16), *certDetail.SerialNo) { - getUserCertificateDetailReq := &aliyunCas.GetUserCertificateDetailRequest{ + getUserCertificateDetailReq := &alicas.GetUserCertificateDetailRequest{ CertId: certDetail.CertificateId, } getUserCertificateDetailResp, err := u.sdkClient.GetUserCertificateDetail(getUserCertificateDetailReq) + u.logger.Debug("sdk request 'cas.GetUserCertificateDetail'", slog.Any("request", getUserCertificateDetailReq), slog.Any("response", getUserCertificateDetailResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cas.GetUserCertificateDetail'") } @@ -89,16 +99,17 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe if *getUserCertificateDetailResp.Body.Cert == certPem { isSameCert = true } else { - oldCertX509, err := certs.ParseCertificateFromPEM(*getUserCertificateDetailResp.Body.Cert) + oldCertX509, err := certutil.ParseCertificateFromPEM(*getUserCertificateDetailResp.Body.Cert) if err != nil { continue } - isSameCert = certs.EqualCertificate(certX509, oldCertX509) + isSameCert = certutil.EqualCertificate(certX509, oldCertX509) } - // 如果已存在相同证书,直接返回已有的证书信息 + // 如果已存在相同证书,直接返回 if isSameCert { + u.logger.Info("ssl certificate already exists") return &uploader.UploadResult{ CertId: fmt.Sprintf("%d", tea.Int64Value(certDetail.CertificateId)), CertName: *certDetail.Name, @@ -121,12 +132,13 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe // 上传新证书 // REF: https://help.aliyun.com/zh/ssl-certificate/developer-reference/api-cas-2020-04-07-uploadusercertificate - uploadUserCertificateReq := &aliyunCas.UploadUserCertificateRequest{ + uploadUserCertificateReq := &alicas.UploadUserCertificateRequest{ Name: tea.String(certName), Cert: tea.String(certPem), Key: tea.String(privkeyPem), } uploadUserCertificateResp, err := u.sdkClient.UploadUserCertificate(uploadUserCertificateReq) + u.logger.Debug("sdk request 'cas.UploadUserCertificate'", slog.Any("request", uploadUserCertificateReq), slog.Any("response", uploadUserCertificateResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cas.UploadUserCertificate'") } @@ -138,7 +150,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe }, nil } -func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunCas.Client, error) { +func createSdkClient(accessKeyId, accessKeySecret, region string) (*alicas.Client, error) { if region == "" { region = "cn-hangzhou" // CAS 服务默认区域:华东一杭州 } @@ -152,13 +164,13 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunCas.Cl endpoint = fmt.Sprintf("cas.%s.aliyuncs.com", region) } - config := &aliyunOpen.Config{ + config := &aliopen.Config{ Endpoint: tea.String(endpoint), AccessKeyId: tea.String(accessKeyId), AccessKeySecret: tea.String(accessKeySecret), } - client, err := aliyunCas.NewClient(config) + client, err := alicas.NewClient(config) if err != nil { return nil, err } 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 d687822a..59607ade 100644 --- a/internal/pkg/core/uploader/providers/aliyun-slb/aliyun_slb.go +++ b/internal/pkg/core/uploader/providers/aliyun-slb/aliyun_slb.go @@ -5,17 +5,18 @@ import ( "crypto/sha256" "encoding/hex" "fmt" + "log/slog" "regexp" "strings" "time" - aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client" - aliyunSlb "github.com/alibabacloud-go/slb-20140515/v4/client" + aliopen "github.com/alibabacloud-go/darabonba-openapi/v2/client" + alislb "github.com/alibabacloud-go/slb-20140515/v4/client" "github.com/alibabacloud-go/tea/tea" xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/pkg/core/uploader" - "github.com/usual2970/certimate/internal/pkg/utils/certs" + "github.com/usual2970/certimate/internal/pkg/utils/certutil" ) type UploaderConfig struct { @@ -29,7 +30,8 @@ type UploaderConfig struct { type UploaderProvider struct { config *UploaderConfig - sdkClient *aliyunSlb.Client + logger *slog.Logger + sdkClient *alislb.Client } var _ uploader.Uploader = (*UploaderProvider)(nil) @@ -39,34 +41,41 @@ func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { panic("config is nil") } - client, err := createSdkClient( - config.AccessKeyId, - config.AccessKeySecret, - config.Region, - ) + client, err := createSdkClient(config.AccessKeyId, config.AccessKeySecret, config.Region) if err != nil { return nil, xerrors.Wrap(err, "failed to create sdk client") } return &UploaderProvider{ config: config, + logger: slog.Default(), sdkClient: client, }, nil } +func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader { + if logger == nil { + u.logger = slog.Default() + } else { + u.logger = logger + } + return u +} + func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 解析证书内容 - certX509, err := certs.ParseCertificateFromPEM(certPem) + certX509, err := certutil.ParseCertificateFromPEM(certPem) if err != nil { return nil, err } // 查询证书列表,避免重复上传 // REF: https://help.aliyun.com/zh/slb/classic-load-balancer/developer-reference/api-slb-2014-05-15-describeservercertificates - describeServerCertificatesReq := &aliyunSlb.DescribeServerCertificatesRequest{ + describeServerCertificatesReq := &alislb.DescribeServerCertificatesRequest{ RegionId: tea.String(u.config.Region), } describeServerCertificatesResp, err := u.sdkClient.DescribeServerCertificates(describeServerCertificatesReq) + u.logger.Debug("sdk request 'slb.DescribeServerCertificates'", slog.Any("request", describeServerCertificatesReq), slog.Any("response", describeServerCertificatesResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'slb.DescribeServerCertificates'") } @@ -78,8 +87,9 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe isSameCert := *certDetail.IsAliCloudCertificate == 0 && strings.EqualFold(fingerprintHex, strings.ReplaceAll(*certDetail.Fingerprint, ":", "")) && strings.EqualFold(certX509.Subject.CommonName, *certDetail.CommonName) - // 如果已存在相同证书,直接返回已有的证书信息 + // 如果已存在相同证书,直接返回 if isSameCert { + u.logger.Info("ssl certificate already exists") return &uploader.UploadResult{ CertId: *certDetail.ServerCertificateId, CertName: *certDetail.ServerCertificateName, @@ -100,13 +110,14 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe // 上传新证书 // REF: https://help.aliyun.com/zh/slb/classic-load-balancer/developer-reference/api-slb-2014-05-15-uploadservercertificate - uploadServerCertificateReq := &aliyunSlb.UploadServerCertificateRequest{ + uploadServerCertificateReq := &alislb.UploadServerCertificateRequest{ RegionId: tea.String(u.config.Region), ServerCertificateName: tea.String(certName), ServerCertificate: tea.String(certPem), PrivateKey: tea.String(privkeyPem), } uploadServerCertificateResp, err := u.sdkClient.UploadServerCertificate(uploadServerCertificateReq) + u.logger.Debug("sdk request 'slb.UploadServerCertificate'", slog.Any("request", uploadServerCertificateReq), slog.Any("response", uploadServerCertificateResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'slb.UploadServerCertificate'") } @@ -118,7 +129,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe }, nil } -func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunSlb.Client, error) { +func createSdkClient(accessKeyId, accessKeySecret, region string) (*alislb.Client, error) { // 接入点一览 https://api.aliyun.com/product/Slb var endpoint string switch region { @@ -132,13 +143,13 @@ func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunSlb.Cl endpoint = fmt.Sprintf("slb.%s.aliyuncs.com", region) } - config := &aliyunOpen.Config{ + config := &aliopen.Config{ Endpoint: tea.String(endpoint), AccessKeyId: tea.String(accessKeyId), AccessKeySecret: tea.String(accessKeySecret), } - client, err := aliyunSlb.NewClient(config) + client, err := alislb.NewClient(config) if err != nil { return nil, err } 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 2f5db477..f0a3ccb5 100644 --- a/internal/pkg/core/uploader/providers/aws-acm/aws_acm.go +++ b/internal/pkg/core/uploader/providers/aws-acm/aws_acm.go @@ -2,16 +2,17 @@ import ( "context" + "log/slog" aws "github.com/aws/aws-sdk-go-v2/aws" - awsCfg "github.com/aws/aws-sdk-go-v2/config" - awsCred "github.com/aws/aws-sdk-go-v2/credentials" - awsAcm "github.com/aws/aws-sdk-go-v2/service/acm" + awscfg "github.com/aws/aws-sdk-go-v2/config" + awscred "github.com/aws/aws-sdk-go-v2/credentials" + awsacm "github.com/aws/aws-sdk-go-v2/service/acm" 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" + "github.com/usual2970/certimate/internal/pkg/utils/certutil" ) type UploaderConfig struct { @@ -25,7 +26,8 @@ type UploaderConfig struct { type UploaderProvider struct { config *UploaderConfig - sdkClient *awsAcm.Client + logger *slog.Logger + sdkClient *awsacm.Client } var _ uploader.Uploader = (*UploaderProvider)(nil) @@ -42,19 +44,29 @@ func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { return &UploaderProvider{ config: config, + logger: slog.Default(), sdkClient: client, }, nil } +func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader { + if logger == nil { + u.logger = slog.Default() + } else { + u.logger = logger + } + return u +} + func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 解析证书内容 - certX509, err := certs.ParseCertificateFromPEM(certPem) + certX509, err := certutil.ParseCertificateFromPEM(certPem) if err != nil { return nil, err } // 生成 AWS 业务参数 - scertPem, _ := certs.ConvertCertificateToPEM(certX509) + scertPem, _ := certutil.ConvertCertificateToPEM(certX509) bcertPem := certPem // 获取证书列表,避免重复上传 @@ -62,11 +74,12 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe listCertificatesNextToken := new(string) listCertificatesMaxItems := int32(1000) for { - listCertificatesReq := &awsAcm.ListCertificatesInput{ + listCertificatesReq := &awsacm.ListCertificatesInput{ NextToken: listCertificatesNextToken, MaxItems: aws.Int32(listCertificatesMaxItems), } listCertificatesResp, err := u.sdkClient.ListCertificates(context.TODO(), listCertificatesReq) + u.logger.Debug("sdk request 'acm.ListCertificates'", slog.Any("request", listCertificatesReq), slog.Any("response", listCertificatesResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'acm.ListCertificates'") } @@ -87,7 +100,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe // 最后对比证书内容 // REF: https://docs.aws.amazon.com/en_us/acm/latest/APIReference/API_ListTagsForCertificate.html - getCertificateReq := &awsAcm.GetCertificateInput{ + getCertificateReq := &awsacm.GetCertificateInput{ CertificateArn: certSummary.CertificateArn, } getCertificateResp, err := u.sdkClient.GetCertificate(context.TODO(), getCertificateReq) @@ -99,17 +112,18 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe oldCertPem = aws.ToString(getCertificateResp.Certificate) } - oldCertX509, err := certs.ParseCertificateFromPEM(oldCertPem) + oldCertX509, err := certutil.ParseCertificateFromPEM(oldCertPem) if err != nil { continue } - if !certs.EqualCertificate(certX509, oldCertX509) { + if !certutil.EqualCertificate(certX509, oldCertX509) { continue } } // 如果以上信息都一致,则视为已存在相同证书,直接返回 + u.logger.Info("ssl certificate already exists") return &uploader.UploadResult{ CertId: *certSummary.CertificateArn, }, nil @@ -124,12 +138,13 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe // 导入证书 // REF: https://docs.aws.amazon.com/en_us/acm/latest/APIReference/API_ImportCertificate.html - importCertificateReq := &awsAcm.ImportCertificateInput{ + importCertificateReq := &awsacm.ImportCertificateInput{ Certificate: ([]byte)(scertPem), CertificateChain: ([]byte)(bcertPem), PrivateKey: ([]byte)(privkeyPem), } importCertificateResp, err := u.sdkClient.ImportCertificate(context.TODO(), importCertificateReq) + u.logger.Debug("sdk request 'acm.ImportCertificate'", slog.Any("request", importCertificateReq), slog.Any("response", importCertificateResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'acm.ImportCertificate'") } @@ -139,15 +154,15 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe }, nil } -func createSdkClient(accessKeyId, secretAccessKey, region string) (*awsAcm.Client, error) { - cfg, err := awsCfg.LoadDefaultConfig(context.TODO()) +func createSdkClient(accessKeyId, secretAccessKey, region string) (*awsacm.Client, error) { + cfg, err := awscfg.LoadDefaultConfig(context.TODO()) if err != nil { return nil, err } - client := awsAcm.NewFromConfig(cfg, func(o *awsAcm.Options) { + client := awsacm.NewFromConfig(cfg, func(o *awsacm.Options) { o.Region = region - o.Credentials = aws.NewCredentialsCache(awsCred.NewStaticCredentialsProvider(accessKeyId, secretAccessKey, "")) + o.Credentials = aws.NewCredentialsCache(awscred.NewStaticCredentialsProvider(accessKeyId, secretAccessKey, "")) }) return client, nil } diff --git a/internal/pkg/core/uploader/providers/azure-keyvault/azure_keyvault.go b/internal/pkg/core/uploader/providers/azure-keyvault/azure_keyvault.go index 16109171..5f6f998a 100644 --- a/internal/pkg/core/uploader/providers/azure-keyvault/azure_keyvault.go +++ b/internal/pkg/core/uploader/providers/azure-keyvault/azure_keyvault.go @@ -4,6 +4,7 @@ import ( "context" "crypto/x509" "fmt" + "log/slog" "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore" @@ -13,7 +14,7 @@ import ( xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/pkg/core/uploader" - "github.com/usual2970/certimate/internal/pkg/utils/certs" + "github.com/usual2970/certimate/internal/pkg/utils/certutil" azcommon "github.com/usual2970/certimate/internal/pkg/vendors/azure-sdk/common" ) @@ -32,6 +33,7 @@ type UploaderConfig struct { type UploaderProvider struct { config *UploaderConfig + logger *slog.Logger sdkClient *azcertificates.Client } @@ -49,13 +51,23 @@ func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { return &UploaderProvider{ config: config, + logger: slog.Default(), sdkClient: client, }, nil } +func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader { + if logger == nil { + u.logger = slog.Default() + } else { + u.logger = logger + } + return u +} + func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 解析证书内容 - certX509, err := certs.ParseCertificateFromPEM(certPem) + certX509, err := certutil.ParseCertificateFromPEM(certPem) if err != nil { return nil, err } @@ -103,6 +115,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe // 最后对比证书内容 getCertificateResp, err := u.sdkClient.GetCertificate(context.TODO(), certItem.ID.Name(), certItem.ID.Version(), nil) + u.logger.Debug("sdk request 'keyvault.GetCertificate'", slog.String("request.certificateName", certItem.ID.Name()), slog.String("request.certificateVersion", certItem.ID.Version()), slog.Any("response", getCertificateResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'keyvault.GetCertificate'") } else { @@ -111,12 +124,13 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe continue } - if !certs.EqualCertificate(certX509, oldCertX509) { + if !certutil.EqualCertificate(certX509, oldCertX509) { continue } } // 如果以上信息都一致,则视为已存在相同证书,直接返回 + u.logger.Info("ssl certificate already exists") return &uploader.UploadResult{ CertId: string(*certItem.ID), CertName: certItem.ID.Name(), @@ -142,6 +156,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe }, } importCertificateResp, err := u.sdkClient.ImportCertificate(context.TODO(), certName, importCertificateParams, nil) + u.logger.Debug("sdk request 'keyvault.ImportCertificate'", slog.String("request.certificateName", certName), slog.Any("request.parameters", importCertificateParams), slog.Any("response", importCertificateResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'keyvault.ImportCertificate'") } 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 04116e31..cdba9d4f 100644 --- a/internal/pkg/core/uploader/providers/byteplus-cdn/byteplus_cdn.go +++ b/internal/pkg/core/uploader/providers/byteplus-cdn/byteplus_cdn.go @@ -6,14 +6,15 @@ import ( "crypto/sha256" "encoding/hex" "fmt" + "log/slog" "strings" "time" - bpCdn "github.com/byteplus-sdk/byteplus-sdk-golang/service/cdn" + bytepluscdn "github.com/byteplus-sdk/byteplus-sdk-golang/service/cdn" xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/pkg/core/uploader" - "github.com/usual2970/certimate/internal/pkg/utils/certs" + "github.com/usual2970/certimate/internal/pkg/utils/certutil" ) type UploaderConfig struct { @@ -25,7 +26,8 @@ type UploaderConfig struct { type UploaderProvider struct { config *UploaderConfig - sdkClient *bpCdn.CDN + logger *slog.Logger + sdkClient *bytepluscdn.CDN } var _ uploader.Uploader = (*UploaderProvider)(nil) @@ -35,19 +37,29 @@ func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { panic("config is nil") } - client := bpCdn.NewInstance() + client := bytepluscdn.NewInstance() client.Client.SetAccessKey(config.AccessKey) client.Client.SetSecretKey(config.SecretKey) return &UploaderProvider{ config: config, + logger: slog.Default(), sdkClient: client, }, nil } +func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader { + if logger == nil { + u.logger = slog.Default() + } else { + u.logger = logger + } + return u +} + func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 解析证书内容 - certX509, err := certs.ParseCertificateFromPEM(certPem) + certX509, err := certutil.ParseCertificateFromPEM(certPem) if err != nil { return nil, err } @@ -57,13 +69,14 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe listCertInfoPageNum := int64(1) listCertInfoPageSize := int64(100) listCertInfoTotal := 0 - listCertInfoReq := &bpCdn.ListCertInfoRequest{ - PageNum: bpCdn.GetInt64Ptr(listCertInfoPageNum), - PageSize: bpCdn.GetInt64Ptr(listCertInfoPageSize), - Source: bpCdn.GetStrPtr("cert_center"), + listCertInfoReq := &bytepluscdn.ListCertInfoRequest{ + PageNum: bytepluscdn.GetInt64Ptr(listCertInfoPageNum), + PageSize: bytepluscdn.GetInt64Ptr(listCertInfoPageSize), + Source: bytepluscdn.GetStrPtr("cert_center"), } for { listCertInfoResp, err := u.sdkClient.ListCertInfo(listCertInfoReq) + u.logger.Debug("sdk request 'cdn.ListCertInfo'", slog.Any("request", listCertInfoReq), slog.Any("response", listCertInfoResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.ListCertInfo'") } @@ -74,8 +87,9 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe fingerprintSha256 := sha256.Sum256(certX509.Raw) isSameCert := strings.EqualFold(hex.EncodeToString(fingerprintSha1[:]), certDetail.CertFingerprint.Sha1) && strings.EqualFold(hex.EncodeToString(fingerprintSha256[:]), certDetail.CertFingerprint.Sha256) - // 如果已存在相同证书,直接返回已有的证书信息 + // 如果已存在相同证书,直接返回 if isSameCert { + u.logger.Info("ssl certificate already exists") return &uploader.UploadResult{ CertId: certDetail.CertId, CertName: certDetail.Desc, @@ -99,13 +113,14 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe // 上传新证书 // REF: https://docs.byteplus.com/en/docs/byteplus-cdn/reference-addcertificate - addCertificateReq := &bpCdn.AddCertificateRequest{ + addCertificateReq := &bytepluscdn.AddCertificateRequest{ Certificate: certPem, PrivateKey: privkeyPem, - Source: bpCdn.GetStrPtr("cert_center"), - Desc: bpCdn.GetStrPtr(certName), + Source: bytepluscdn.GetStrPtr("cert_center"), + Desc: bytepluscdn.GetStrPtr(certName), } addCertificateResp, err := u.sdkClient.AddCertificate(addCertificateReq) + u.logger.Debug("sdk request 'cdn.AddCertificate'", slog.Any("request", addCertificateReq), slog.Any("response", addCertificateResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.AddCertificate'") } diff --git a/internal/pkg/core/uploader/providers/dogecloud/dogecloud.go b/internal/pkg/core/uploader/providers/dogecloud/dogecloud.go index 82856b6e..420f93bc 100644 --- a/internal/pkg/core/uploader/providers/dogecloud/dogecloud.go +++ b/internal/pkg/core/uploader/providers/dogecloud/dogecloud.go @@ -3,12 +3,13 @@ import ( "context" "fmt" + "log/slog" "time" xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/pkg/core/uploader" - doge "github.com/usual2970/certimate/internal/pkg/vendors/dogecloud-sdk" + dogesdk "github.com/usual2970/certimate/internal/pkg/vendors/dogecloud-sdk" ) type UploaderConfig struct { @@ -20,7 +21,8 @@ type UploaderConfig struct { type UploaderProvider struct { config *UploaderConfig - sdkClient *doge.Client + logger *slog.Logger + sdkClient *dogesdk.Client } var _ uploader.Uploader = (*UploaderProvider)(nil) @@ -30,20 +32,27 @@ func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { panic("config is nil") } - client, err := createSdkClient( - config.AccessKey, - config.SecretKey, - ) + client, err := createSdkClient(config.AccessKey, config.SecretKey) if err != nil { return nil, xerrors.Wrap(err, "failed to create sdk client") } return &UploaderProvider{ config: config, + logger: slog.Default(), sdkClient: client, }, nil } +func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader { + if logger == nil { + u.logger = slog.Default() + } else { + u.logger = logger + } + return u +} + func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 生成新证书名(需符合多吉云命名规则) var certId, certName string @@ -52,6 +61,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe // 上传新证书 // REF: https://docs.dogecloud.com/cdn/api-cert-upload uploadSslCertResp, err := u.sdkClient.UploadCdnCert(certName, certPem, privkeyPem) + u.logger.Debug("sdk request 'cdn.UploadCdnCert'", slog.Any("response", uploadSslCertResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.UploadCdnCert'") } @@ -63,7 +73,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe }, nil } -func createSdkClient(accessKey, secretKey string) (*doge.Client, error) { - client := doge.NewClient(accessKey, secretKey) +func createSdkClient(accessKey, secretKey string) (*dogesdk.Client, error) { + client := dogesdk.NewClient(accessKey, secretKey) return client, nil } diff --git a/internal/pkg/core/uploader/providers/gcore-cdn/gcore_cdn.go b/internal/pkg/core/uploader/providers/gcore-cdn/gcore_cdn.go index b990c694..7f0a6580 100644 --- a/internal/pkg/core/uploader/providers/gcore-cdn/gcore_cdn.go +++ b/internal/pkg/core/uploader/providers/gcore-cdn/gcore_cdn.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "log/slog" "time" gprovider "github.com/G-Core/gcorelabscdn-go/gcore/provider" @@ -21,6 +22,7 @@ type UploaderConfig struct { type UploaderProvider struct { config *UploaderConfig + logger *slog.Logger sdkClient *gsslcerts.Service } @@ -38,10 +40,20 @@ func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { return &UploaderProvider{ config: config, + logger: slog.Default(), sdkClient: client, }, nil } +func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader { + if logger == nil { + u.logger = slog.Default() + } else { + u.logger = logger + } + return u +} + func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 生成新证书名(需符合 Gcore 命名规则) var certId, certName string @@ -57,6 +69,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe ValidateRootCA: false, } createCertificateResp, err := u.sdkClient.Create(context.TODO(), createCertificateReq) + u.logger.Debug("sdk request 'sslcerts.Create'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'sslcerts.Create'") } 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 96a1ff7b..50d716a1 100644 --- a/internal/pkg/core/uploader/providers/huaweicloud-elb/huaweicloud_elb.go +++ b/internal/pkg/core/uploader/providers/huaweicloud-elb/huaweicloud_elb.go @@ -4,20 +4,21 @@ import ( "context" "errors" "fmt" + "log/slog" "time" "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic" "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/global" - hcElb "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/elb/v3" - hcElbModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/elb/v3/model" - hcElbRegion "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/elb/v3/region" - 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" + hcelb "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/elb/v3" + hcelbmodel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/elb/v3/model" + hcelbregion "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/elb/v3/region" + 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" xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/pkg/core/uploader" - "github.com/usual2970/certimate/internal/pkg/utils/certs" + "github.com/usual2970/certimate/internal/pkg/utils/certutil" hwsdk "github.com/usual2970/certimate/internal/pkg/vendors/huaweicloud-sdk" ) @@ -32,7 +33,8 @@ type UploaderConfig struct { type UploaderProvider struct { config *UploaderConfig - sdkClient *hcElb.ElbClient + logger *slog.Logger + sdkClient *hcelb.ElbClient } var _ uploader.Uploader = (*UploaderProvider)(nil) @@ -42,24 +44,30 @@ func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { panic("config is nil") } - client, err := createSdkClient( - config.AccessKeyId, - config.SecretAccessKey, - config.Region, - ) + 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, + logger: slog.Default(), sdkClient: client, }, nil } +func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader { + if logger == nil { + u.logger = slog.Default() + } else { + u.logger = logger + } + return u +} + func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 解析证书内容 - certX509, err := certs.ParseCertificateFromPEM(certPem) + certX509, err := certutil.ParseCertificateFromPEM(certPem) if err != nil { return nil, err } @@ -69,12 +77,13 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe listCertificatesLimit := int32(2000) var listCertificatesMarker *string = nil for { - listCertificatesReq := &hcElbModel.ListCertificatesRequest{ + listCertificatesReq := &hcelbmodel.ListCertificatesRequest{ Limit: hwsdk.Int32Ptr(listCertificatesLimit), Marker: listCertificatesMarker, Type: &[]string{"server"}, } listCertificatesResp, err := u.sdkClient.ListCertificates(listCertificatesReq) + u.logger.Debug("sdk request 'elb.ListCertificates'", slog.Any("request", listCertificatesReq), slog.Any("response", listCertificatesResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'elb.ListCertificates'") } @@ -85,16 +94,17 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe if certDetail.Certificate == certPem { isSameCert = true } else { - oldCertX509, err := certs.ParseCertificateFromPEM(certDetail.Certificate) + oldCertX509, err := certutil.ParseCertificateFromPEM(certDetail.Certificate) if err != nil { continue } - isSameCert = certs.EqualCertificate(certX509, oldCertX509) + isSameCert = certutil.EqualCertificate(certX509, oldCertX509) } - // 如果已存在相同证书,直接返回已有的证书信息 + // 如果已存在相同证书,直接返回 if isSameCert { + u.logger.Info("ssl certificate already exists") return &uploader.UploadResult{ CertId: certDetail.Id, CertName: certDetail.Name, @@ -123,9 +133,9 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe // 创建新证书 // REF: https://support.huaweicloud.com/api-elb/CreateCertificate.html - createCertificateReq := &hcElbModel.CreateCertificateRequest{ - Body: &hcElbModel.CreateCertificateRequestBody{ - Certificate: &hcElbModel.CreateCertificateOption{ + createCertificateReq := &hcelbmodel.CreateCertificateRequest{ + Body: &hcelbmodel.CreateCertificateRequestBody{ + Certificate: &hcelbmodel.CreateCertificateOption{ ProjectId: hwsdk.StringPtr(projectId), Name: hwsdk.StringPtr(certName), Certificate: hwsdk.StringPtr(certPem), @@ -134,6 +144,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe }, } createCertificateResp, err := u.sdkClient.CreateCertificate(createCertificateReq) + u.logger.Debug("sdk request 'elb.CreateCertificate'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'elb.CreateCertificate'") } @@ -146,7 +157,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe }, nil } -func createSdkClient(accessKeyId, secretAccessKey, region string) (*hcElb.ElbClient, error) { +func createSdkClient(accessKeyId, secretAccessKey, region string) (*hcelb.ElbClient, error) { if region == "" { region = "cn-north-4" // ELB 服务默认区域:华北四北京 } @@ -159,12 +170,12 @@ func createSdkClient(accessKeyId, secretAccessKey, region string) (*hcElb.ElbCli return nil, err } - hcRegion, err := hcElbRegion.SafeValueOf(region) + hcRegion, err := hcelbregion.SafeValueOf(region) if err != nil { return nil, err } - hcClient, err := hcElb.ElbClientBuilder(). + hcClient, err := hcelb.ElbClientBuilder(). WithRegion(hcRegion). WithCredential(auth). SafeBuild() @@ -172,7 +183,7 @@ func createSdkClient(accessKeyId, secretAccessKey, region string) (*hcElb.ElbCli return nil, err } - client := hcElb.NewElbClient(hcClient) + client := hcelb.NewElbClient(hcClient) return client, nil } @@ -189,12 +200,12 @@ func getSdkProjectId(accessKeyId, secretAccessKey, region string) (string, error return "", err } - hcRegion, err := hcIamRegion.SafeValueOf(region) + hcRegion, err := hciamregion.SafeValueOf(region) if err != nil { return "", err } - hcClient, err := hcIam.IamClientBuilder(). + hcClient, err := hciam.IamClientBuilder(). WithRegion(hcRegion). WithCredential(auth). SafeBuild() @@ -202,9 +213,9 @@ func getSdkProjectId(accessKeyId, secretAccessKey, region string) (string, error return "", err } - client := hcIam.NewIamClient(hcClient) + client := hciam.NewIamClient(hcClient) - request := &hcIamModel.KeystoneListProjectsRequest{ + request := &hciammodel.KeystoneListProjectsRequest{ Name: ®ion, } response, err := client.KeystoneListProjects(request) 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 9406c55d..94413993 100644 --- a/internal/pkg/core/uploader/providers/huaweicloud-scm/huaweicloud_scm.go +++ b/internal/pkg/core/uploader/providers/huaweicloud-scm/huaweicloud_scm.go @@ -3,16 +3,17 @@ import ( "context" "fmt" + "log/slog" "time" "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic" - hcScm "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/scm/v3" - hcScmModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/scm/v3/model" - hcScmRegion "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/scm/v3/region" + hcscm "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/scm/v3" + hcscmmodel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/scm/v3/model" + hcscmregion "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/scm/v3/region" xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/pkg/core/uploader" - "github.com/usual2970/certimate/internal/pkg/utils/certs" + "github.com/usual2970/certimate/internal/pkg/utils/certutil" hwsdk "github.com/usual2970/certimate/internal/pkg/vendors/huaweicloud-sdk" ) @@ -27,7 +28,8 @@ type UploaderConfig struct { type UploaderProvider struct { config *UploaderConfig - sdkClient *hcScm.ScmClient + logger *slog.Logger + sdkClient *hcscm.ScmClient } var _ uploader.Uploader = (*UploaderProvider)(nil) @@ -37,24 +39,30 @@ func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { panic("config is nil") } - client, err := createSdkClient( - config.AccessKeyId, - config.SecretAccessKey, - config.Region, - ) + 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, + logger: slog.Default(), sdkClient: client, }, nil } +func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader { + if logger == nil { + u.logger = slog.Default() + } else { + u.logger = logger + } + return u +} + func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 解析证书内容 - certX509, err := certs.ParseCertificateFromPEM(certPem) + certX509, err := certutil.ParseCertificateFromPEM(certPem) if err != nil { return nil, err } @@ -65,23 +73,25 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe listCertificatesLimit := int32(50) listCertificatesOffset := int32(0) for { - listCertificatesReq := &hcScmModel.ListCertificatesRequest{ + listCertificatesReq := &hcscmmodel.ListCertificatesRequest{ Limit: hwsdk.Int32Ptr(listCertificatesLimit), Offset: hwsdk.Int32Ptr(listCertificatesOffset), SortDir: hwsdk.StringPtr("DESC"), SortKey: hwsdk.StringPtr("certExpiredTime"), } listCertificatesResp, err := u.sdkClient.ListCertificates(listCertificatesReq) + u.logger.Debug("sdk request 'scm.ListCertificates'", slog.Any("request", listCertificatesReq), slog.Any("response", listCertificatesResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'scm.ListCertificates'") } if listCertificatesResp.Certificates != nil { for _, certDetail := range *listCertificatesResp.Certificates { - exportCertificateReq := &hcScmModel.ExportCertificateRequest{ + exportCertificateReq := &hcscmmodel.ExportCertificateRequest{ CertificateId: certDetail.Id, } exportCertificateResp, err := u.sdkClient.ExportCertificate(exportCertificateReq) + u.logger.Debug("sdk request 'scm.ExportCertificate'", slog.Any("request", exportCertificateReq), slog.Any("response", exportCertificateResp)) if err != nil { if exportCertificateResp != nil && exportCertificateResp.HttpStatusCode == 404 { continue @@ -93,16 +103,17 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe if *exportCertificateResp.Certificate == certPem { isSameCert = true } else { - oldCertX509, err := certs.ParseCertificateFromPEM(*exportCertificateResp.Certificate) + oldCertX509, err := certutil.ParseCertificateFromPEM(*exportCertificateResp.Certificate) if err != nil { continue } - isSameCert = certs.EqualCertificate(certX509, oldCertX509) + isSameCert = certutil.EqualCertificate(certX509, oldCertX509) } - // 如果已存在相同证书,直接返回已有的证书信息 + // 如果已存在相同证书,直接返回 if isSameCert { + u.logger.Info("ssl certificate already exists") return &uploader.UploadResult{ CertId: certDetail.Id, CertName: certDetail.Name, @@ -124,14 +135,15 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe // 上传新证书 // REF: https://support.huaweicloud.com/api-ccm/ImportCertificate.html - importCertificateReq := &hcScmModel.ImportCertificateRequest{ - Body: &hcScmModel.ImportCertificateRequestBody{ + importCertificateReq := &hcscmmodel.ImportCertificateRequest{ + Body: &hcscmmodel.ImportCertificateRequestBody{ Name: certName, Certificate: certPem, PrivateKey: privkeyPem, }, } importCertificateResp, err := u.sdkClient.ImportCertificate(importCertificateReq) + u.logger.Debug("sdk request 'scm.ImportCertificate'", slog.Any("request", importCertificateReq), slog.Any("response", importCertificateResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'scm.ImportCertificate'") } @@ -143,7 +155,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe }, nil } -func createSdkClient(accessKeyId, secretAccessKey, region string) (*hcScm.ScmClient, error) { +func createSdkClient(accessKeyId, secretAccessKey, region string) (*hcscm.ScmClient, error) { if region == "" { region = "cn-north-4" // SCM 服务默认区域:华北四北京 } @@ -156,12 +168,12 @@ func createSdkClient(accessKeyId, secretAccessKey, region string) (*hcScm.ScmCli return nil, err } - hcRegion, err := hcScmRegion.SafeValueOf(region) + hcRegion, err := hcscmregion.SafeValueOf(region) if err != nil { return nil, err } - hcClient, err := hcScm.ScmClientBuilder(). + hcClient, err := hcscm.ScmClientBuilder(). WithRegion(hcRegion). WithCredential(auth). SafeBuild() @@ -169,6 +181,6 @@ func createSdkClient(accessKeyId, secretAccessKey, region string) (*hcScm.ScmCli return nil, err } - client := hcScm.NewScmClient(hcClient) + client := hcscm.NewScmClient(hcClient) return client, 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 index 19e7cea7..86d25426 100644 --- a/internal/pkg/core/uploader/providers/huaweicloud-waf/huaweicloud_waf.go +++ b/internal/pkg/core/uploader/providers/huaweicloud-waf/huaweicloud_waf.go @@ -4,20 +4,21 @@ import ( "context" "errors" "fmt" + "log/slog" "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" + 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" + "github.com/usual2970/certimate/internal/pkg/utils/certutil" hwsdk "github.com/usual2970/certimate/internal/pkg/vendors/huaweicloud-sdk" ) @@ -32,7 +33,8 @@ type UploaderConfig struct { type UploaderProvider struct { config *UploaderConfig - sdkClient *hcWaf.WafClient + logger *slog.Logger + sdkClient *hcwaf.WafClient } var _ uploader.Uploader = (*UploaderProvider)(nil) @@ -42,24 +44,30 @@ func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { panic("config is nil") } - client, err := createSdkClient( - config.AccessKeyId, - config.SecretAccessKey, - config.Region, - ) + 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, + logger: slog.Default(), sdkClient: client, }, nil } +func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader { + if logger == nil { + u.logger = slog.Default() + } else { + u.logger = logger + } + return u +} + func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 解析证书内容 - certX509, err := certs.ParseCertificateFromPEM(certPem) + certX509, err := certutil.ParseCertificateFromPEM(certPem) if err != nil { return nil, err } @@ -70,21 +78,23 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe listCertificatesPage := int32(1) listCertificatesPageSize := int32(100) for { - listCertificatesReq := &hcWafModel.ListCertificatesRequest{ + listCertificatesReq := &hcwafmodel.ListCertificatesRequest{ Page: hwsdk.Int32Ptr(listCertificatesPage), Pagesize: hwsdk.Int32Ptr(listCertificatesPageSize), } listCertificatesResp, err := u.sdkClient.ListCertificates(listCertificatesReq) + u.logger.Debug("sdk request 'waf.ShowCertificate'", slog.Any("request", listCertificatesReq), slog.Any("response", listCertificatesResp)) 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{ + showCertificateReq := &hcwafmodel.ShowCertificateRequest{ CertificateId: certItem.Id, } showCertificateResp, err := u.sdkClient.ShowCertificate(showCertificateReq) + u.logger.Debug("sdk request 'waf.ShowCertificate'", slog.Any("request", showCertificateReq), slog.Any("response", showCertificateResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'waf.ShowCertificate'") } @@ -93,16 +103,17 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe if *showCertificateResp.Content == certPem { isSameCert = true } else { - oldCertX509, err := certs.ParseCertificateFromPEM(*showCertificateResp.Content) + oldCertX509, err := certutil.ParseCertificateFromPEM(*showCertificateResp.Content) if err != nil { continue } - isSameCert = certs.EqualCertificate(certX509, oldCertX509) + isSameCert = certutil.EqualCertificate(certX509, oldCertX509) } - // 如果已存在相同证书,直接返回已有的证书信息 + // 如果已存在相同证书,直接返回 if isSameCert { + u.logger.Info("ssl certificate already exists") return &uploader.UploadResult{ CertId: certItem.Id, CertName: certItem.Name, @@ -124,14 +135,15 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe // 创建证书 // REF: https://support.huaweicloud.com/api-waf/CreateCertificate.html - createCertificateReq := &hcWafModel.CreateCertificateRequest{ - Body: &hcWafModel.CreateCertificateRequestBody{ + createCertificateReq := &hcwafmodel.CreateCertificateRequest{ + Body: &hcwafmodel.CreateCertificateRequestBody{ Name: certName, Content: certPem, Key: privkeyPem, }, } createCertificateResp, err := u.sdkClient.CreateCertificate(createCertificateReq) + u.logger.Debug("sdk request 'waf.CreateCertificate'", slog.Any("request", createCertificateReq), slog.Any("response", createCertificateResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'waf.CreateCertificate'") } @@ -144,7 +156,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe }, nil } -func createSdkClient(accessKeyId, secretAccessKey, region string) (*hcWaf.WafClient, error) { +func createSdkClient(accessKeyId, secretAccessKey, region string) (*hcwaf.WafClient, error) { projectId, err := getSdkProjectId(accessKeyId, secretAccessKey, region) if err != nil { return nil, err @@ -159,12 +171,12 @@ func createSdkClient(accessKeyId, secretAccessKey, region string) (*hcWaf.WafCli return nil, err } - hcRegion, err := hcWafRegion.SafeValueOf(region) + hcRegion, err := hcwafregion.SafeValueOf(region) if err != nil { return nil, err } - hcClient, err := hcWaf.WafClientBuilder(). + hcClient, err := hcwaf.WafClientBuilder(). WithRegion(hcRegion). WithCredential(auth). SafeBuild() @@ -172,7 +184,7 @@ func createSdkClient(accessKeyId, secretAccessKey, region string) (*hcWaf.WafCli return nil, err } - client := hcWaf.NewWafClient(hcClient) + client := hcwaf.NewWafClient(hcClient) return client, nil } @@ -185,12 +197,12 @@ func getSdkProjectId(accessKeyId, secretAccessKey, region string) (string, error return "", err } - hcRegion, err := hcIamRegion.SafeValueOf(region) + hcRegion, err := hciamregion.SafeValueOf(region) if err != nil { return "", err } - hcClient, err := hcIam.IamClientBuilder(). + hcClient, err := hciam.IamClientBuilder(). WithRegion(hcRegion). WithCredential(auth). SafeBuild() @@ -198,9 +210,9 @@ func getSdkProjectId(accessKeyId, secretAccessKey, region string) (string, error return "", err } - client := hcIam.NewIamClient(hcClient) + client := hciam.NewIamClient(hcClient) - request := &hcIamModel.KeystoneListProjectsRequest{ + request := &hciammodel.KeystoneListProjectsRequest{ Name: ®ion, } response, err := client.KeystoneListProjects(request) diff --git a/internal/pkg/core/uploader/providers/jdcloud-ssl/jdcloud_ssl.go b/internal/pkg/core/uploader/providers/jdcloud-ssl/jdcloud_ssl.go index 6518bf41..10f7c203 100644 --- a/internal/pkg/core/uploader/providers/jdcloud-ssl/jdcloud_ssl.go +++ b/internal/pkg/core/uploader/providers/jdcloud-ssl/jdcloud_ssl.go @@ -5,17 +5,18 @@ import ( "crypto/sha256" "encoding/hex" "fmt" + "log/slog" "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" + 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" + "github.com/usual2970/certimate/internal/pkg/utils/certutil" ) type UploaderConfig struct { @@ -27,7 +28,8 @@ type UploaderConfig struct { type UploaderProvider struct { config *UploaderConfig - sdkClient *jdSslClient.SslClient + logger *slog.Logger + sdkClient *jdsslclient.SslClient } var _ uploader.Uploader = (*UploaderProvider)(nil) @@ -44,13 +46,23 @@ func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { return &UploaderProvider{ config: config, + logger: slog.Default(), sdkClient: client, }, nil } +func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader { + if logger == nil { + u.logger = slog.Default() + } else { + u.logger = logger + } + return u +} + func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 解析证书内容 - certX509, err := certs.ParseCertificateFromPEM(certPem) + certX509, err := certutil.ParseCertificateFromPEM(certPem) if err != nil { return nil, err } @@ -66,11 +78,12 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe describeCertsPageNumber := 1 describeCertsPageSize := 10 for { - describeCertsReq := jdSslApi.NewDescribeCertsRequest() + describeCertsReq := jdsslapi.NewDescribeCertsRequest() describeCertsReq.SetDomainName(certX509.Subject.CommonName) describeCertsReq.SetPageNumber(describeCertsPageNumber) describeCertsReq.SetPageSize(describeCertsPageSize) describeCertsResp, err := u.sdkClient.DescribeCerts(describeCertsReq) + u.logger.Debug("sdk request 'ssl.DescribeCerts'", slog.Any("request", describeCertsReq), slog.Any("response", describeCertsResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'ssl.DescribeCerts'") } @@ -101,6 +114,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe } // 如果以上信息都一致,则视为已存在相同证书,直接返回 + u.logger.Info("ssl certificate already exists") return &uploader.UploadResult{ CertId: certDetail.CertId, CertName: certDetail.CertName, @@ -119,8 +133,9 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe // 上传证书 // REF: https://docs.jdcloud.com/cn/ssl-certificate/api/uploadcert - uploadCertReq := jdSslApi.NewUploadCertRequest(certName, privkeyPem, certPem) + uploadCertReq := jdsslapi.NewUploadCertRequest(certName, privkeyPem, certPem) uploadCertResp, err := u.sdkClient.UploadCert(uploadCertReq) + u.logger.Debug("sdk request 'ssl.UploadCertificate'", slog.Any("request", uploadCertReq), slog.Any("response", uploadCertResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'ssl.UploadCertificate'") } @@ -131,9 +146,9 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe }, nil } -func createSdkClient(accessKeyId, accessKeySecret string) (*jdSslClient.SslClient, error) { - clientCredentials := jdCore.NewCredentials(accessKeyId, accessKeySecret) - client := jdSslClient.NewSslClient(clientCredentials) - client.SetLogger(jdCore.NewDefaultLogger(jdCore.LogWarn)) +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/qiniu-sslcert/qiniu_sslcert.go b/internal/pkg/core/uploader/providers/qiniu-sslcert/qiniu_sslcert.go index 05c57be8..6bc71c3f 100644 --- a/internal/pkg/core/uploader/providers/qiniu-sslcert/qiniu_sslcert.go +++ b/internal/pkg/core/uploader/providers/qiniu-sslcert/qiniu_sslcert.go @@ -2,15 +2,17 @@ import ( "context" + "errors" "fmt" + "log/slog" "time" xerrors "github.com/pkg/errors" "github.com/qiniu/go-sdk/v7/auth" "github.com/usual2970/certimate/internal/pkg/core/uploader" - "github.com/usual2970/certimate/internal/pkg/utils/certs" - qiniuEx "github.com/usual2970/certimate/internal/pkg/vendors/qiniu-sdk" + "github.com/usual2970/certimate/internal/pkg/utils/certutil" + qiniusdk "github.com/usual2970/certimate/internal/pkg/vendors/qiniu-sdk" ) type UploaderConfig struct { @@ -22,7 +24,8 @@ type UploaderConfig struct { type UploaderProvider struct { config *UploaderConfig - sdkClient *qiniuEx.Client + logger *slog.Logger + sdkClient *qiniusdk.Client } var _ uploader.Uploader = (*UploaderProvider)(nil) @@ -32,23 +35,30 @@ func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { panic("config is nil") } - client, err := createSdkClient( - config.AccessKey, - config.SecretKey, - ) + client, err := createSdkClient(config.AccessKey, config.SecretKey) if err != nil { return nil, xerrors.Wrap(err, "failed to create sdk client") } return &UploaderProvider{ config: config, + logger: slog.Default(), sdkClient: client, }, nil } +func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader { + if logger == nil { + u.logger = slog.Default() + } else { + u.logger = logger + } + return u +} + func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 解析证书内容 - certX509, err := certs.ParseCertificateFromPEM(certPem) + certX509, err := certutil.ParseCertificateFromPEM(certPem) if err != nil { return nil, err } @@ -60,6 +70,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe // 上传新证书 // REF: https://developer.qiniu.com/fusion/8593/interface-related-certificate uploadSslCertResp, err := u.sdkClient.UploadSslCert(context.TODO(), certName, certX509.Subject.CommonName, certPem, privkeyPem) + u.logger.Debug("sdk request 'cdn.UploadSslCert'", slog.Any("response", uploadSslCertResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.UploadSslCert'") } @@ -71,8 +82,16 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe }, nil } -func createSdkClient(accessKey, secretKey string) (*qiniuEx.Client, error) { +func createSdkClient(accessKey, secretKey string) (*qiniusdk.Client, error) { + if secretKey == "" { + return nil, errors.New("invalid qiniu access key") + } + + if secretKey == "" { + return nil, errors.New("invalid qiniu secret key") + } + credential := auth.New(accessKey, secretKey) - client := qiniuEx.NewClient(credential) + client := qiniusdk.NewClient(credential) return client, 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 a76bf2a0..45c7ba9e 100644 --- a/internal/pkg/core/uploader/providers/tencentcloud-ssl/tencentcloud_ssl.go +++ b/internal/pkg/core/uploader/providers/tencentcloud-ssl/tencentcloud_ssl.go @@ -2,11 +2,12 @@ import ( "context" + "log/slog" xerrors "github.com/pkg/errors" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile" - tcSsl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205" + tcssl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205" "github.com/usual2970/certimate/internal/pkg/core/uploader" ) @@ -20,7 +21,8 @@ type UploaderConfig struct { type UploaderProvider struct { config *UploaderConfig - sdkClient *tcSsl.Client + logger *slog.Logger + sdkClient *tcssl.Client } var _ uploader.Uploader = (*UploaderProvider)(nil) @@ -30,28 +32,36 @@ func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { panic("config is nil") } - client, err := createSdkClient( - config.SecretId, - config.SecretKey, - ) + client, err := createSdkClient(config.SecretId, config.SecretKey) if err != nil { return nil, xerrors.Wrap(err, "failed to create sdk client") } return &UploaderProvider{ config: config, + logger: slog.Default(), sdkClient: client, }, nil } +func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader { + if logger == nil { + u.logger = slog.Default() + } else { + u.logger = logger + } + return u +} + 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() + uploadCertificateReq := tcssl.NewUploadCertificateRequest() uploadCertificateReq.CertificatePublicKey = common.StringPtr(certPem) uploadCertificateReq.CertificatePrivateKey = common.StringPtr(privkeyPem) uploadCertificateReq.Repeatable = common.BoolPtr(false) uploadCertificateResp, err := u.sdkClient.UploadCertificate(uploadCertificateReq) + u.logger.Debug("sdk request 'ssl.UploadCertificate'", slog.Any("request", uploadCertificateReq), slog.Any("response", uploadCertificateResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'ssl.UploadCertificate'") } @@ -63,9 +73,9 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe }, nil } -func createSdkClient(secretId, secretKey string) (*tcSsl.Client, error) { +func createSdkClient(secretId, secretKey string) (*tcssl.Client, error) { credential := common.NewCredential(secretId, secretKey) - client, err := tcSsl.NewClient(credential, "", profile.NewClientProfile()) + client, err := tcssl.NewClient(credential, "", profile.NewClientProfile()) if err != nil { return nil, err } 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 67506bf4..b8639bf3 100644 --- a/internal/pkg/core/uploader/providers/ucloud-ussl/ucloud_ussl.go +++ b/internal/pkg/core/uploader/providers/ucloud-ussl/ucloud_ussl.go @@ -8,16 +8,17 @@ import ( "encoding/hex" "errors" "fmt" + "log/slog" "strings" "time" xerrors "github.com/pkg/errors" - usdk "github.com/ucloud/ucloud-sdk-go/ucloud" - uAuth "github.com/ucloud/ucloud-sdk-go/ucloud/auth" + "github.com/ucloud/ucloud-sdk-go/ucloud" + ucloudauth "github.com/ucloud/ucloud-sdk-go/ucloud/auth" "github.com/usual2970/certimate/internal/pkg/core/uploader" - "github.com/usual2970/certimate/internal/pkg/utils/certs" - usdkSsl "github.com/usual2970/certimate/internal/pkg/vendors/ucloud-sdk/ussl" + "github.com/usual2970/certimate/internal/pkg/utils/certutil" + usslsdk "github.com/usual2970/certimate/internal/pkg/vendors/ucloud-sdk/ussl" ) type UploaderConfig struct { @@ -31,7 +32,8 @@ type UploaderConfig struct { type UploaderProvider struct { config *UploaderConfig - sdkClient *usdkSsl.USSLClient + logger *slog.Logger + sdkClient *usslsdk.USSLClient } var _ uploader.Uploader = (*UploaderProvider)(nil) @@ -48,10 +50,20 @@ func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { return &UploaderProvider{ config: config, + logger: slog.Default(), sdkClient: client, }, nil } +func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader { + if logger == nil { + u.logger = slog.Default() + } else { + u.logger = logger + } + return u +} + func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 生成新证书名(需符合优刻得命名规则) var certId, certName string @@ -66,14 +78,15 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe // 上传托管证书 // REF: https://docs.ucloud.cn/api/usslcertificate-api/upload_normal_certificate uploadNormalCertificateReq := u.sdkClient.NewUploadNormalCertificateRequest() - uploadNormalCertificateReq.CertificateName = usdk.String(certName) - uploadNormalCertificateReq.SslPublicKey = usdk.String(certPemBase64) - uploadNormalCertificateReq.SslPrivateKey = usdk.String(privkeyPemBase64) - uploadNormalCertificateReq.SslMD5 = usdk.String(certMd5Hex) + uploadNormalCertificateReq.CertificateName = ucloud.String(certName) + uploadNormalCertificateReq.SslPublicKey = ucloud.String(certPemBase64) + uploadNormalCertificateReq.SslPrivateKey = ucloud.String(privkeyPemBase64) + uploadNormalCertificateReq.SslMD5 = ucloud.String(certMd5Hex) if u.config.ProjectId != "" { - uploadNormalCertificateReq.ProjectId = usdk.String(u.config.ProjectId) + uploadNormalCertificateReq.ProjectId = ucloud.String(u.config.ProjectId) } uploadNormalCertificateResp, err := u.sdkClient.UploadNormalCertificate(uploadNormalCertificateReq) + u.logger.Debug("sdk request 'ussl.UploadNormalCertificate'", slog.Any("request", uploadNormalCertificateReq), slog.Any("response", uploadNormalCertificateResp)) if err != nil { if uploadNormalCertificateResp != nil && uploadNormalCertificateResp.GetRetCode() == 80035 { if res, err := u.getExistCert(ctx, certPem); err != nil { @@ -81,6 +94,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe } else if res == nil { return nil, errors.New("no certificate found") } else { + u.logger.Info("ssl certificate already exists") return res, nil } } @@ -92,7 +106,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe return &uploader.UploadResult{ CertId: certId, CertName: certName, - ExtendedData: map[string]interface{}{ + ExtendedData: map[string]any{ "resourceId": uploadNormalCertificateResp.LongResourceID, }, }, nil @@ -100,7 +114,7 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe func (u *UploaderProvider) getExistCert(ctx context.Context, certPem string) (res *uploader.UploadResult, err error) { // 解析证书内容 - certX509, err := certs.ParseCertificateFromPEM(certPem) + certX509, err := certutil.ParseCertificateFromPEM(certPem) if err != nil { return nil, err } @@ -112,15 +126,16 @@ func (u *UploaderProvider) getExistCert(ctx context.Context, certPem string) (re getCertificateListLimit := int(1000) for { getCertificateListReq := u.sdkClient.NewGetCertificateListRequest() - getCertificateListReq.Mode = usdk.String("trust") - getCertificateListReq.Domain = usdk.String(certX509.Subject.CommonName) - getCertificateListReq.Sort = usdk.String("2") - getCertificateListReq.Page = usdk.Int(getCertificateListPage) - getCertificateListReq.PageSize = usdk.Int(getCertificateListLimit) + getCertificateListReq.Mode = ucloud.String("trust") + getCertificateListReq.Domain = ucloud.String(certX509.Subject.CommonName) + getCertificateListReq.Sort = ucloud.String("2") + getCertificateListReq.Page = ucloud.Int(getCertificateListPage) + getCertificateListReq.PageSize = ucloud.Int(getCertificateListLimit) if u.config.ProjectId != "" { - getCertificateListReq.ProjectId = usdk.String(u.config.ProjectId) + getCertificateListReq.ProjectId = ucloud.String(u.config.ProjectId) } getCertificateListResp, err := u.sdkClient.GetCertificateList(getCertificateListReq) + u.logger.Debug("sdk request 'ussl.GetCertificateList'", slog.Any("request", getCertificateListReq), slog.Any("response", getCertificateListResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'ussl.GetCertificateList'") } @@ -143,9 +158,9 @@ func (u *UploaderProvider) getExistCert(ctx context.Context, certPem string) (re } getCertificateDetailInfoReq := u.sdkClient.NewGetCertificateDetailInfoRequest() - getCertificateDetailInfoReq.CertificateID = usdk.Int(certInfo.CertificateID) + getCertificateDetailInfoReq.CertificateID = ucloud.Int(certInfo.CertificateID) if u.config.ProjectId != "" { - getCertificateDetailInfoReq.ProjectId = usdk.String(u.config.ProjectId) + getCertificateDetailInfoReq.ProjectId = ucloud.String(u.config.ProjectId) } getCertificateDetailInfoResp, err := u.sdkClient.GetCertificateDetailInfo(getCertificateDetailInfoReq) if err != nil { @@ -197,7 +212,7 @@ func (u *UploaderProvider) getExistCert(ctx context.Context, certPem string) (re return &uploader.UploadResult{ CertId: fmt.Sprintf("%d", certInfo.CertificateID), CertName: certInfo.Name, - ExtendedData: map[string]interface{}{ + ExtendedData: map[string]any{ "resourceId": certInfo.CertificateSN, }, }, nil @@ -214,13 +229,13 @@ func (u *UploaderProvider) getExistCert(ctx context.Context, certPem string) (re return nil, nil } -func createSdkClient(privateKey, publicKey string) (*usdkSsl.USSLClient, error) { - cfg := usdk.NewConfig() +func createSdkClient(privateKey, publicKey string) (*usslsdk.USSLClient, error) { + cfg := ucloud.NewConfig() - credential := uAuth.NewCredential() + credential := ucloudauth.NewCredential() credential.PrivateKey = privateKey credential.PublicKey = publicKey - client := usdkSsl.NewClient(&cfg, &credential) + client := usslsdk.NewClient(&cfg, &credential) return client, nil } diff --git a/internal/pkg/core/uploader/providers/upyun-ssl/upyun_ssl.go b/internal/pkg/core/uploader/providers/upyun-ssl/upyun_ssl.go new file mode 100644 index 00000000..3e4d3c40 --- /dev/null +++ b/internal/pkg/core/uploader/providers/upyun-ssl/upyun_ssl.go @@ -0,0 +1,83 @@ +package upyunssl + +import ( + "context" + "errors" + "log/slog" + + xerrors "github.com/pkg/errors" + + "github.com/usual2970/certimate/internal/pkg/core/uploader" + upyunsdk "github.com/usual2970/certimate/internal/pkg/vendors/upyun-sdk/console" +) + +type UploaderConfig struct { + // 又拍云账号用户名。 + Username string `json:"username"` + // 又拍云账号密码。 + Password string `json:"password"` +} + +type UploaderProvider struct { + config *UploaderConfig + logger *slog.Logger + sdkClient *upyunsdk.Client +} + +var _ uploader.Uploader = (*UploaderProvider)(nil) + +func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { + if config == nil { + panic("config is nil") + } + + client, err := createSdkClient(config.Username, config.Password) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + return &UploaderProvider{ + config: config, + logger: slog.Default(), + sdkClient: client, + }, nil +} + +func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader { + if logger == nil { + u.logger = slog.Default() + } else { + u.logger = logger + } + return u +} + +func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { + // 上传证书 + uploadHttpsCertificateReq := &upyunsdk.UploadHttpsCertificateRequest{ + Certificate: certPem, + PrivateKey: privkeyPem, + } + uploadHttpsCertificateResp, err := u.sdkClient.UploadHttpsCertificate(uploadHttpsCertificateReq) + u.logger.Debug("sdk request 'ssl.UploadHttpsCertificate'", slog.Any("response", uploadHttpsCertificateResp)) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'ssl.UploadHttpsCertificate'") + } + + return &uploader.UploadResult{ + CertId: uploadHttpsCertificateResp.Data.Result.CertificateId, + }, nil +} + +func createSdkClient(username, password string) (*upyunsdk.Client, error) { + if username == "" { + return nil, errors.New("invalid upyun username") + } + + if password == "" { + return nil, errors.New("invalid upyun password") + } + + client := upyunsdk.NewClient(username, password) + return client, nil +} diff --git a/internal/pkg/core/uploader/providers/upyun-ssl/upyun_ssl_test.go b/internal/pkg/core/uploader/providers/upyun-ssl/upyun_ssl_test.go new file mode 100644 index 00000000..1e6d81ec --- /dev/null +++ b/internal/pkg/core/uploader/providers/upyun-ssl/upyun_ssl_test.go @@ -0,0 +1,72 @@ +package upyunssl_test + +import ( + "context" + "encoding/json" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/upyun-ssl" +) + +var ( + fInputCertPath string + fInputKeyPath string + fUsername string + fPassword string +) + +func init() { + argsPrefix := "CERTIMATE_UPLOADER_UPYUNSSL_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fUsername, argsPrefix+"USERNAME", "", "") + flag.StringVar(&fPassword, argsPrefix+"PASSWORD", "", "") +} + +/* +Shell command to run this test: + + go test -v ./upyun_ssl_test.go -args \ + --CERTIMATE_UPLOADER_UPYUNSSL_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_UPLOADER_UPYUNSSL_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_UPLOADER_UPYUNSSL_USERNAME="your-username" \ + --CERTIMATE_UPLOADER_UPYUNSSL_PASSWORD="your-password" +*/ +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("USERNAME: %v", fUsername), + fmt.Sprintf("PASSWORD: %v", fPassword), + }, "\n")) + + uploader, err := provider.NewUploader(&provider.UploaderConfig{ + Username: fUsername, + Password: fPassword, + }) + 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/volcengine-cdn/volcengine_cdn.go b/internal/pkg/core/uploader/providers/volcengine-cdn/volcengine_cdn.go index 9b5c9b56..2fe52472 100644 --- a/internal/pkg/core/uploader/providers/volcengine-cdn/volcengine_cdn.go +++ b/internal/pkg/core/uploader/providers/volcengine-cdn/volcengine_cdn.go @@ -6,15 +6,16 @@ import ( "crypto/sha256" "encoding/hex" "fmt" + "log/slog" "strings" "time" xerrors "github.com/pkg/errors" - veCdn "github.com/volcengine/volc-sdk-golang/service/cdn" + vecdn "github.com/volcengine/volc-sdk-golang/service/cdn" ve "github.com/volcengine/volcengine-go-sdk/volcengine" "github.com/usual2970/certimate/internal/pkg/core/uploader" - "github.com/usual2970/certimate/internal/pkg/utils/certs" + "github.com/usual2970/certimate/internal/pkg/utils/certutil" ) type UploaderConfig struct { @@ -26,7 +27,8 @@ type UploaderConfig struct { type UploaderProvider struct { config *UploaderConfig - sdkClient *veCdn.CDN + logger *slog.Logger + sdkClient *vecdn.CDN } var _ uploader.Uploader = (*UploaderProvider)(nil) @@ -36,19 +38,29 @@ func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { panic("config is nil") } - client := veCdn.NewInstance() + client := vecdn.NewInstance() client.Client.SetAccessKey(config.AccessKeyId) client.Client.SetSecretKey(config.AccessKeySecret) return &UploaderProvider{ config: config, + logger: slog.Default(), sdkClient: client, }, nil } +func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader { + if logger == nil { + u.logger = slog.Default() + } else { + u.logger = logger + } + return u +} + func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 解析证书内容 - certX509, err := certs.ParseCertificateFromPEM(certPem) + certX509, err := certutil.ParseCertificateFromPEM(certPem) if err != nil { return nil, err } @@ -58,13 +70,14 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe listCertInfoPageNum := int64(1) listCertInfoPageSize := int64(100) listCertInfoTotal := 0 - listCertInfoReq := &veCdn.ListCertInfoRequest{ + listCertInfoReq := &vecdn.ListCertInfoRequest{ PageNum: ve.Int64(listCertInfoPageNum), PageSize: ve.Int64(listCertInfoPageSize), Source: "volc_cert_center", } for { listCertInfoResp, err := u.sdkClient.ListCertInfo(listCertInfoReq) + u.logger.Debug("sdk request 'cdn.ListCertInfo'", slog.Any("request", listCertInfoReq), slog.Any("response", listCertInfoResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.ListCertInfo'") } @@ -75,8 +88,9 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe fingerprintSha256 := sha256.Sum256(certX509.Raw) isSameCert := strings.EqualFold(hex.EncodeToString(fingerprintSha1[:]), certDetail.CertFingerprint.Sha1) && strings.EqualFold(hex.EncodeToString(fingerprintSha256[:]), certDetail.CertFingerprint.Sha256) - // 如果已存在相同证书,直接返回已有的证书信息 + // 如果已存在相同证书,直接返回 if isSameCert { + u.logger.Info("ssl certificate already exists") return &uploader.UploadResult{ CertId: certDetail.CertId, CertName: certDetail.Desc, @@ -100,13 +114,14 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe // 上传新证书 // REF: https://www.volcengine.com/docs/6454/1245763 - addCertificateReq := &veCdn.AddCertificateRequest{ + addCertificateReq := &vecdn.AddCertificateRequest{ Certificate: certPem, PrivateKey: privkeyPem, Source: ve.String("volc_cert_center"), Desc: ve.String(certName), } addCertificateResp, err := u.sdkClient.AddCertificate(addCertificateReq) + u.logger.Debug("sdk request 'cdn.AddCertificate'", slog.Any("request", addCertificateResp), slog.Any("response", addCertificateResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.AddCertificate'") } 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 1ff133e5..990d9550 100644 --- a/internal/pkg/core/uploader/providers/volcengine-certcenter/volcengine_certcenter.go +++ b/internal/pkg/core/uploader/providers/volcengine-certcenter/volcengine_certcenter.go @@ -2,13 +2,14 @@ package volcenginecertcenter import ( "context" + "log/slog" xerrors "github.com/pkg/errors" ve "github.com/volcengine/volcengine-go-sdk/volcengine" - veSession "github.com/volcengine/volcengine-go-sdk/volcengine/session" + vesession "github.com/volcengine/volcengine-go-sdk/volcengine/session" "github.com/usual2970/certimate/internal/pkg/core/uploader" - vesdkCc "github.com/usual2970/certimate/internal/pkg/vendors/volcengine-sdk/certcenter" + veccsdk "github.com/usual2970/certimate/internal/pkg/vendors/volcengine-sdk/certcenter" ) type UploaderConfig struct { @@ -22,7 +23,8 @@ type UploaderConfig struct { type UploaderProvider struct { config *UploaderConfig - sdkClient *vesdkCc.CertCenter + logger *slog.Logger + sdkClient *veccsdk.CertCenter } var _ uploader.Uploader = (*UploaderProvider)(nil) @@ -39,21 +41,32 @@ func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { return &UploaderProvider{ config: config, + logger: slog.Default(), sdkClient: client, }, nil } +func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader { + if logger == nil { + u.logger = slog.Default() + } else { + u.logger = logger + } + return u +} + 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{ - CertificateInfo: &vesdkCc.ImportCertificateInputCertificateInfo{ + importCertificateReq := &veccsdk.ImportCertificateInput{ + CertificateInfo: &veccsdk.ImportCertificateInputCertificateInfo{ CertificateChain: ve.String(certPem), PrivateKey: ve.String(privkeyPem), }, Repeatable: ve.Bool(false), } importCertificateResp, err := u.sdkClient.ImportCertificate(importCertificateReq) + u.logger.Debug("sdk request 'certcenter.ImportCertificate'", slog.Any("request", importCertificateReq), slog.Any("response", importCertificateResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'certcenter.ImportCertificate'") } @@ -70,18 +83,18 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe }, nil } -func createSdkClient(accessKeyId, accessKeySecret, region string) (*vesdkCc.CertCenter, error) { +func createSdkClient(accessKeyId, accessKeySecret, region string) (*veccsdk.CertCenter, error) { if region == "" { region = "cn-beijing" // 证书中心默认区域:北京 } config := ve.NewConfig().WithRegion(region).WithAkSk(accessKeyId, accessKeySecret) - session, err := veSession.NewSession(config) + session, err := vesession.NewSession(config) if err != nil { return nil, err } - client := vesdkCc.New(session) + client := veccsdk.New(session) return client, nil } 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 3a7a39eb..46031c61 100644 --- a/internal/pkg/core/uploader/providers/volcengine-live/volcengine_live.go +++ b/internal/pkg/core/uploader/providers/volcengine-live/volcengine_live.go @@ -3,15 +3,16 @@ package volcenginelive import ( "context" "fmt" + "log/slog" "strings" "time" xerrors "github.com/pkg/errors" - veLive "github.com/volcengine/volc-sdk-golang/service/live/v20230101" + velive "github.com/volcengine/volc-sdk-golang/service/live/v20230101" ve "github.com/volcengine/volcengine-go-sdk/volcengine" "github.com/usual2970/certimate/internal/pkg/core/uploader" - "github.com/usual2970/certimate/internal/pkg/utils/certs" + "github.com/usual2970/certimate/internal/pkg/utils/certutil" ) type UploaderConfig struct { @@ -23,7 +24,8 @@ type UploaderConfig struct { type UploaderProvider struct { config *UploaderConfig - sdkClient *veLive.Live + logger *slog.Logger + sdkClient *velive.Live } var _ uploader.Uploader = (*UploaderProvider)(nil) @@ -33,27 +35,38 @@ func NewUploader(config *UploaderConfig) (*UploaderProvider, error) { panic("config is nil") } - client := veLive.NewInstance() + client := velive.NewInstance() client.SetAccessKey(config.AccessKeyId) client.SetSecretKey(config.AccessKeySecret) return &UploaderProvider{ config: config, + logger: slog.Default(), sdkClient: client, }, nil } +func (u *UploaderProvider) WithLogger(logger *slog.Logger) uploader.Uploader { + if logger == nil { + u.logger = slog.Default() + } else { + u.logger = logger + } + return u +} + func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPem string) (res *uploader.UploadResult, err error) { // 解析证书内容 - certX509, err := certs.ParseCertificateFromPEM(certPem) + certX509, err := certutil.ParseCertificateFromPEM(certPem) if err != nil { return nil, err } // 查询证书列表,避免重复上传 // REF: https://www.volcengine.com/docs/6469/1186278#%E6%9F%A5%E8%AF%A2%E8%AF%81%E4%B9%A6%E5%88%97%E8%A1%A8 - listCertReq := &veLive.ListCertV2Body{} + listCertReq := &velive.ListCertV2Body{} listCertResp, err := u.sdkClient.ListCertV2(ctx, listCertReq) + u.logger.Debug("sdk request 'live.ListCertV2'", slog.Any("request", listCertReq), slog.Any("response", listCertResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'live.ListCertV2'") } @@ -61,10 +74,11 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe for _, certDetail := range listCertResp.Result.CertList { // 查询证书详细信息 // REF: https://www.volcengine.com/docs/6469/1186278#%E6%9F%A5%E7%9C%8B%E8%AF%81%E4%B9%A6%E8%AF%A6%E6%83%85 - describeCertDetailSecretReq := &veLive.DescribeCertDetailSecretV2Body{ + describeCertDetailSecretReq := &velive.DescribeCertDetailSecretV2Body{ ChainID: ve.String(certDetail.ChainID), } describeCertDetailSecretResp, err := u.sdkClient.DescribeCertDetailSecretV2(ctx, describeCertDetailSecretReq) + u.logger.Debug("sdk request 'live.DescribeCertDetailSecretV2'", slog.Any("request", describeCertDetailSecretReq), slog.Any("response", describeCertDetailSecretResp)) if err != nil { continue } @@ -74,16 +88,17 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe if certificate == certPem { isSameCert = true } else { - oldCertX509, err := certs.ParseCertificateFromPEM(certificate) + oldCertX509, err := certutil.ParseCertificateFromPEM(certificate) if err != nil { continue } - isSameCert = certs.EqualCertificate(certX509, oldCertX509) + isSameCert = certutil.EqualCertificate(certX509, oldCertX509) } - // 如果已存在相同证书,直接返回已有的证书信息 + // 如果已存在相同证书,直接返回 if isSameCert { + u.logger.Info("ssl certificate already exists") return &uploader.UploadResult{ CertId: certDetail.ChainID, CertName: certDetail.CertName, @@ -98,16 +113,17 @@ func (u *UploaderProvider) Upload(ctx context.Context, certPem string, privkeyPe // 上传新证书 // REF: https://www.volcengine.com/docs/6469/1186278#%E6%B7%BB%E5%8A%A0%E8%AF%81%E4%B9%A6 - createCertReq := &veLive.CreateCertBody{ + createCertReq := &velive.CreateCertBody{ CertName: ve.String(certName), UseWay: "https", ProjectName: ve.String("default"), - Rsa: veLive.CreateCertBodyRsa{ + Rsa: velive.CreateCertBodyRsa{ Prikey: privkeyPem, Pubkey: certPem, }, } createCertResp, err := u.sdkClient.CreateCert(ctx, createCertReq) + u.logger.Debug("sdk request 'live.CreateCert'", slog.Any("request", createCertReq), slog.Any("response", createCertResp)) if err != nil { return nil, xerrors.Wrap(err, "failed to execute sdk request 'live.CreateCert'") } diff --git a/internal/pkg/core/uploader/uploader.go b/internal/pkg/core/uploader/uploader.go index 76748a99..06cecec0 100644 --- a/internal/pkg/core/uploader/uploader.go +++ b/internal/pkg/core/uploader/uploader.go @@ -1,11 +1,16 @@ package uploader -import "context" +import ( + "context" + "log/slog" +) // 表示定义证书上传器的抽象类型接口。 // 云服务商通常会提供 SSL 证书管理服务,可供用户集中管理证书。 // 注意与 `Deployer` 区分,“上传”通常为“部署”的前置操作。 type Uploader interface { + WithLogger(logger *slog.Logger) Uploader + // 上传证书。 // // 入参: diff --git a/internal/pkg/logging/handler.go b/internal/pkg/logging/handler.go new file mode 100644 index 00000000..36174b45 --- /dev/null +++ b/internal/pkg/logging/handler.go @@ -0,0 +1,192 @@ +package logging + +import ( + "context" + "fmt" + "log/slog" + "sync" + + types "github.com/pocketbase/pocketbase/tools/types" +) + +type HookHandlerOptions struct { + Level slog.Leveler + WriteFunc func(ctx context.Context, record *Record) error +} + +var _ slog.Handler = (*HookHandler)(nil) + +type HookHandler struct { + mutex *sync.Mutex + parent *HookHandler + options *HookHandlerOptions + group string + attrs []slog.Attr +} + +func NewHookHandler(opts *HookHandlerOptions) *HookHandler { + if opts == nil { + opts = &HookHandlerOptions{} + } + + h := &HookHandler{ + mutex: &sync.Mutex{}, + options: opts, + } + + if h.options.WriteFunc == nil { + panic("`options.WriteFunc` is nil") + } + + if h.options.Level == nil { + h.options.Level = slog.LevelInfo + } + + return h +} + +func (h *HookHandler) Enabled(ctx context.Context, level slog.Level) bool { + return level >= h.options.Level.Level() +} + +func (h *HookHandler) WithGroup(name string) slog.Handler { + if name == "" { + return h + } + + return &HookHandler{ + parent: h, + mutex: h.mutex, + options: h.options, + group: name, + } +} + +func (h *HookHandler) WithAttrs(attrs []slog.Attr) slog.Handler { + if len(attrs) == 0 { + return h + } + + return &HookHandler{ + parent: h, + mutex: h.mutex, + options: h.options, + attrs: attrs, + } +} + +func (h *HookHandler) Handle(ctx context.Context, r slog.Record) error { + if h.group != "" { + h.mutex.Lock() + attrs := make([]any, 0, len(h.attrs)+r.NumAttrs()) + for _, a := range h.attrs { + attrs = append(attrs, a) + } + h.mutex.Unlock() + + r.Attrs(func(a slog.Attr) bool { + attrs = append(attrs, a) + return true + }) + + r = slog.NewRecord(r.Time, r.Level, r.Message, r.PC) + r.AddAttrs(slog.Group(h.group, attrs...)) + } else if len(h.attrs) > 0 { + r = r.Clone() + + h.mutex.Lock() + r.AddAttrs(h.attrs...) + h.mutex.Unlock() + } + + if h.parent != nil { + return h.parent.Handle(ctx, r) + } + + data := make(map[string]any, r.NumAttrs()) + + r.Attrs(func(a slog.Attr) bool { + if err := h.resolveAttr(data, a); err != nil { + return false + } + return true + }) + + log := &Record{ + Time: r.Time, + Message: r.Message, + Data: types.JSONMap[any](data), + } + switch r.Level { + case slog.LevelDebug: + log.Level = LevelDebug + case slog.LevelInfo: + log.Level = LevelInfo + case slog.LevelWarn: + log.Level = LevelWarn + case slog.LevelError: + log.Level = LevelError + default: + log.Level = Level(fmt.Sprintf("LV(%d)", r.Level)) + } + + if err := h.writeRecord(ctx, log); err != nil { + return err + } + + return nil +} + +func (h *HookHandler) SetLevel(level slog.Level) { + h.mutex.Lock() + h.options.Level = level + h.mutex.Unlock() +} + +func (h *HookHandler) writeRecord(ctx context.Context, r *Record) error { + if h.parent != nil { + return h.parent.writeRecord(ctx, r) + } + + return h.options.WriteFunc(ctx, r) +} + +func (h *HookHandler) resolveAttr(data map[string]any, attr slog.Attr) error { + attr.Value = attr.Value.Resolve() + + if attr.Equal(slog.Attr{}) { + return nil + } + + switch attr.Value.Kind() { + case slog.KindGroup: + { + attrs := attr.Value.Group() + if len(attrs) == 0 { + return nil + } + + groupData := make(map[string]any, len(attrs)) + + for _, subAttr := range attrs { + h.resolveAttr(groupData, subAttr) + } + + if len(groupData) > 0 { + data[attr.Key] = groupData + } + } + + default: + { + switch v := attr.Value.Any().(type) { + case error: + data[attr.Key] = v.Error() + default: + data[attr.Key] = v + } + } + } + + return nil +} diff --git a/internal/pkg/logging/level.go b/internal/pkg/logging/level.go new file mode 100644 index 00000000..2af1c2f4 --- /dev/null +++ b/internal/pkg/logging/level.go @@ -0,0 +1,31 @@ +package logging + +import "log/slog" + +type Level string + +const ( + LevelDebug Level = "DEBUG" + LevelInfo Level = "INFO" + LevelWarn Level = "WARN" + LevelError Level = "ERROR" +) + +func (l Level) String() string { + return string(l) +} + +func (l Level) Level() slog.Level { + switch l { + case LevelDebug: + return slog.LevelDebug + case LevelInfo: + return slog.LevelInfo + case LevelWarn: + return slog.LevelWarn + case LevelError: + return slog.LevelError + default: + return slog.Level(-1) + } +} diff --git a/internal/pkg/logging/record.go b/internal/pkg/logging/record.go new file mode 100644 index 00000000..9980489b --- /dev/null +++ b/internal/pkg/logging/record.go @@ -0,0 +1,14 @@ +package logging + +import ( + "time" + + types "github.com/pocketbase/pocketbase/tools/types" +) + +type Record struct { + Time time.Time + Level Level + Message string + Data types.JSONMap[any] +} diff --git a/internal/pkg/utils/certs/common.go b/internal/pkg/utils/certutil/common.go similarity index 97% rename from internal/pkg/utils/certs/common.go rename to internal/pkg/utils/certutil/common.go index 03fbeaeb..409233b6 100644 --- a/internal/pkg/utils/certs/common.go +++ b/internal/pkg/utils/certutil/common.go @@ -1,4 +1,4 @@ -package certs +package certutil import ( "crypto/x509" diff --git a/internal/pkg/utils/certs/converter.go b/internal/pkg/utils/certutil/converter.go similarity index 98% rename from internal/pkg/utils/certs/converter.go rename to internal/pkg/utils/certutil/converter.go index 74a9a5ab..ccbe6360 100644 --- a/internal/pkg/utils/certs/converter.go +++ b/internal/pkg/utils/certutil/converter.go @@ -1,4 +1,4 @@ -package certs +package certutil import ( "crypto/ecdsa" diff --git a/internal/pkg/utils/certs/extractor.go b/internal/pkg/utils/certutil/extractor.go similarity index 98% rename from internal/pkg/utils/certs/extractor.go rename to internal/pkg/utils/certutil/extractor.go index bf07b4f3..d4e7ee6e 100644 --- a/internal/pkg/utils/certs/extractor.go +++ b/internal/pkg/utils/certutil/extractor.go @@ -1,4 +1,4 @@ -package certs +package certutil import ( "encoding/pem" diff --git a/internal/pkg/utils/certs/parser.go b/internal/pkg/utils/certutil/parser.go similarity index 99% rename from internal/pkg/utils/certs/parser.go rename to internal/pkg/utils/certutil/parser.go index af62b03a..e93ce583 100644 --- a/internal/pkg/utils/certs/parser.go +++ b/internal/pkg/utils/certutil/parser.go @@ -1,4 +1,4 @@ -package certs +package certutil import ( "crypto" diff --git a/internal/pkg/utils/certs/transformer.go b/internal/pkg/utils/certutil/transformer.go similarity index 99% rename from internal/pkg/utils/certs/transformer.go rename to internal/pkg/utils/certutil/transformer.go index 60105d3e..f48641ae 100644 --- a/internal/pkg/utils/certs/transformer.go +++ b/internal/pkg/utils/certutil/transformer.go @@ -1,4 +1,4 @@ -package certs +package certutil import ( "bytes" diff --git a/internal/pkg/utils/files/files.go b/internal/pkg/utils/fileutil/io.go similarity index 98% rename from internal/pkg/utils/files/files.go rename to internal/pkg/utils/fileutil/io.go index 654bf164..336f524d 100644 --- a/internal/pkg/utils/files/files.go +++ b/internal/pkg/utils/fileutil/io.go @@ -1,4 +1,4 @@ -package files +package fileutil import ( "os" diff --git a/internal/pkg/utils/maps/maps.go b/internal/pkg/utils/maputil/getter.go similarity index 70% rename from internal/pkg/utils/maps/maps.go rename to internal/pkg/utils/maputil/getter.go index 4a4417d0..36561381 100644 --- a/internal/pkg/utils/maps/maps.go +++ b/internal/pkg/utils/maputil/getter.go @@ -1,9 +1,7 @@ -package maps +package maputil import ( "strconv" - - mapstructure "github.com/go-viper/mapstructure/v2" ) // 以字符串形式从字典中获取指定键的值。 @@ -14,8 +12,8 @@ import ( // // 出参: // - 字典中键对应的值。如果指定键不存在或者值的类型不是字符串,则返回空字符串。 -func GetValueAsString(dict map[string]any, key string) string { - return GetValueOrDefaultAsString(dict, key, "") +func GetString(dict map[string]any, key string) string { + return GetOrDefaultString(dict, key, "") } // 以字符串形式从字典中获取指定键的值。 @@ -27,7 +25,7 @@ func GetValueAsString(dict map[string]any, key string) string { // // 出参: // - 字典中键对应的值。如果指定键不存在、值的类型不是字符串或者值为零值,则返回默认值。 -func GetValueOrDefaultAsString(dict map[string]any, key string, defaultValue string) string { +func GetOrDefaultString(dict map[string]any, key string, defaultValue string) string { if dict == nil { return defaultValue } @@ -51,8 +49,8 @@ func GetValueOrDefaultAsString(dict map[string]any, key string, defaultValue str // // 出参: // - 字典中键对应的值。如果指定键不存在或者值的类型不是 32 位整数,则返回 0。 -func GetValueAsInt32(dict map[string]any, key string) int32 { - return GetValueOrDefaultAsInt32(dict, key, 0) +func GetInt32(dict map[string]any, key string) int32 { + return GetOrDefaultInt32(dict, key, 0) } // 以 32 位整数形式从字典中获取指定键的值。 @@ -64,7 +62,7 @@ func GetValueAsInt32(dict map[string]any, key string) int32 { // // 出参: // - 字典中键对应的值。如果指定键不存在、值的类型不是 32 位整数或者值为零值,则返回默认值。 -func GetValueOrDefaultAsInt32(dict map[string]any, key string, defaultValue int32) int32 { +func GetOrDefaultInt32(dict map[string]any, key string, defaultValue int32) int32 { if dict == nil { return defaultValue } @@ -97,8 +95,8 @@ func GetValueOrDefaultAsInt32(dict map[string]any, key string, defaultValue int3 // // 出参: // - 字典中键对应的值。如果指定键不存在或者值的类型不是 64 位整数,则返回 0。 -func GetValueAsInt64(dict map[string]any, key string) int64 { - return GetValueOrDefaultAsInt64(dict, key, 0) +func GetInt64(dict map[string]any, key string) int64 { + return GetOrDefaultInt64(dict, key, 0) } // 以 64 位整数形式从字典中获取指定键的值。 @@ -110,7 +108,7 @@ func GetValueAsInt64(dict map[string]any, key string) int64 { // // 出参: // - 字典中键对应的值。如果指定键不存在、值的类型不是 64 位整数或者值为零值,则返回默认值。 -func GetValueOrDefaultAsInt64(dict map[string]any, key string, defaultValue int64) int64 { +func GetOrDefaultInt64(dict map[string]any, key string, defaultValue int64) int64 { if dict == nil { return defaultValue } @@ -149,8 +147,8 @@ func GetValueOrDefaultAsInt64(dict map[string]any, key string, defaultValue int6 // // 出参: // - 字典中键对应的值。如果指定键不存在或者值的类型不是布尔,则返回 false。 -func GetValueAsBool(dict map[string]any, key string) bool { - return GetValueOrDefaultAsBool(dict, key, false) +func GetBool(dict map[string]any, key string) bool { + return GetOrDefaultBool(dict, key, false) } // 以布尔形式从字典中获取指定键的值。 @@ -162,7 +160,7 @@ func GetValueAsBool(dict map[string]any, key string) bool { // // 出参: // - 字典中键对应的值。如果指定键不存在或者值的类型不是布尔,则返回默认值。 -func GetValueOrDefaultAsBool(dict map[string]any, key string, defaultValue bool) bool { +func GetOrDefaultBool(dict map[string]any, key string, defaultValue bool) bool { if dict == nil { return defaultValue } @@ -182,28 +180,3 @@ func GetValueOrDefaultAsBool(dict map[string]any, key string, defaultValue bool) return defaultValue } - -// 将字典填充到指定类型的结构体。 -// 与 [json.Unmarshal] 类似,但传入的是一个 [map[string]interface{}] 对象而非 JSON 格式的字符串。 -// -// 入参: -// - dict: 字典。 -// - output: 结构体指针。 -// -// 出参: -// - 错误信息。如果填充失败,则返回错误信息。 -func Populate(dict map[string]any, output any) error { - config := &mapstructure.DecoderConfig{ - Metadata: nil, - Result: output, - WeaklyTypedInput: true, - TagName: "json", - } - - decoder, err := mapstructure.NewDecoder(config) - if err != nil { - return err - } - - return decoder.Decode(dict) -} diff --git a/internal/pkg/utils/maputil/marshal.go b/internal/pkg/utils/maputil/marshal.go new file mode 100644 index 00000000..64bd97e6 --- /dev/null +++ b/internal/pkg/utils/maputil/marshal.go @@ -0,0 +1,30 @@ +package maputil + +import ( + mapstructure "github.com/go-viper/mapstructure/v2" +) + +// 将字典填充到指定类型的结构体。 +// 与 [json.Unmarshal] 类似,但传入的是一个 [map[string]any] 对象而非 JSON 格式的字符串。 +// +// 入参: +// - dict: 字典。 +// - output: 结构体指针。 +// +// 出参: +// - 错误信息。如果填充失败,则返回错误信息。 +func Populate(dict map[string]any, output any) error { + config := &mapstructure.DecoderConfig{ + Metadata: nil, + Result: output, + WeaklyTypedInput: true, + TagName: "json", + } + + decoder, err := mapstructure.NewDecoder(config) + if err != nil { + return err + } + + return decoder.Decode(dict) +} diff --git a/internal/pkg/utils/slices/slices.go b/internal/pkg/utils/sliceutil/slices.go similarity index 98% rename from internal/pkg/utils/slices/slices.go rename to internal/pkg/utils/sliceutil/slices.go index e4e4d746..ba63b82a 100644 --- a/internal/pkg/utils/slices/slices.go +++ b/internal/pkg/utils/sliceutil/slices.go @@ -1,4 +1,4 @@ -package slices +package sliceutil // 创建给定切片一部分的浅拷贝,其包含通过所提供函数实现的测试的所有元素。 // diff --git a/internal/pkg/utils/types/types.go b/internal/pkg/utils/typeutil/types.go similarity index 97% rename from internal/pkg/utils/types/types.go rename to internal/pkg/utils/typeutil/types.go index f23d8e33..4e5d3711 100644 --- a/internal/pkg/utils/types/types.go +++ b/internal/pkg/utils/typeutil/types.go @@ -1,4 +1,4 @@ -package types +package typeutil import "reflect" diff --git a/internal/pkg/vendors/baishan-sdk/models.go b/internal/pkg/vendors/baishan-sdk/models.go index 78685571..e1c79c0e 100644 --- a/internal/pkg/vendors/baishan-sdk/models.go +++ b/internal/pkg/vendors/baishan-sdk/models.go @@ -31,7 +31,7 @@ type CreateCertificateResponse struct { type GetDomainConfigRequest struct { Domains string `json:"domains"` - Config string `json:"config"` + Config []string `json:"config"` } type GetDomainConfigResponse struct { diff --git a/internal/pkg/vendors/cdnfly-sdk/models.go b/internal/pkg/vendors/cdnfly-sdk/models.go index 873b80b0..adaf3188 100644 --- a/internal/pkg/vendors/cdnfly-sdk/models.go +++ b/internal/pkg/vendors/cdnfly-sdk/models.go @@ -1,17 +1,19 @@ package cdnflysdk +import "encoding/json" + type BaseResponse interface { GetCode() string GetMessage() string } type baseResponse struct { - Code string `json:"code"` - Message string `json:"msg"` + Code json.Number `json:"code"` + Message string `json:"msg"` } func (r *baseResponse) GetCode() string { - return r.Code + return r.Code.String() } func (r *baseResponse) GetMessage() string { @@ -25,7 +27,7 @@ type GetSiteRequest struct { type GetSiteResponse struct { baseResponse Data *struct { - Id string `json:"id"` + Id int64 `json:"id"` Name string `json:"name"` Domain string `json:"domain"` HttpsListen string `json:"https_listen"` diff --git a/internal/pkg/vendors/upyun-sdk/console/api.go b/internal/pkg/vendors/upyun-sdk/console/api.go new file mode 100644 index 00000000..afcb0b5b --- /dev/null +++ b/internal/pkg/vendors/upyun-sdk/console/api.go @@ -0,0 +1,104 @@ +package console + +import ( + "encoding/json" + "errors" + "fmt" + "net/http" +) + +func (c *Client) getCookie() error { + req := &signinRequest{Username: c.username, Password: c.password} + res, err := c.sendRequest(http.MethodPost, "/accounts/signin/", req) + if err != nil { + return err + } + + resp := &signinResponse{} + if err := json.Unmarshal(res.Body(), &resp); err != nil { + return fmt.Errorf("upyun api error: failed to parse response: %w", err) + } else if !resp.Data.Result { + return errors.New("upyun console signin failed") + } + + c.loginCookie = res.Header().Get("Set-Cookie") + + return nil +} + +func (c *Client) UploadHttpsCertificate(req *UploadHttpsCertificateRequest) (*UploadHttpsCertificateResponse, error) { + if c.loginCookie == "" { + if err := c.getCookie(); err != nil { + return nil, err + } + } + + resp := UploadHttpsCertificateResponse{} + err := c.sendRequestWithResult(http.MethodPost, "/api/https/certificate/", req, &resp) + if err != nil { + return nil, err + } + return &resp, nil +} + +func (c *Client) GetHttpsCertificateManager(certificateId string) (*GetHttpsCertificateManagerResponse, error) { + if c.loginCookie == "" { + if err := c.getCookie(); err != nil { + return nil, err + } + } + + req := GetHttpsCertificateManagerRequest{CertificateId: certificateId} + resp := GetHttpsCertificateManagerResponse{} + err := c.sendRequestWithResult(http.MethodGet, "/api/https/certificate/manager/", &req, &resp) + if err != nil { + return nil, err + } + return &resp, nil +} + +func (c *Client) UpdateHttpsCertificateManager(req *UpdateHttpsCertificateManagerRequest) (*UpdateHttpsCertificateManagerResponse, error) { + if c.loginCookie == "" { + if err := c.getCookie(); err != nil { + return nil, err + } + } + + resp := UpdateHttpsCertificateManagerResponse{} + err := c.sendRequestWithResult(http.MethodPost, "/api/https/certificate/manager", req, &resp) + if err != nil { + return nil, err + } + return &resp, nil +} + +func (c *Client) GetHttpsServiceManager(domain string) (*GetHttpsServiceManagerResponse, error) { + if c.loginCookie == "" { + if err := c.getCookie(); err != nil { + return nil, err + } + } + + req := GetHttpsServiceManagerRequest{Domain: domain} + resp := GetHttpsServiceManagerResponse{} + err := c.sendRequestWithResult(http.MethodGet, "/api/https/services/manager", &req, &resp) + if err != nil { + return nil, err + } + return &resp, nil +} + +func (c *Client) MigrateHttpsDomain(req *MigrateHttpsDomainRequest) (*MigrateHttpsDomainResponse, error) { + if c.loginCookie == "" { + if err := c.getCookie(); err != nil { + return nil, err + } + } + + resp := MigrateHttpsDomainResponse{} + err := c.sendRequestWithResult(http.MethodPost, "/api/https/migrate/domain", req, &resp) + if err != nil { + return nil, err + } + return &resp, nil +} diff --git a/internal/pkg/vendors/upyun-sdk/console/client.go b/internal/pkg/vendors/upyun-sdk/console/client.go new file mode 100644 index 00000000..74758b82 --- /dev/null +++ b/internal/pkg/vendors/upyun-sdk/console/client.go @@ -0,0 +1,94 @@ +package console + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + "time" + + "github.com/go-resty/resty/v2" +) + +type Client struct { + username string + password string + loginCookie string + + client *resty.Client +} + +func NewClient(username, password string) *Client { + client := resty.New() + + return &Client{ + username: username, + password: password, + 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.username, c.password) + req.Method = method + req.URL = "https://console.upyun.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). + SetHeader("Cookie", c.loginCookie) + } else { + req = req. + SetHeader("Content-Type", "application/json"). + SetHeader("Cookie", c.loginCookie). + SetBody(params) + } + + req = req.SetDebug(true) + resp, err := req.Send() + if err != nil { + return nil, fmt.Errorf("upyun api error: failed to send request: %w", err) + } else if resp.IsError() { + return nil, fmt.Errorf("upyun 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 interface{}) 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("upyun api error: failed to parse response: %w", err) + } + + tresp := &baseResponse{} + if err := json.Unmarshal(resp.Body(), &tresp); err != nil { + return fmt.Errorf("upyun api error: failed to parse response: %w", err) + } else if tdata := tresp.GetData(); tdata == nil { + return fmt.Errorf("upyun api error: empty data") + } else if errcode := tdata.GetErrorCode(); errcode > 0 { + return fmt.Errorf("upyun api error: %d - %s", errcode, tdata.GetErrorMessage()) + } + + return nil +} diff --git a/internal/pkg/vendors/upyun-sdk/console/models.go b/internal/pkg/vendors/upyun-sdk/console/models.go new file mode 100644 index 00000000..982993fe --- /dev/null +++ b/internal/pkg/vendors/upyun-sdk/console/models.go @@ -0,0 +1,141 @@ +package console + +import ( + "encoding/json" +) + +type baseResponse struct { + Data *baseResponseData `json:"data,omitempty"` +} + +func (r *baseResponse) GetData() *baseResponseData { + return r.Data +} + +type baseResponseData struct { + ErrorCode json.Number `json:"error_code"` + ErrorMessage string `json:"message"` +} + +func (r *baseResponseData) GetErrorCode() int { + if r.ErrorCode.String() == "" { + return 0 + } + + errcode, err := r.ErrorCode.Int64() + if err != nil { + return -1 + } + + return int(errcode) +} + +func (r *baseResponseData) GetErrorMessage() string { + return r.ErrorMessage +} + +type signinRequest struct { + Username string `json:"username"` + Password string `json:"password"` +} + +type signinResponse struct { + baseResponse + Data struct { + baseResponseData + Result bool `json:"result"` + } `json:"data"` +} + +type UploadHttpsCertificateRequest struct { + Certificate string `json:"certificate"` + PrivateKey string `json:"private_key"` +} + +type UploadHttpsCertificateResponse struct { + baseResponse + Data *struct { + baseResponseData + Status int `json:"status"` + Result struct { + CertificateId string `json:"certificate_id"` + CommonName string `json:"commonName"` + Serial string `json:"serial"` + } `json:"result"` + } `json:"data"` +} + +type GetHttpsCertificateManagerRequest struct { + CertificateId string `json:"certificate_id"` +} + +type GetHttpsCertificateManagerResponse struct { + baseResponse + Data *struct { + baseResponseData + AuthenticateNum int32 `json:"authenticate_num"` + AuthenticateDomains []string `json:"authenticate_domain"` + Domains []HttpsCertificateManagerDomain `json:"domains"` + } `json:"data"` +} + +type HttpsCertificateManagerDomain struct { + Name string `json:"name"` + Type string `json:"type"` + BucketId int64 `json:"bucket_id"` + BucketName string `json:"bucket_name"` +} + +type UpdateHttpsCertificateManagerRequest struct { + CertificateId string `json:"certificate_id"` + Domain string `json:"domain"` + Https bool `json:"https"` + ForceHttps bool `json:"force_https"` +} + +type UpdateHttpsCertificateManagerResponse struct { + baseResponse + Data *struct { + baseResponseData + Status bool `json:"status"` + } `json:"data"` +} + +type GetHttpsServiceManagerRequest struct { + Domain string `json:"domain"` +} + +type GetHttpsServiceManagerResponse struct { + baseResponse + Data *struct { + baseResponseData + Status int `json:"status"` + Domains []HttpsServiceManagerDomain `json:"result"` + } `json:"data"` +} + +type HttpsServiceManagerDomain struct { + CertificateId string `json:"certificate_id"` + CommonName string `json:"commonName"` + Https bool `json:"https"` + ForceHttps bool `json:"force_https"` + PaymentType string `json:"payment_type"` + DomainType string `json:"domain_type"` + Validity struct { + Start int64 `json:"start"` + End int64 `json:"end"` + } `json:"validity"` +} + +type MigrateHttpsDomainRequest struct { + CertificateId string `json:"crt_id"` + Domain string `json:"domain_name"` +} + +type MigrateHttpsDomainResponse struct { + baseResponse + Data *struct { + baseResponseData + Status bool `json:"status"` + } `json:"data"` +} diff --git a/internal/repository/certificate.go b/internal/repository/certificate.go index 0695ca47..13d2c094 100644 --- a/internal/repository/certificate.go +++ b/internal/repository/certificate.go @@ -67,11 +67,9 @@ func (r *CertificateRepository) GetByWorkflowNodeId(ctx context.Context, workflo dbx.Params{"workflowNodeId": workflowNodeId}, ) if err != nil { - if errors.Is(err, sql.ErrNoRows) { - return nil, domain.ErrRecordNotFound - } return nil, err } + if len(records) == 0 { return nil, domain.ErrRecordNotFound } @@ -125,6 +123,29 @@ func (r *CertificateRepository) Save(ctx context.Context, certificate *domain.Ce return certificate, nil } +func (r *CertificateRepository) DeleteWhere(ctx context.Context, exprs ...dbx.Expression) (int, error) { + records, err := app.GetApp().FindAllRecords(domain.CollectionNameCertificate, exprs...) + if err != nil { + return 0, nil + } + + var ret int + var errs []error + for _, record := range records { + if err := app.GetApp().Delete(record); err != nil { + errs = append(errs, err) + } else { + ret++ + } + } + + if len(errs) > 0 { + return ret, errors.Join(errs...) + } + + return ret, nil +} + func (r *CertificateRepository) castRecordToModel(record *core.Record) (*domain.Certificate, error) { if record == nil { return nil, fmt.Errorf("record is nil") diff --git a/internal/repository/workflow_log.go b/internal/repository/workflow_log.go new file mode 100644 index 00000000..0b801231 --- /dev/null +++ b/internal/repository/workflow_log.go @@ -0,0 +1,112 @@ +package repository + +import ( + "context" + "database/sql" + "errors" + "fmt" + + "github.com/pocketbase/dbx" + "github.com/pocketbase/pocketbase/core" + "github.com/usual2970/certimate/internal/app" + "github.com/usual2970/certimate/internal/domain" +) + +type WorkflowLogRepository struct{} + +func NewWorkflowLogRepository() *WorkflowLogRepository { + return &WorkflowLogRepository{} +} + +func (r *WorkflowLogRepository) ListByWorkflowRunId(ctx context.Context, workflowRunId string) ([]*domain.WorkflowLog, error) { + records, err := app.GetApp().FindRecordsByFilter( + domain.CollectionNameWorkflowLog, + "runId={:runId}", + "timestamp", + 0, 0, + dbx.Params{"runId": workflowRunId}, + ) + if err != nil { + return nil, err + } + + workflowLogs := make([]*domain.WorkflowLog, 0) + for _, record := range records { + workflowLog, err := r.castRecordToModel(record) + if err != nil { + return nil, err + } + + workflowLogs = append(workflowLogs, workflowLog) + } + + return workflowLogs, nil +} + +func (r *WorkflowLogRepository) Save(ctx context.Context, workflowLog *domain.WorkflowLog) (*domain.WorkflowLog, error) { + collection, err := app.GetApp().FindCollectionByNameOrId(domain.CollectionNameWorkflowLog) + if err != nil { + return workflowLog, err + } + + var record *core.Record + if workflowLog.Id == "" { + record = core.NewRecord(collection) + } else { + record, err = app.GetApp().FindRecordById(collection, workflowLog.Id) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return workflowLog, err + } + record = core.NewRecord(collection) + } + } + + record.Set("workflowId", workflowLog.WorkflowId) + record.Set("runId", workflowLog.RunId) + record.Set("nodeId", workflowLog.NodeId) + record.Set("nodeName", workflowLog.NodeName) + record.Set("timestamp", workflowLog.Timestamp) + record.Set("level", workflowLog.Level) + record.Set("message", workflowLog.Message) + record.Set("data", workflowLog.Data) + record.Set("created", workflowLog.CreatedAt) + err = app.GetApp().Save(record) + if err != nil { + return workflowLog, err + } + + workflowLog.Id = record.Id + workflowLog.CreatedAt = record.GetDateTime("created").Time() + workflowLog.UpdatedAt = record.GetDateTime("updated").Time() + + return workflowLog, nil +} + +func (r *WorkflowLogRepository) castRecordToModel(record *core.Record) (*domain.WorkflowLog, error) { + if record == nil { + return nil, fmt.Errorf("record is nil") + } + + logdata := make(map[string]any) + if err := record.UnmarshalJSONField("data", &logdata); err != nil { + return nil, err + } + + workflowLog := &domain.WorkflowLog{ + Meta: domain.Meta{ + Id: record.Id, + CreatedAt: record.GetDateTime("created").Time(), + UpdatedAt: record.GetDateTime("updated").Time(), + }, + WorkflowId: record.GetString("workflowId"), + RunId: record.GetString("runId"), + NodeId: record.GetString("nodeId"), + NodeName: record.GetString("nodeName"), + Timestamp: int64(record.GetInt("timestamp")), + Level: record.GetString("level"), + Message: record.GetString("message"), + Data: logdata, + } + return workflowLog, nil +} diff --git a/internal/repository/workflow_run.go b/internal/repository/workflow_run.go index b1a5234b..19a06747 100644 --- a/internal/repository/workflow_run.go +++ b/internal/repository/workflow_run.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" + "github.com/pocketbase/dbx" "github.com/pocketbase/pocketbase/core" "github.com/usual2970/certimate/internal/app" "github.com/usual2970/certimate/internal/domain" @@ -54,7 +55,7 @@ func (r *WorkflowRunRepository) Save(ctx context.Context, workflowRun *domain.Wo record.Set("status", string(workflowRun.Status)) record.Set("startedAt", workflowRun.StartedAt) record.Set("endedAt", workflowRun.EndedAt) - record.Set("logs", workflowRun.Logs) + record.Set("detail", workflowRun.Detail) record.Set("error", workflowRun.Error) err = txApp.Save(record) if err != nil { @@ -96,13 +97,36 @@ func (r *WorkflowRunRepository) Save(ctx context.Context, workflowRun *domain.Wo return workflowRun, nil } +func (r *WorkflowRunRepository) DeleteWhere(ctx context.Context, exprs ...dbx.Expression) (int, error) { + records, err := app.GetApp().FindAllRecords(domain.CollectionNameWorkflowRun, exprs...) + if err != nil { + return 0, nil + } + + var ret int + var errs []error + for _, record := range records { + if err := app.GetApp().Delete(record); err != nil { + errs = append(errs, err) + } else { + ret++ + } + } + + if len(errs) > 0 { + return ret, errors.Join(errs...) + } + + return ret, nil +} + func (r *WorkflowRunRepository) castRecordToModel(record *core.Record) (*domain.WorkflowRun, error) { if record == nil { return nil, fmt.Errorf("record is nil") } - logs := make([]domain.WorkflowRunLog, 0) - if err := record.UnmarshalJSONField("logs", &logs); err != nil { + detail := &domain.WorkflowNode{} + if err := record.UnmarshalJSONField("detail", &detail); err != nil { return nil, err } @@ -117,7 +141,7 @@ func (r *WorkflowRunRepository) castRecordToModel(record *core.Record) (*domain. Trigger: domain.WorkflowTriggerType(record.GetString("trigger")), StartedAt: record.GetDateTime("startedAt").Time(), EndedAt: record.GetDateTime("endedAt").Time(), - Logs: logs, + Detail: detail, Error: record.GetString("error"), } return workflowRun, nil diff --git a/internal/rest/routes/routes.go b/internal/rest/routes/routes.go index 87fcb297..6172bc12 100644 --- a/internal/rest/routes/routes.go +++ b/internal/rest/routes/routes.go @@ -23,17 +23,15 @@ var ( ) func Register(router *router.Router[*core.RequestEvent]) { - certificateRepo := repository.NewCertificateRepository() - certificateSvc = certificate.NewCertificateService(certificateRepo) - workflowRepo := repository.NewWorkflowRepository() workflowRunRepo := repository.NewWorkflowRunRepository() - workflowSvc = workflow.NewWorkflowService(workflowRepo, workflowRunRepo) - - statisticsRepo := repository.NewStatisticsRepository() - statisticsSvc = statistics.NewStatisticsService(statisticsRepo) - + certificateRepo := repository.NewCertificateRepository() settingsRepo := repository.NewSettingsRepository() + statisticsRepo := repository.NewStatisticsRepository() + + certificateSvc = certificate.NewCertificateService(certificateRepo, settingsRepo) + workflowSvc = workflow.NewWorkflowService(workflowRepo, workflowRunRepo, settingsRepo) + statisticsSvc = statistics.NewStatisticsService(statisticsRepo) notifySvc = notify.NewNotifyService(settingsRepo) group := router.Group("/api") diff --git a/internal/scheduler/scheduler.go b/internal/scheduler/scheduler.go index 91dbf115..ba4ee9c3 100644 --- a/internal/scheduler/scheduler.go +++ b/internal/scheduler/scheduler.go @@ -10,10 +10,11 @@ import ( func Register() { workflowRepo := repository.NewWorkflowRepository() workflowRunRepo := repository.NewWorkflowRunRepository() - workflowSvc := workflow.NewWorkflowService(workflowRepo, workflowRunRepo) - certificateRepo := repository.NewCertificateRepository() - certificateSvc := certificate.NewCertificateService(certificateRepo) + settingsRepo := repository.NewSettingsRepository() + + workflowSvc := workflow.NewWorkflowService(workflowRepo, workflowRunRepo, settingsRepo) + certificateSvc := certificate.NewCertificateService(certificateRepo, settingsRepo) if err := InitWorkflowScheduler(workflowSvc); err != nil { app.GetLogger().Error("failed to init workflow scheduler", "err", err) diff --git a/internal/workflow/dispatcher/dispatcher.go b/internal/workflow/dispatcher/dispatcher.go index 53081b6b..d453b72f 100644 --- a/internal/workflow/dispatcher/dispatcher.go +++ b/internal/workflow/dispatcher/dispatcher.go @@ -11,7 +11,7 @@ import ( "github.com/usual2970/certimate/internal/app" "github.com/usual2970/certimate/internal/domain" - "github.com/usual2970/certimate/internal/pkg/utils/slices" + "github.com/usual2970/certimate/internal/pkg/utils/sliceutil" ) var maxWorkers = 16 @@ -51,9 +51,10 @@ type WorkflowDispatcher struct { workflowRepo workflowRepository workflowRunRepo workflowRunRepository + workflowLogRepo workflowLogRepository } -func newWorkflowDispatcher(workflowRepo workflowRepository, workflowRunRepo workflowRunRepository) *WorkflowDispatcher { +func newWorkflowDispatcher(workflowRepo workflowRepository, workflowRunRepo workflowRunRepository, workflowLogRepo workflowLogRepository) *WorkflowDispatcher { dispatcher := &WorkflowDispatcher{ semaphore: make(chan struct{}, maxWorkers), @@ -69,6 +70,7 @@ func newWorkflowDispatcher(workflowRepo workflowRepository, workflowRunRepo work workflowRepo: workflowRepo, workflowRunRepo: workflowRunRepo, + workflowLogRepo: workflowLogRepo, } go func() { @@ -86,139 +88,139 @@ func newWorkflowDispatcher(workflowRepo workflowRepository, workflowRunRepo work return dispatcher } -func (w *WorkflowDispatcher) Dispatch(data *WorkflowWorkerData) { +func (d *WorkflowDispatcher) Dispatch(data *WorkflowWorkerData) { if data == nil { panic("worker data is nil") } - w.enqueueWorker(data) + d.enqueueWorker(data) select { - case w.chWork <- data: + case d.chWork <- data: default: } } -func (w *WorkflowDispatcher) Cancel(runId string) { +func (d *WorkflowDispatcher) Cancel(runId string) { hasWorker := false // 取消正在执行的 WorkflowRun - w.workerMutex.Lock() - if workflowId, ok := w.workerIdMap[runId]; ok { - if worker, ok := w.workers[workflowId]; ok { + d.workerMutex.Lock() + if workflowId, ok := d.workerIdMap[runId]; ok { + if worker, ok := d.workers[workflowId]; ok { hasWorker = true worker.Cancel() - delete(w.workers, workflowId) - delete(w.workerIdMap, runId) + delete(d.workers, workflowId) + delete(d.workerIdMap, runId) } } - w.workerMutex.Unlock() + d.workerMutex.Unlock() // 移除排队中的 WorkflowRun - w.queueMutex.Lock() - w.queue = slices.Filter(w.queue, func(d *WorkflowWorkerData) bool { + d.queueMutex.Lock() + d.queue = sliceutil.Filter(d.queue, func(d *WorkflowWorkerData) bool { return d.RunId != runId }) - w.queueMutex.Unlock() + d.queueMutex.Unlock() // 已挂起,查询 WorkflowRun 并更新其状态为 Canceled if !hasWorker { - if run, err := w.workflowRunRepo.GetById(context.Background(), runId); err == nil { + if run, err := d.workflowRunRepo.GetById(context.Background(), runId); err == nil { if run.Status == domain.WorkflowRunStatusTypePending || run.Status == domain.WorkflowRunStatusTypeRunning { run.Status = domain.WorkflowRunStatusTypeCanceled - w.workflowRunRepo.Save(context.Background(), run) + d.workflowRunRepo.Save(context.Background(), run) } } } } -func (w *WorkflowDispatcher) Shutdown() { +func (d *WorkflowDispatcher) Shutdown() { // 清空排队中的 WorkflowRun - w.queueMutex.Lock() - w.queue = make([]*WorkflowWorkerData, 0) - w.queueMutex.Unlock() + d.queueMutex.Lock() + d.queue = make([]*WorkflowWorkerData, 0) + d.queueMutex.Unlock() // 等待所有正在执行的 WorkflowRun 完成 - w.workerMutex.Lock() - for _, worker := range w.workers { + d.workerMutex.Lock() + for _, worker := range d.workers { worker.Cancel() - delete(w.workers, worker.Data.WorkflowId) - delete(w.workerIdMap, worker.Data.RunId) + delete(d.workers, worker.Data.WorkflowId) + delete(d.workerIdMap, worker.Data.RunId) } - w.workerMutex.Unlock() - w.wg.Wait() + d.workerMutex.Unlock() + d.wg.Wait() } -func (w *WorkflowDispatcher) enqueueWorker(data *WorkflowWorkerData) { - w.queueMutex.Lock() - defer w.queueMutex.Unlock() - w.queue = append(w.queue, data) +func (d *WorkflowDispatcher) enqueueWorker(data *WorkflowWorkerData) { + d.queueMutex.Lock() + defer d.queueMutex.Unlock() + d.queue = append(d.queue, data) } -func (w *WorkflowDispatcher) dequeueWorker() { +func (d *WorkflowDispatcher) dequeueWorker() { for { select { - case w.semaphore <- struct{}{}: + case d.semaphore <- struct{}{}: default: // 达到最大并发数 return } - w.queueMutex.Lock() - if len(w.queue) == 0 { - w.queueMutex.Unlock() - <-w.semaphore + d.queueMutex.Lock() + if len(d.queue) == 0 { + d.queueMutex.Unlock() + <-d.semaphore return } - data := w.queue[0] - w.queue = w.queue[1:] - w.queueMutex.Unlock() + data := d.queue[0] + d.queue = d.queue[1:] + d.queueMutex.Unlock() // 检查是否有相同 WorkflowId 的 WorkflowRun 正在执行 // 如果有,则重新排队,以保证同一个工作流同一时间内只有一个正在执行 // 即不同 WorkflowId 的任务并行化,相同 WorkflowId 的任务串行化 - w.workerMutex.Lock() - if _, exists := w.workers[data.WorkflowId]; exists { - w.queueMutex.Lock() - w.queue = append(w.queue, data) - w.queueMutex.Unlock() - w.workerMutex.Unlock() + d.workerMutex.Lock() + if _, exists := d.workers[data.WorkflowId]; exists { + d.queueMutex.Lock() + d.queue = append(d.queue, data) + d.queueMutex.Unlock() + d.workerMutex.Unlock() - <-w.semaphore + <-d.semaphore continue } ctx, cancel := context.WithCancel(context.Background()) - w.workers[data.WorkflowId] = &workflowWorker{data, cancel} - w.workerIdMap[data.RunId] = data.WorkflowId - w.workerMutex.Unlock() + d.workers[data.WorkflowId] = &workflowWorker{data, cancel} + d.workerIdMap[data.RunId] = data.WorkflowId + d.workerMutex.Unlock() - w.wg.Add(1) - go w.work(ctx, data) + d.wg.Add(1) + go d.work(ctx, data) } } -func (w *WorkflowDispatcher) work(ctx context.Context, data *WorkflowWorkerData) { +func (d *WorkflowDispatcher) work(ctx context.Context, data *WorkflowWorkerData) { defer func() { - <-w.semaphore - w.workerMutex.Lock() - delete(w.workers, data.WorkflowId) - delete(w.workerIdMap, data.RunId) - w.workerMutex.Unlock() + <-d.semaphore + d.workerMutex.Lock() + delete(d.workers, data.WorkflowId) + delete(d.workerIdMap, data.RunId) + d.workerMutex.Unlock() - w.wg.Done() + d.wg.Done() // 尝试取出排队中的其他 WorkflowRun 继续执行 select { - case w.chCandi <- struct{}{}: + case d.chCandi <- struct{}{}: default: } }() // 查询 WorkflowRun - run, err := w.workflowRunRepo.GetById(ctx, data.RunId) + run, err := d.workflowRunRepo.GetById(ctx, data.RunId) if err != nil { if !(errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded)) { app.GetLogger().Error(fmt.Sprintf("failed to get workflow run #%s", data.RunId), "err", err) @@ -228,13 +230,13 @@ func (w *WorkflowDispatcher) work(ctx context.Context, data *WorkflowWorkerData) return } else if ctx.Err() != nil { run.Status = domain.WorkflowRunStatusTypeCanceled - w.workflowRunRepo.Save(ctx, run) + d.workflowRunRepo.Save(ctx, run) return } // 更新 WorkflowRun 状态为 Running run.Status = domain.WorkflowRunStatusTypeRunning - if _, err := w.workflowRunRepo.Save(ctx, run); err != nil { + if _, err := d.workflowRunRepo.Save(ctx, run); err != nil { if !(errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded)) { panic(err) } @@ -242,19 +244,17 @@ func (w *WorkflowDispatcher) work(ctx context.Context, data *WorkflowWorkerData) } // 执行工作流 - invoker := newWorkflowInvokerWithData(w.workflowRunRepo, data) + invoker := newWorkflowInvokerWithData(d.workflowLogRepo, data) if runErr := invoker.Invoke(ctx); runErr != nil { if errors.Is(runErr, context.Canceled) { run.Status = domain.WorkflowRunStatusTypeCanceled - run.Logs = invoker.GetLogs() } else { run.Status = domain.WorkflowRunStatusTypeFailed run.EndedAt = time.Now() - run.Logs = invoker.GetLogs() run.Error = runErr.Error() } - if _, err := w.workflowRunRepo.Save(ctx, run); err != nil { + if _, err := d.workflowRunRepo.Save(ctx, run); err != nil { if !(errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded)) { panic(err) } @@ -265,14 +265,13 @@ func (w *WorkflowDispatcher) work(ctx context.Context, data *WorkflowWorkerData) // 更新 WorkflowRun 状态为 Succeeded/Failed run.EndedAt = time.Now() - run.Logs = invoker.GetLogs() - run.Error = domain.WorkflowRunLogs(invoker.GetLogs()).ErrorString() + run.Error = invoker.GetLogs().ErrorString() if run.Error == "" { run.Status = domain.WorkflowRunStatusTypeSucceeded } else { run.Status = domain.WorkflowRunStatusTypeFailed } - if _, err := w.workflowRunRepo.Save(ctx, run); err != nil { + if _, err := d.workflowRunRepo.Save(ctx, run); err != nil { if !(errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded)) { panic(err) } diff --git a/internal/workflow/dispatcher/invoker.go b/internal/workflow/dispatcher/invoker.go index d35cca3e..5f344458 100644 --- a/internal/workflow/dispatcher/invoker.go +++ b/internal/workflow/dispatcher/invoker.go @@ -3,8 +3,10 @@ package dispatcher import ( "context" "errors" + "log/slog" "github.com/usual2970/certimate/internal/domain" + "github.com/usual2970/certimate/internal/pkg/logging" nodes "github.com/usual2970/certimate/internal/workflow/node-processor" ) @@ -12,24 +14,23 @@ type workflowInvoker struct { workflowId string workflowContent *domain.WorkflowNode runId string - runLogs []domain.WorkflowRunLog + logs []domain.WorkflowLog - workflowRunRepo workflowRunRepository + workflowLogRepo workflowLogRepository } -func newWorkflowInvokerWithData(workflowRunRepo workflowRunRepository, data *WorkflowWorkerData) *workflowInvoker { +func newWorkflowInvokerWithData(workflowLogRepo workflowLogRepository, data *WorkflowWorkerData) *workflowInvoker { if data == nil { panic("worker data is nil") } - // TODO: 待优化,日志与执行解耦 return &workflowInvoker{ workflowId: data.WorkflowId, workflowContent: data.WorkflowContent, runId: data.RunId, - runLogs: make([]domain.WorkflowRunLog, 0), + logs: make([]domain.WorkflowLog, 0), - workflowRunRepo: workflowRunRepo, + workflowLogRepo: workflowLogRepo, } } @@ -39,8 +40,8 @@ func (w *workflowInvoker) Invoke(ctx context.Context) error { return w.processNode(ctx, w.workflowContent) } -func (w *workflowInvoker) GetLogs() []domain.WorkflowRunLog { - return w.runLogs +func (w *workflowInvoker) GetLogs() domain.WorkflowLogs { + return w.logs } func (w *workflowInvoker) processNode(ctx context.Context, node *domain.WorkflowNode) error { @@ -68,21 +69,34 @@ func (w *workflowInvoker) processNode(ctx context.Context, node *domain.Workflow if current.Type != domain.WorkflowNodeTypeBranch && current.Type != domain.WorkflowNodeTypeExecuteResultBranch { processor, procErr = nodes.GetProcessor(current) if procErr != nil { - break + panic(procErr) } + processor.SetLogger(slog.New(logging.NewHookHandler(&logging.HookHandlerOptions{ + Level: slog.LevelDebug, + WriteFunc: func(ctx context.Context, record *logging.Record) error { + log := domain.WorkflowLog{} + log.WorkflowId = w.workflowId + log.RunId = w.runId + log.NodeId = current.Id + log.NodeName = current.Name + log.Timestamp = record.Time.UnixMilli() + log.Level = record.Level.String() + log.Message = record.Message + log.Data = record.Data + log.CreatedAt = record.Time + if _, err := w.workflowLogRepo.Save(ctx, &log); err != nil { + return err + } + + w.logs = append(w.logs, log) + return nil + }, + }))) + procErr = processor.Process(ctx) - log := processor.GetLog(ctx) - if log != nil { - w.runLogs = append(w.runLogs, *log) - - // TODO: 待优化,把 /pkg/core/* 包下的输出写入到 DEBUG 级别的日志中 - if run, err := w.workflowRunRepo.GetById(ctx, w.runId); err == nil { - run.Logs = w.runLogs - w.workflowRunRepo.Save(ctx, run) - } - } if procErr != nil { + processor.GetLogger().Error(procErr.Error()) break } } diff --git a/internal/workflow/dispatcher/singleton.go b/internal/workflow/dispatcher/singleton.go index b5834c48..20fdde97 100644 --- a/internal/workflow/dispatcher/singleton.go +++ b/internal/workflow/dispatcher/singleton.go @@ -5,6 +5,7 @@ import ( "sync" "github.com/usual2970/certimate/internal/domain" + "github.com/usual2970/certimate/internal/repository" ) type workflowRepository interface { @@ -17,15 +18,18 @@ type workflowRunRepository interface { Save(ctx context.Context, workflowRun *domain.WorkflowRun) (*domain.WorkflowRun, error) } +type workflowLogRepository interface { + Save(ctx context.Context, workflowLog *domain.WorkflowLog) (*domain.WorkflowLog, error) +} + var ( instance *WorkflowDispatcher intanceOnce sync.Once ) -func GetSingletonDispatcher(workflowRepo workflowRepository, workflowRunRepo workflowRunRepository) *WorkflowDispatcher { - // TODO: 待优化构造过程 +func GetSingletonDispatcher() *WorkflowDispatcher { intanceOnce.Do(func() { - instance = newWorkflowDispatcher(workflowRepo, workflowRunRepo) + instance = newWorkflowDispatcher(repository.NewWorkflowRepository(), repository.NewWorkflowRunRepository(), repository.NewWorkflowLogRepository()) }) return instance diff --git a/internal/workflow/event.go b/internal/workflow/event.go index 0fedd67b..ec850af9 100644 --- a/internal/workflow/event.go +++ b/internal/workflow/event.go @@ -65,7 +65,7 @@ func onWorkflowRecordCreateOrUpdate(ctx context.Context, record *core.Record) er // 反之,重新添加定时任务 err := scheduler.Add(fmt.Sprintf("workflow#%s", workflowId), record.GetString("triggerCron"), func() { - workflowSrv := NewWorkflowService(repository.NewWorkflowRepository(), repository.NewWorkflowRunRepository()) + workflowSrv := NewWorkflowService(repository.NewWorkflowRepository(), repository.NewWorkflowRunRepository(), repository.NewSettingsRepository()) workflowSrv.StartRun(ctx, &dtos.WorkflowStartRunReq{ WorkflowId: workflowId, RunTrigger: domain.WorkflowTriggerTypeAuto, diff --git a/internal/workflow/node-processor/apply_node.go b/internal/workflow/node-processor/apply_node.go index 26ff6b9e..a7d6a101 100644 --- a/internal/workflow/node-processor/apply_node.go +++ b/internal/workflow/node-processor/apply_node.go @@ -9,13 +9,13 @@ import ( "github.com/usual2970/certimate/internal/applicant" "github.com/usual2970/certimate/internal/domain" - "github.com/usual2970/certimate/internal/pkg/utils/certs" + "github.com/usual2970/certimate/internal/pkg/utils/certutil" "github.com/usual2970/certimate/internal/repository" ) type applyNode struct { node *domain.WorkflowNode - *nodeLogger + *nodeProcessor certRepo certificateRepository outputRepo workflowOutputRepository @@ -23,8 +23,8 @@ type applyNode struct { func NewApplyNode(node *domain.WorkflowNode) *applyNode { return &applyNode{ - node: node, - nodeLogger: newNodeLogger(node), + node: node, + nodeProcessor: newNodeProcessor(node), certRepo: repository.NewCertificateRepository(), outputRepo: repository.NewWorkflowOutputRepository(), @@ -32,40 +32,40 @@ func NewApplyNode(node *domain.WorkflowNode) *applyNode { } func (n *applyNode) Process(ctx context.Context) error { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelInfo, "进入申请证书节点") + n.logger.Info("ready to apply ...") // 查询上次执行结果 lastOutput, err := n.outputRepo.GetByNodeId(ctx, n.node.Id) if err != nil && !domain.IsRecordNotFoundError(err) { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelError, "查询申请记录失败", err.Error()) return err } // 检测是否可以跳过本次执行 if skippable, skipReason := n.checkCanSkip(ctx, lastOutput); skippable { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelInfo, skipReason) + n.logger.Info(fmt.Sprintf("skip this application, because %s", skipReason)) return nil + } else if skipReason != "" { + n.logger.Info(fmt.Sprintf("continue to apply, because %s", skipReason)) } // 初始化申请器 applicant, err := applicant.NewWithApplyNode(n.node) if err != nil { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelError, "获取申请对象失败", err.Error()) + n.logger.Warn("failed to create applicant provider") return err } // 申请证书 applyResult, err := applicant.Apply() if err != nil { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelError, "申请失败", err.Error()) + n.logger.Warn("failed to apply") return err } - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelInfo, "申请成功") // 解析证书并生成实体 - certX509, err := certs.ParseCertificateFromPEM(applyResult.CertificateFullChain) + certX509, err := certutil.ParseCertificateFromPEM(applyResult.CertificateFullChain) if err != nil { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelError, "解析证书失败", err.Error()) + n.logger.Warn("failed to parse certificate, may be the CA responded error") return err } certificate := &domain.Certificate{ @@ -89,10 +89,11 @@ func (n *applyNode) Process(ctx context.Context) error { Outputs: n.node.Outputs, } if _, err := n.outputRepo.SaveWithCertificate(ctx, output, certificate); err != nil { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelError, "保存申请记录失败", err.Error()) + n.logger.Warn("failed to save node output") return err } - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelInfo, "保存申请记录成功") + + n.logger.Info("apply completed") return nil } @@ -103,19 +104,19 @@ func (n *applyNode) checkCanSkip(ctx context.Context, lastOutput *domain.Workflo currentNodeConfig := n.node.GetConfigForApply() lastNodeConfig := lastOutput.Node.GetConfigForApply() if currentNodeConfig.Domains != lastNodeConfig.Domains { - return false, "配置项变化:域名" + return false, "the configuration item 'Domains' changed" } if currentNodeConfig.ContactEmail != lastNodeConfig.ContactEmail { - return false, "配置项变化:联系邮箱" + return false, "the configuration item 'ContactEmail' changed" } if currentNodeConfig.ProviderAccessId != lastNodeConfig.ProviderAccessId { - return false, "配置项变化:DNS 提供商授权" + return false, "the configuration item 'ProviderAccessId' changed" } if !maps.Equal(currentNodeConfig.ProviderConfig, lastNodeConfig.ProviderConfig) { - return false, "配置项变化:DNS 提供商参数" + return false, "the configuration item 'ProviderConfig' changed" } if currentNodeConfig.KeyAlgorithm != lastNodeConfig.KeyAlgorithm { - return false, "配置项变化:数字签名算法" + return false, "the configuration item 'KeyAlgorithm' changed" } lastCertificate, _ := n.certRepo.GetByWorkflowNodeId(ctx, n.node.Id) @@ -123,7 +124,7 @@ func (n *applyNode) checkCanSkip(ctx context.Context, lastOutput *domain.Workflo renewalInterval := time.Duration(currentNodeConfig.SkipBeforeExpiryDays) * time.Hour * 24 expirationTime := time.Until(lastCertificate.ExpireAt) if expirationTime > renewalInterval { - return true, fmt.Sprintf("已申请过证书,且证书尚未临近过期(尚余 %d 天过期,不足 %d 天时续期),跳过此次申请", int(expirationTime.Hours()/24), currentNodeConfig.SkipBeforeExpiryDays) + return true, fmt.Sprintf("the certificate has already been issued (expires in %dd, next renewal in %dd)", int(expirationTime.Hours()/24), currentNodeConfig.SkipBeforeExpiryDays) } } } diff --git a/internal/workflow/node-processor/condition_node.go b/internal/workflow/node-processor/condition_node.go index 499a5004..2bac55fa 100644 --- a/internal/workflow/node-processor/condition_node.go +++ b/internal/workflow/node-processor/condition_node.go @@ -8,13 +8,13 @@ import ( type conditionNode struct { node *domain.WorkflowNode - *nodeLogger + *nodeProcessor } func NewConditionNode(node *domain.WorkflowNode) *conditionNode { return &conditionNode{ - node: node, - nodeLogger: newNodeLogger(node), + node: node, + nodeProcessor: newNodeProcessor(node), } } diff --git a/internal/workflow/node-processor/deploy_node.go b/internal/workflow/node-processor/deploy_node.go index 492f5385..42bc9ca6 100644 --- a/internal/workflow/node-processor/deploy_node.go +++ b/internal/workflow/node-processor/deploy_node.go @@ -3,6 +3,7 @@ package nodeprocessor import ( "context" "fmt" + "log/slog" "strings" "github.com/usual2970/certimate/internal/deployer" @@ -13,7 +14,7 @@ import ( type deployNode struct { node *domain.WorkflowNode - *nodeLogger + *nodeProcessor certRepo certificateRepository outputRepo workflowOutputRepository @@ -21,8 +22,8 @@ type deployNode struct { func NewDeployNode(node *domain.WorkflowNode) *deployNode { return &deployNode{ - node: node, - nodeLogger: newNodeLogger(node), + node: node, + nodeProcessor: newNodeProcessor(node), certRepo: repository.NewCertificateRepository(), outputRepo: repository.NewWorkflowOutputRepository(), @@ -30,12 +31,11 @@ func NewDeployNode(node *domain.WorkflowNode) *deployNode { } func (n *deployNode) Process(ctx context.Context) error { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelInfo, "开始执行") + n.logger.Info("ready to deploy ...") // 查询上次执行结果 lastOutput, err := n.outputRepo.GetByNodeId(ctx, n.node.Id) if err != nil && !domain.IsRecordNotFoundError(err) { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelError, "查询部署记录失败", err.Error()) return err } @@ -43,20 +43,22 @@ func (n *deployNode) Process(ctx context.Context) error { previousNodeOutputCertificateSource := n.node.GetConfigForDeploy().Certificate previousNodeOutputCertificateSourceSlice := strings.Split(previousNodeOutputCertificateSource, "#") if len(previousNodeOutputCertificateSourceSlice) != 2 { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelError, "证书来源配置错误", previousNodeOutputCertificateSource) - return fmt.Errorf("证书来源配置错误: %s", previousNodeOutputCertificateSource) + n.logger.Warn("invalid certificate source", slog.String("certificate.source", previousNodeOutputCertificateSource)) + return fmt.Errorf("invalid certificate source: %s", previousNodeOutputCertificateSource) } certificate, err := n.certRepo.GetByWorkflowNodeId(ctx, previousNodeOutputCertificateSourceSlice[0]) if err != nil { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelError, "获取证书失败", err.Error()) + n.logger.Warn("invalid certificate source", slog.String("certificate.source", previousNodeOutputCertificateSource)) return err } // 检测是否可以跳过本次执行 if lastOutput != nil && certificate.CreatedAt.Before(lastOutput.UpdatedAt) { if skippable, skipReason := n.checkCanSkip(ctx, lastOutput); skippable { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelInfo, skipReason) + n.logger.Info(fmt.Sprintf("skip this deployment, because %s", skipReason)) return nil + } else if skipReason != "" { + n.logger.Info(fmt.Sprintf("continue to deploy, because %s", skipReason)) } } @@ -66,16 +68,16 @@ func (n *deployNode) Process(ctx context.Context) error { PrivateKey string }{Certificate: certificate.Certificate, PrivateKey: certificate.PrivateKey}) if err != nil { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelError, "获取部署对象失败", err.Error()) + n.logger.Warn("failed to create deployer provider") return err } // 部署证书 + deployer.SetLogger(n.logger) if err := deployer.Deploy(ctx); err != nil { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelError, "部署失败", err.Error()) + n.logger.Warn("failed to deploy") return err } - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelInfo, "部署成功") // 保存执行结果 output := &domain.WorkflowOutput{ @@ -86,10 +88,11 @@ func (n *deployNode) Process(ctx context.Context) error { Succeeded: true, } if _, err := n.outputRepo.Save(ctx, output); err != nil { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelError, "保存部署记录失败", err.Error()) + n.logger.Warn("failed to save node output") return err } - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelInfo, "保存部署记录成功") + + n.logger.Info("deploy completed") return nil } @@ -100,14 +103,14 @@ func (n *deployNode) checkCanSkip(ctx context.Context, lastOutput *domain.Workfl currentNodeConfig := n.node.GetConfigForDeploy() lastNodeConfig := lastOutput.Node.GetConfigForDeploy() if currentNodeConfig.ProviderAccessId != lastNodeConfig.ProviderAccessId { - return false, "配置项变化:主机提供商授权" + return false, "the configuration item 'ProviderAccessId' changed" } if !maps.Equal(currentNodeConfig.ProviderConfig, lastNodeConfig.ProviderConfig) { - return false, "配置项变化:主机提供商参数" + return false, "the configuration item 'ProviderConfig' changed" } if currentNodeConfig.SkipOnLastSucceeded { - return true, "已部署过证书,跳过此次部署" + return true, "the certificate has already been deployed" } } diff --git a/internal/workflow/node-processor/execute_failure_node.go b/internal/workflow/node-processor/execute_failure_node.go index 2516edb4..59f6a5bd 100644 --- a/internal/workflow/node-processor/execute_failure_node.go +++ b/internal/workflow/node-processor/execute_failure_node.go @@ -8,19 +8,19 @@ import ( type executeFailureNode struct { node *domain.WorkflowNode - *nodeLogger + *nodeProcessor } func NewExecuteFailureNode(node *domain.WorkflowNode) *executeFailureNode { return &executeFailureNode{ - node: node, - nodeLogger: newNodeLogger(node), + node: node, + nodeProcessor: newNodeProcessor(node), } } func (n *executeFailureNode) Process(ctx context.Context) error { // 此类型节点不需要执行任何操作,直接返回 - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelInfo, "进入执行失败分支") + n.logger.Info("the previous node execution was failed") return nil } diff --git a/internal/workflow/node-processor/execute_success_node.go b/internal/workflow/node-processor/execute_success_node.go index a7833a53..e5b65860 100644 --- a/internal/workflow/node-processor/execute_success_node.go +++ b/internal/workflow/node-processor/execute_success_node.go @@ -8,19 +8,19 @@ import ( type executeSuccessNode struct { node *domain.WorkflowNode - *nodeLogger + *nodeProcessor } func NewExecuteSuccessNode(node *domain.WorkflowNode) *executeSuccessNode { return &executeSuccessNode{ - node: node, - nodeLogger: newNodeLogger(node), + node: node, + nodeProcessor: newNodeProcessor(node), } } func (n *executeSuccessNode) Process(ctx context.Context) error { // 此类型节点不需要执行任何操作,直接返回 - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelInfo, "进入执行成功分支") + n.logger.Info("the previous node execution was succeeded") return nil } diff --git a/internal/workflow/node-processor/notify_node.go b/internal/workflow/node-processor/notify_node.go index e4c3da2d..1c2b49d8 100644 --- a/internal/workflow/node-processor/notify_node.go +++ b/internal/workflow/node-processor/notify_node.go @@ -2,6 +2,7 @@ package nodeprocessor import ( "context" + "log/slog" "github.com/usual2970/certimate/internal/domain" "github.com/usual2970/certimate/internal/notify" @@ -10,45 +11,44 @@ import ( type notifyNode struct { node *domain.WorkflowNode - *nodeLogger + *nodeProcessor settingsRepo settingsRepository } func NewNotifyNode(node *domain.WorkflowNode) *notifyNode { return ¬ifyNode{ - node: node, - nodeLogger: newNodeLogger(node), + node: node, + nodeProcessor: newNodeProcessor(node), settingsRepo: repository.NewSettingsRepository(), } } func (n *notifyNode) Process(ctx context.Context) error { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelInfo, "进入推送通知节点") + n.logger.Info("ready to notify ...") nodeConfig := n.node.GetConfigForNotify() // 获取通知配置 settings, err := n.settingsRepo.GetByName(ctx, "notifyChannels") if err != nil { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelError, "获取通知配置失败", err.Error()) return err } // 获取通知渠道 channelConfig, err := settings.GetNotifyChannelConfig(nodeConfig.Channel) if err != nil { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelError, "获取通知渠道配置失败", err.Error()) return err } // 发送通知 if err := notify.SendToChannel(nodeConfig.Subject, nodeConfig.Message, nodeConfig.Channel, channelConfig); err != nil { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelError, "发送通知失败", err.Error()) + n.logger.Warn("failed to notify", slog.String("channel", nodeConfig.Channel)) return err } - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelInfo, "发送通知成功") + + n.logger.Info("notify completed") return nil } diff --git a/internal/workflow/node-processor/processor.go b/internal/workflow/node-processor/processor.go index 08712280..4523b13a 100644 --- a/internal/workflow/node-processor/processor.go +++ b/internal/workflow/node-processor/processor.go @@ -2,21 +2,34 @@ package nodeprocessor import ( "context" - "errors" - "time" + "fmt" + "io" + "log/slog" "github.com/usual2970/certimate/internal/domain" ) type NodeProcessor interface { - Process(ctx context.Context) error + GetLogger() *slog.Logger + SetLogger(*slog.Logger) - GetLog(ctx context.Context) *domain.WorkflowRunLog - AppendLogRecord(ctx context.Context, level domain.WorkflowRunLogLevel, content string, err ...string) + Process(ctx context.Context) error } -type nodeLogger struct { - log *domain.WorkflowRunLog +type nodeProcessor struct { + logger *slog.Logger +} + +func (n *nodeProcessor) GetLogger() *slog.Logger { + return n.logger +} + +func (n *nodeProcessor) SetLogger(logger *slog.Logger) { + if logger == nil { + panic("logger is nil") + } + + n.logger = logger } type certificateRepository interface { @@ -33,34 +46,12 @@ type settingsRepository interface { GetByName(ctx context.Context, name string) (*domain.Settings, error) } -func newNodeLogger(node *domain.WorkflowNode) *nodeLogger { - return &nodeLogger{ - log: &domain.WorkflowRunLog{ - NodeId: node.Id, - NodeName: node.Name, - Records: make([]domain.WorkflowRunLogRecord, 0), - }, +func newNodeProcessor(node *domain.WorkflowNode) *nodeProcessor { + return &nodeProcessor{ + logger: slog.New(slog.NewTextHandler(io.Discard, nil)), } } -func (l *nodeLogger) GetLog(ctx context.Context) *domain.WorkflowRunLog { - return l.log -} - -func (l *nodeLogger) AppendLogRecord(ctx context.Context, level domain.WorkflowRunLogLevel, content string, err ...string) { - record := domain.WorkflowRunLogRecord{ - Time: time.Now().UTC().Format(time.RFC3339), - Level: level, - Content: content, - } - if len(err) > 0 { - record.Error = err[0] - l.log.Error = err[0] - } - - l.log.Records = append(l.log.Records, record) -} - func GetProcessor(node *domain.WorkflowNode) (NodeProcessor, error) { switch node.Type { case domain.WorkflowNodeTypeStart: @@ -80,7 +71,8 @@ func GetProcessor(node *domain.WorkflowNode) (NodeProcessor, error) { case domain.WorkflowNodeTypeExecuteFailure: return NewExecuteFailureNode(node), nil } - return nil, errors.New("not implemented") + + return nil, fmt.Errorf("supported node type: %s", string(node.Type)) } func getContextWorkflowId(ctx context.Context) string { diff --git a/internal/workflow/node-processor/start_node.go b/internal/workflow/node-processor/start_node.go index 7d04685a..5bbc1c09 100644 --- a/internal/workflow/node-processor/start_node.go +++ b/internal/workflow/node-processor/start_node.go @@ -8,19 +8,19 @@ import ( type startNode struct { node *domain.WorkflowNode - *nodeLogger + *nodeProcessor } func NewStartNode(node *domain.WorkflowNode) *startNode { return &startNode{ - node: node, - nodeLogger: newNodeLogger(node), + node: node, + nodeProcessor: newNodeProcessor(node), } } func (n *startNode) Process(ctx context.Context) error { // 此类型节点不需要执行任何操作,直接返回 - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelInfo, "进入开始节点") + n.logger.Info("ready to start ...") return nil } diff --git a/internal/workflow/node-processor/upload_node.go b/internal/workflow/node-processor/upload_node.go index 99108481..6c46e90f 100644 --- a/internal/workflow/node-processor/upload_node.go +++ b/internal/workflow/node-processor/upload_node.go @@ -2,18 +2,16 @@ package nodeprocessor import ( "context" - "errors" + "fmt" "strings" - "time" "github.com/usual2970/certimate/internal/domain" - "github.com/usual2970/certimate/internal/pkg/utils/certs" "github.com/usual2970/certimate/internal/repository" ) type uploadNode struct { node *domain.WorkflowNode - *nodeLogger + *nodeProcessor certRepo certificateRepository outputRepo workflowOutputRepository @@ -21,8 +19,8 @@ type uploadNode struct { func NewUploadNode(node *domain.WorkflowNode) *uploadNode { return &uploadNode{ - node: node, - nodeLogger: newNodeLogger(node), + node: node, + nodeProcessor: newNodeProcessor(node), certRepo: repository.NewCertificateRepository(), outputRepo: repository.NewWorkflowOutputRepository(), @@ -30,33 +28,22 @@ func NewUploadNode(node *domain.WorkflowNode) *uploadNode { } func (n *uploadNode) Process(ctx context.Context) error { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelInfo, "进入上传证书节点") + n.logger.Info("ready to upload ...") nodeConfig := n.node.GetConfigForUpload() // 查询上次执行结果 lastOutput, err := n.outputRepo.GetByNodeId(ctx, n.node.Id) if err != nil && !domain.IsRecordNotFoundError(err) { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelError, "查询申请记录失败", err.Error()) return err } // 检测是否可以跳过本次执行 if skippable, skipReason := n.checkCanSkip(ctx, lastOutput); skippable { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelInfo, skipReason) + n.logger.Info(fmt.Sprintf("skip this upload, because %s", skipReason)) return nil - } - - // 检查证书是否过期 - // 如果证书过期,则直接返回错误 - certX509, err := certs.ParseCertificateFromPEM(nodeConfig.Certificate) - if err != nil { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelError, "解析证书失败") - return err - } - if time.Now().After(certX509.NotAfter) { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelWarn, "证书已过期") - return errors.New("certificate is expired") + } else if skipReason != "" { + n.logger.Info(fmt.Sprintf("continue to upload, because %s", skipReason)) } // 生成证书实体 @@ -75,10 +62,11 @@ func (n *uploadNode) Process(ctx context.Context) error { Outputs: n.node.Outputs, } if _, err := n.outputRepo.SaveWithCertificate(ctx, output, certificate); err != nil { - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelError, "保存上传记录失败", err.Error()) + n.logger.Warn("failed to save node output") return err } - n.AppendLogRecord(ctx, domain.WorkflowRunLogLevelInfo, "保存上传记录成功") + + n.logger.Info("upload completed") return nil } @@ -89,15 +77,15 @@ func (n *uploadNode) checkCanSkip(ctx context.Context, lastOutput *domain.Workfl currentNodeConfig := n.node.GetConfigForUpload() lastNodeConfig := lastOutput.Node.GetConfigForUpload() if strings.TrimSpace(currentNodeConfig.Certificate) != strings.TrimSpace(lastNodeConfig.Certificate) { - return false, "配置项变化:证书" + return false, "the configuration item 'Certificate' changed" } if strings.TrimSpace(currentNodeConfig.PrivateKey) != strings.TrimSpace(lastNodeConfig.PrivateKey) { - return false, "配置项变化:私钥" + return false, "the configuration item 'PrivateKey' changed" } lastCertificate, _ := n.certRepo.GetByWorkflowNodeId(ctx, n.node.Id) if lastCertificate != nil { - return true, "已上传过证书" + return true, "the certificate has already been uploaded" } } diff --git a/internal/workflow/service.go b/internal/workflow/service.go index d2236a8d..f234be63 100644 --- a/internal/workflow/service.go +++ b/internal/workflow/service.go @@ -2,10 +2,13 @@ package workflow import ( "context" + "encoding/json" "errors" "fmt" "time" + "github.com/pocketbase/dbx" + "github.com/usual2970/certimate/internal/app" "github.com/usual2970/certimate/internal/domain" "github.com/usual2970/certimate/internal/domain/dtos" @@ -21,6 +24,11 @@ type workflowRepository interface { type workflowRunRepository interface { GetById(ctx context.Context, id string) (*domain.WorkflowRun, error) Save(ctx context.Context, workflowRun *domain.WorkflowRun) (*domain.WorkflowRun, error) + DeleteWhere(ctx context.Context, exprs ...dbx.Expression) (int, error) +} + +type settingsRepository interface { + GetByName(ctx context.Context, name string) (*domain.Settings, error) } type WorkflowService struct { @@ -28,40 +36,71 @@ type WorkflowService struct { workflowRepo workflowRepository workflowRunRepo workflowRunRepository + settingsRepo settingsRepository } -func NewWorkflowService(workflowRepo workflowRepository, workflowRunRepo workflowRunRepository) *WorkflowService { +func NewWorkflowService(workflowRepo workflowRepository, workflowRunRepo workflowRunRepository, settingsRepo settingsRepository) *WorkflowService { srv := &WorkflowService{ - dispatcher: dispatcher.GetSingletonDispatcher(workflowRepo, workflowRunRepo), + dispatcher: dispatcher.GetSingletonDispatcher(), workflowRepo: workflowRepo, workflowRunRepo: workflowRunRepo, + settingsRepo: settingsRepo, } return srv } func (s *WorkflowService) InitSchedule(ctx context.Context) error { - workflows, err := s.workflowRepo.ListEnabledAuto(ctx) - if err != nil { - return err - } - - scheduler := app.GetScheduler() - for _, workflow := range workflows { - var errs []error - - err := scheduler.Add(fmt.Sprintf("workflow#%s", workflow.Id), workflow.TriggerCron, func() { - s.StartRun(ctx, &dtos.WorkflowStartRunReq{ - WorkflowId: workflow.Id, - RunTrigger: domain.WorkflowTriggerTypeAuto, - }) - }) + // 每日清理工作流执行历史 + app.GetScheduler().MustAdd("workflowHistoryRunsCleanup", "0 0 * * *", func() { + settings, err := s.settingsRepo.GetByName(ctx, "persistence") if err != nil { - errs = append(errs, err) + app.GetLogger().Error("failed to get persistence settings", "err", err) + return } - if len(errs) > 0 { - return errors.Join(errs...) + var settingsContent *domain.PersistenceSettingsContent + json.Unmarshal([]byte(settings.Content), &settingsContent) + if settingsContent != nil && settingsContent.WorkflowRunsMaxDaysRetention != 0 { + ret, err := s.workflowRunRepo.DeleteWhere( + context.Background(), + dbx.NewExp(fmt.Sprintf("status!='%s'", string(domain.WorkflowRunStatusTypePending))), + dbx.NewExp(fmt.Sprintf("status!='%s'", string(domain.WorkflowRunStatusTypeRunning))), + dbx.NewExp(fmt.Sprintf("endedAt 0 { + app.GetLogger().Info(fmt.Sprintf("cleanup %d workflow history runs", ret)) + } + } + }) + + // 工作流 + { + workflows, err := s.workflowRepo.ListEnabledAuto(ctx) + if err != nil { + return err + } + + for _, workflow := range workflows { + var errs []error + + err := app.GetScheduler().Add(fmt.Sprintf("workflow#%s", workflow.Id), workflow.TriggerCron, func() { + s.StartRun(ctx, &dtos.WorkflowStartRunReq{ + WorkflowId: workflow.Id, + RunTrigger: domain.WorkflowTriggerTypeAuto, + }) + }) + if err != nil { + errs = append(errs, err) + } + + if len(errs) > 0 { + return errors.Join(errs...) + } } } @@ -83,6 +122,7 @@ func (s *WorkflowService) StartRun(ctx context.Context, req *dtos.WorkflowStartR Status: domain.WorkflowRunStatusTypePending, Trigger: req.RunTrigger, StartedAt: time.Now(), + Detail: workflow.Content, } if resp, err := s.workflowRunRepo.Save(ctx, run); err != nil { return err @@ -91,8 +131,8 @@ func (s *WorkflowService) StartRun(ctx context.Context, req *dtos.WorkflowStartR } s.dispatcher.Dispatch(&dispatcher.WorkflowWorkerData{ - WorkflowId: workflow.Id, - WorkflowContent: workflow.Content, + WorkflowId: run.WorkflowId, + WorkflowContent: run.Detail, RunId: run.Id, }) diff --git a/migrations/1739462400_collections_snapshot.go b/migrations/1739462400_collections_snapshot.go index 67453954..d8ed7409 100644 --- a/migrations/1739462400_collections_snapshot.go +++ b/migrations/1739462400_collections_snapshot.go @@ -7,8 +7,7 @@ import ( "github.com/pocketbase/pocketbase/core" m "github.com/pocketbase/pocketbase/migrations" - - "github.com/usual2970/certimate/internal/pkg/utils/certs" + "github.com/usual2970/certimate/internal/pkg/utils/certutil" ) func init() { @@ -1754,21 +1753,21 @@ func init() { case "certificate": { if record.GetString("issuer") == "" { - cert, _ := certs.ParseCertificateFromPEM(record.GetString("certificate")) + cert, _ := certutil.ParseCertificateFromPEM(record.GetString("certificate")) if cert != nil { record.Set("issuer", strings.Join(cert.Issuer.Organization, ";")) changed = true } } if record.GetString("serialNumber") == "" { - cert, _ := certs.ParseCertificateFromPEM(record.GetString("certificate")) + cert, _ := certutil.ParseCertificateFromPEM(record.GetString("certificate")) if cert != nil { record.Set("serialNumber", strings.ToUpper(cert.SerialNumber.Text(16))) changed = true } } if record.GetString("keyAlgorithm") == "" { - cert, _ := certs.ParseCertificateFromPEM(record.GetString("certificate")) + cert, _ := certutil.ParseCertificateFromPEM(record.GetString("certificate")) if cert != nil { switch cert.SignatureAlgorithm { case x509.SHA256WithRSA, x509.SHA256WithRSAPSS: diff --git a/migrations/1740050400_collections_hotfix.go b/migrations/1740050400_upgrade.go similarity index 83% rename from migrations/1740050400_collections_hotfix.go rename to migrations/1740050400_upgrade.go index be193a17..93bc3f33 100644 --- a/migrations/1740050400_collections_hotfix.go +++ b/migrations/1740050400_upgrade.go @@ -7,11 +7,13 @@ import ( func init() { m.Register(func(app core.App) error { - certimateCollection, err := app.FindCollectionByNameOrId("4szxr9x43tpj6np") - if err != nil { - return err - } else { - // update field + // update collection `certificate` + { + certimateCollection, err := app.FindCollectionByNameOrId("4szxr9x43tpj6np") + if err != nil { + return err + } + if err := certimateCollection.Fields.AddMarshaledJSONAt(4, []byte(`{ "autogeneratePattern": "", "hidden": false, @@ -29,7 +31,6 @@ func init() { return err } - // update field if err := certimateCollection.Fields.AddMarshaledJSONAt(5, []byte(`{ "autogeneratePattern": "", "hidden": false, @@ -47,7 +48,6 @@ func init() { return err } - // update field if err := certimateCollection.Fields.AddMarshaledJSONAt(7, []byte(`{ "autogeneratePattern": "", "hidden": false, @@ -70,11 +70,13 @@ func init() { } } - workflowCollection, err := app.FindCollectionByNameOrId("tovyif5ax6j62ur") - if err != nil { - return err - } else { - // update field + // update collection `workflow` + { + workflowCollection, err := app.FindCollectionByNameOrId("tovyif5ax6j62ur") + if err != nil { + return err + } + if err := workflowCollection.Fields.AddMarshaledJSONAt(6, []byte(`{ "hidden": false, "id": "awlphkfe", @@ -88,7 +90,6 @@ func init() { return err } - // update field if err := workflowCollection.Fields.AddMarshaledJSONAt(7, []byte(`{ "hidden": false, "id": "g9ohkk5o", @@ -107,11 +108,13 @@ func init() { } } - workflowOutputCollection, err := app.FindCollectionByNameOrId("bqnxb95f2cooowp") - if err != nil { - return err - } else { - // update field + // update collection `workflow_output` + { + workflowOutputCollection, err := app.FindCollectionByNameOrId("bqnxb95f2cooowp") + if err != nil { + return err + } + if err := workflowOutputCollection.Fields.AddMarshaledJSONAt(4, []byte(`{ "hidden": false, "id": "c2rm9omj", diff --git a/migrations/1742209200_upgrade.go b/migrations/1742209200_upgrade.go new file mode 100644 index 00000000..0a980972 --- /dev/null +++ b/migrations/1742209200_upgrade.go @@ -0,0 +1,335 @@ +package migrations + +import ( + "encoding/json" + "strings" + "time" + + "github.com/pocketbase/pocketbase/core" + m "github.com/pocketbase/pocketbase/migrations" + + "github.com/usual2970/certimate/internal/domain" +) + +func init() { + m.Register(func(app core.App) error { + // create collection `workflow_logs` + { + jsonData := `{ + "createRule": null, + "deleteRule": null, + "fields": [ + { + "autogeneratePattern": "[a-z0-9]{15}", + "hidden": false, + "id": "text3208210256", + "max": 15, + "min": 15, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + }, + { + "cascadeDelete": true, + "collectionId": "tovyif5ax6j62ur", + "hidden": false, + "id": "relation3371272342", + "maxSelect": 1, + "minSelect": 0, + "name": "workflowId", + "presentable": false, + "required": false, + "system": false, + "type": "relation" + }, + { + "cascadeDelete": true, + "collectionId": "qjp8lygssgwyqyz", + "hidden": false, + "id": "relation821863227", + "maxSelect": 1, + "minSelect": 0, + "name": "runId", + "presentable": false, + "required": false, + "system": false, + "type": "relation" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text157423495", + "max": 0, + "min": 0, + "name": "nodeId", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text3227511481", + "max": 0, + "min": 0, + "name": "nodeName", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "hidden": false, + "id": "number2782324286", + "max": null, + "min": null, + "name": "timestamp", + "onlyInt": false, + "presentable": false, + "required": false, + "system": false, + "type": "number" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text2599078931", + "max": 0, + "min": 0, + "name": "level", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text3065852031", + "max": 0, + "min": 0, + "name": "message", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "hidden": false, + "id": "json2918445923", + "maxSize": 0, + "name": "data", + "presentable": false, + "required": false, + "system": false, + "type": "json" + }, + { + "hidden": false, + "id": "autodate2990389176", + "name": "created", + "onCreate": true, + "onUpdate": false, + "presentable": false, + "system": false, + "type": "autodate" + } + ], + "id": "pbc_1682296116", + "indexes": [ + "CREATE INDEX ` + "`" + `idx_IOlpy6XuJ2` + "`" + ` ON ` + "`" + `workflow_logs` + "`" + ` (` + "`" + `workflowId` + "`" + `)", + "CREATE INDEX ` + "`" + `idx_qVlTb2yl7v` + "`" + ` ON ` + "`" + `workflow_logs` + "`" + ` (` + "`" + `runId` + "`" + `)" + ], + "listRule": null, + "name": "workflow_logs", + "system": false, + "type": "base", + "updateRule": null, + "viewRule": null + }` + + collection := &core.Collection{} + if err := json.Unmarshal([]byte(jsonData), &collection); err != nil { + return err + } + + if err := app.Save(collection); err != nil { + return err + } + } + + // migrate data + { + workflowRuns, err := app.FindAllRecords("workflow_run") + if err != nil { + return err + } + + for _, workflowRun := range workflowRuns { + type oldWorkflowRunLogRecord struct { + Time string `json:"time"` + Level string `json:"level"` + Content string `json:"content"` + Error string `json:"error"` + } + type oldWorkflowRunLog struct { + NodeId string `json:"nodeId"` + NodeName string `json:"nodeName"` + Records []oldWorkflowRunLogRecord `json:"records"` + Error string `json:"error"` + } + + logs := make([]oldWorkflowRunLog, 0) + if err := workflowRun.UnmarshalJSONField("logs", &logs); err != nil { + continue + } + + collection, err := app.FindCollectionByNameOrId("workflow_logs") + if err != nil { + return err + } + + for _, log := range logs { + for _, logRecord := range log.Records { + record := core.NewRecord(collection) + createdAt, _ := time.Parse(time.RFC3339, logRecord.Time) + record.Set("workflowId", workflowRun.Get("workflowId")) + record.Set("runId", workflowRun.Get("id")) + record.Set("nodeId", log.NodeId) + record.Set("nodeName", log.NodeName) + record.Set("timestamp", createdAt.UnixMilli()) + record.Set("level", logRecord.Level) + record.Set("message", strings.TrimSpace(logRecord.Content+" "+logRecord.Error)) + record.Set("created", createdAt) + if err := app.Save(record); err != nil { + return err + } + } + } + } + } + + // update collection `workflow_run` + { + collection, err := app.FindCollectionByNameOrId("workflow_run") + if err != nil { + return err + } + + if err := collection.Fields.AddMarshaledJSONAt(6, []byte(`{ + "hidden": false, + "id": "json772177811", + "maxSize": 5000000, + "name": "detail", + "presentable": false, + "required": false, + "system": false, + "type": "json" + }`)); err != nil { + return err + } + + if err := app.Save(collection); err != nil { + return err + } + } + + // migrate data + { + workflowRuns, err := app.FindAllRecords("workflow_run") + if err != nil { + return err + } + + workflowOutputs, err := app.FindAllRecords("workflow_output") + if err != nil { + return err + } + + for _, workflowRun := range workflowRuns { + node := &domain.WorkflowNode{} + for _, workflowOutput := range workflowOutputs { + if workflowOutput.GetString("runId") != workflowRun.Get("id") { + continue + } + + if err := workflowOutput.UnmarshalJSONField("node", node); err != nil { + continue + } + + if node.Type != domain.WorkflowNodeTypeApply { + node = &domain.WorkflowNode{} + continue + } + } + + if node.Id == "" { + workflow, _ := app.FindRecordById("workflow", workflowRun.GetString("workflowId")) + if workflow != nil { + workflowRun.Set("detail", workflow.Get("content")) + } else { + workflowRun.Set("detail", make(map[string]any)) + } + } else { + workflow, _ := app.FindRecordById("workflow", workflowRun.GetString("workflowId")) + if workflow != nil { + rootNode := &domain.WorkflowNode{} + if err := workflow.UnmarshalJSONField("content", rootNode); err != nil { + return err + } + + rootNode.Next = node + workflowRun.Set("detail", rootNode) + } else { + rootNode := &domain.WorkflowNode{ + Id: core.GenerateDefaultRandomId(), + Type: domain.WorkflowNodeTypeStart, + Name: "开始", + Config: map[string]any{ + "trigger": "manual", + }, + Next: node, + Validated: true, + } + workflowRun.Set("detail", rootNode) + } + } + + if err := app.Save(workflowRun); err != nil { + return err + } + } + } + + // update collection `workflow_run` + { + collection, err := app.FindCollectionByNameOrId("workflow_run") + if err != nil { + return err + } + + collection.Fields.RemoveByName("logs") + + if err := app.Save(collection); err != nil { + return err + } + } + + return nil + }, func(app core.App) error { + return nil + }) +} diff --git a/migrations/1742392800_upgrade.go b/migrations/1742392800_upgrade.go new file mode 100644 index 00000000..a06bdc75 --- /dev/null +++ b/migrations/1742392800_upgrade.go @@ -0,0 +1,81 @@ +package migrations + +import ( + "github.com/pocketbase/pocketbase/core" + m "github.com/pocketbase/pocketbase/migrations" +) + +func init() { + m.Register(func(app core.App) error { + collection, err := app.FindCollectionByNameOrId("4yzbv8urny5ja1e") + if err != nil { + return err + } + + // update field + if err := collection.Fields.AddMarshaledJSONAt(2, []byte(`{ + "hidden": false, + "id": "hwy7m03o", + "maxSelect": 1, + "name": "provider", + "presentable": false, + "required": false, + "system": false, + "type": "select", + "values": [ + "1panel", + "acmehttpreq", + "akamai", + "aliyun", + "aws", + "azure", + "baiducloud", + "baishan", + "baotapanel", + "byteplus", + "cachefly", + "cdnfly", + "cloudflare", + "cloudns", + "cmcccloud", + "ctcccloud", + "cucccloud", + "dnsla", + "dogecloud", + "dynv6", + "edgio", + "fastly", + "gname", + "gcore", + "godaddy", + "goedge", + "huaweicloud", + "jdcloud", + "k8s", + "local", + "namecheap", + "namedotcom", + "namesilo", + "ns1", + "powerdns", + "qiniu", + "qingcloud", + "rainyun", + "safeline", + "ssh", + "tencentcloud", + "ucloud", + "upyun", + "volcengine", + "webhook", + "westcn" + ] + }`)); err != nil { + return err + } + + return app.Save(collection) + }, func(app core.App) error { + return nil + }) +} diff --git a/ui/package-lock.json b/ui/package-lock.json index 2aafc283..90a18bbf 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -11,23 +11,23 @@ "@ant-design/icons": "^5.6.1", "@ant-design/pro-components": "^2.8.6", "ahooks": "^3.8.4", - "antd": "^5.24.3", + "antd": "^5.24.4", "antd-zod": "^6.0.1", "clsx": "^2.1.1", - "cron-parser": "^5.0.4", + "cron-parser": "^5.0.6", "file-saver": "^2.0.5", - "i18next": "^24.2.2", + "i18next": "^24.2.3", "i18next-browser-languagedetector": "^8.0.4", "immer": "^10.1.1", - "lucide-react": "^0.477.0", - "nanoid": "^5.1.2", + "lucide-react": "^0.483.0", + "nanoid": "^5.1.5", "pocketbase": "^0.25.2", "radash": "^12.1.0", "react": "^18.3.1", "react-copy-to-clipboard": "^5.1.0", "react-dom": "^18.3.1", "react-i18next": "^15.4.1", - "react-router-dom": "^7.2.0", + "react-router-dom": "^7.4.0", "tailwind-merge": "^2.6.0", "zod": "^3.24.2", "zustand": "^5.0.3" @@ -35,17 +35,17 @@ "devDependencies": { "@types/file-saver": "^2.0.7", "@types/fs-extra": "^11.0.4", - "@types/node": "^22.13.9", + "@types/node": "^22.13.10", "@types/react": "^18.3.12", "@types/react-copy-to-clipboard": "^5.0.7", "@types/react-dom": "^18.3.1", - "@typescript-eslint/eslint-plugin": "^8.26.0", - "@typescript-eslint/parser": "^8.26.0", + "@typescript-eslint/eslint-plugin": "^8.27.0", + "@typescript-eslint/parser": "^8.27.0", "@vitejs/plugin-legacy": "^6.0.2", "@vitejs/plugin-react": "^4.3.4", - "autoprefixer": "^10.4.20", + "autoprefixer": "^10.4.21", "eslint": "^8.57.0", - "eslint-config-prettier": "^10.0.2", + "eslint-config-prettier": "^10.1.1", "eslint-import-resolver-typescript": "^3.8.3", "eslint-plugin-import": "^2.31.0", "eslint-plugin-prettier": "^5.2.3", @@ -58,7 +58,7 @@ "tailwindcss": "^3.4.17", "tailwindcss-animate": "^1.0.7", "typescript": "^5.8.2", - "vite": "^6.2.0" + "vite": "^6.2.2" } }, "node_modules/@alloc/quick-lru": { @@ -1879,9 +1879,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.26.0", - "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.26.0.tgz", - "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", + "version": "7.26.10", + "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.26.10.tgz", + "integrity": "sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -3218,9 +3218,9 @@ } }, "node_modules/@types/node": { - "version": "22.13.9", - "resolved": "https://registry.npmmirror.com/@types/node/-/node-22.13.9.tgz", - "integrity": "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw==", + "version": "22.13.10", + "resolved": "https://registry.npmmirror.com/@types/node/-/node-22.13.10.tgz", + "integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==", "dev": true, "dependencies": { "undici-types": "~6.20.0" @@ -3261,16 +3261,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.26.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.26.0.tgz", - "integrity": "sha512-cLr1J6pe56zjKYajK6SSSre6nl1Gj6xDp1TY0trpgPzjVbgDwd09v2Ws37LABxzkicmUjhEeg/fAUjPJJB1v5Q==", + "version": "8.27.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.27.0.tgz", + "integrity": "sha512-4henw4zkePi5p252c8ncBLzLce52SEUz2Ebj8faDnuUXz2UuHEONYcJ+G0oaCF+bYCWVZtrGzq3FD7YXetmnSA==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.26.0", - "@typescript-eslint/type-utils": "8.26.0", - "@typescript-eslint/utils": "8.26.0", - "@typescript-eslint/visitor-keys": "8.26.0", + "@typescript-eslint/scope-manager": "8.27.0", + "@typescript-eslint/type-utils": "8.27.0", + "@typescript-eslint/utils": "8.27.0", + "@typescript-eslint/visitor-keys": "8.27.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -3290,15 +3290,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.26.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-8.26.0.tgz", - "integrity": "sha512-mNtXP9LTVBy14ZF3o7JG69gRPBK/2QWtQd0j0oH26HcY/foyJJau6pNUez7QrM5UHnSvwlQcJXKsk0I99B9pOA==", + "version": "8.27.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-8.27.0.tgz", + "integrity": "sha512-XGwIabPallYipmcOk45DpsBSgLC64A0yvdAkrwEzwZ2viqGqRUJ8eEYoPz0CWnutgAFbNMPdsGGvzjSmcWVlEA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.26.0", - "@typescript-eslint/types": "8.26.0", - "@typescript-eslint/typescript-estree": "8.26.0", - "@typescript-eslint/visitor-keys": "8.26.0", + "@typescript-eslint/scope-manager": "8.27.0", + "@typescript-eslint/types": "8.27.0", + "@typescript-eslint/typescript-estree": "8.27.0", + "@typescript-eslint/visitor-keys": "8.27.0", "debug": "^4.3.4" }, "engines": { @@ -3314,13 +3314,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.26.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-8.26.0.tgz", - "integrity": "sha512-E0ntLvsfPqnPwng8b8y4OGuzh/iIOm2z8U3S9zic2TeMLW61u5IH2Q1wu0oSTkfrSzwbDJIB/Lm8O3//8BWMPA==", + "version": "8.27.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-8.27.0.tgz", + "integrity": "sha512-8oI9GwPMQmBryaaxG1tOZdxXVeMDte6NyJA4i7/TWa4fBwgnAXYlIQP+uYOeqAaLJ2JRxlG9CAyL+C+YE9Xknw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.26.0", - "@typescript-eslint/visitor-keys": "8.26.0" + "@typescript-eslint/types": "8.27.0", + "@typescript-eslint/visitor-keys": "8.27.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3331,13 +3331,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.26.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-8.26.0.tgz", - "integrity": "sha512-ruk0RNChLKz3zKGn2LwXuVoeBcUMh+jaqzN461uMMdxy5H9epZqIBtYj7UiPXRuOpaALXGbmRuZQhmwHhaS04Q==", + "version": "8.27.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-8.27.0.tgz", + "integrity": "sha512-wVArTVcz1oJOIEJxui/nRhV0TXzD/zMSOYi/ggCfNq78EIszddXcJb7r4RCp/oBrjt8n9A0BSxRMKxHftpDxDA==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "8.26.0", - "@typescript-eslint/utils": "8.26.0", + "@typescript-eslint/typescript-estree": "8.27.0", + "@typescript-eslint/utils": "8.27.0", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, @@ -3354,9 +3354,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.26.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-8.26.0.tgz", - "integrity": "sha512-89B1eP3tnpr9A8L6PZlSjBvnJhWXtYfZhECqlBl1D9Lme9mHO6iWlsprBtVenQvY1HMhax1mWOjhtL3fh/u+pA==", + "version": "8.27.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-8.27.0.tgz", + "integrity": "sha512-/6cp9yL72yUHAYq9g6DsAU+vVfvQmd1a8KyA81uvfDE21O2DwQ/qxlM4AR8TSdAu+kJLBDrEHKC5/W2/nxsY0A==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3367,13 +3367,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.26.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.26.0.tgz", - "integrity": "sha512-tiJ1Hvy/V/oMVRTbEOIeemA2XoylimlDQ03CgPPNaHYZbpsc78Hmngnt+WXZfJX1pjQ711V7g0H7cSJThGYfPQ==", + "version": "8.27.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.27.0.tgz", + "integrity": "sha512-BnKq8cqPVoMw71O38a1tEb6iebEgGA80icSxW7g+kndx0o6ot6696HjG7NdgfuAVmVEtwXUr3L8R9ZuVjoQL6A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.26.0", - "@typescript-eslint/visitor-keys": "8.26.0", + "@typescript-eslint/types": "8.27.0", + "@typescript-eslint/visitor-keys": "8.27.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -3393,15 +3393,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.26.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-8.26.0.tgz", - "integrity": "sha512-2L2tU3FVwhvU14LndnQCA2frYC8JnPDVKyQtWFPf8IYFMt/ykEN1bPolNhNbCVgOmdzTlWdusCTKA/9nKrf8Ig==", + "version": "8.27.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-8.27.0.tgz", + "integrity": "sha512-njkodcwH1yvmo31YWgRHNb/x1Xhhq4/m81PhtvmRngD8iHPehxffz1SNCO+kwaePhATC+kOa/ggmvPoPza5i0Q==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.26.0", - "@typescript-eslint/types": "8.26.0", - "@typescript-eslint/typescript-estree": "8.26.0" + "@typescript-eslint/scope-manager": "8.27.0", + "@typescript-eslint/types": "8.27.0", + "@typescript-eslint/typescript-estree": "8.27.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3416,12 +3416,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.26.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.26.0.tgz", - "integrity": "sha512-2z8JQJWAzPdDd51dRQ/oqIJxe99/hoLIqmf8RMCAJQtYDc535W/Jt2+RTP4bP0aKeBG1F65yjIZuczOXCmbWwg==", + "version": "8.27.0", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.27.0.tgz", + "integrity": "sha512-WsXQwMkILJvffP6z4U3FYJPlbf/j07HIxmDjZpbNvBJkMfvwXj5ACRkkHwBDvLBbDbtX5TdU64/rcvKJ/vuInQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.26.0", + "@typescript-eslint/types": "8.27.0", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -3585,9 +3585,9 @@ } }, "node_modules/antd": { - "version": "5.24.3", - "resolved": "https://registry.npmmirror.com/antd/-/antd-5.24.3.tgz", - "integrity": "sha512-H5fopyOVRAnegfwLuEdjhPR+l5z3/lo4aQyDsgIYhfmeBcRgN/XNkefVxzRHNuWHeYr9E9LbyxEQcMF91sy5lg==", + "version": "5.24.4", + "resolved": "https://registry.npmmirror.com/antd/-/antd-5.24.4.tgz", + "integrity": "sha512-s89666DcoWeekJFaIqbtz2vRlIvgPR28GuDYYGUpW1mVP08bV7HZAPBH5lFJKYNGKrN3dHbZGgRK5aNRD2iPHg==", "dependencies": { "@ant-design/colors": "^7.2.0", "@ant-design/cssinjs": "^1.23.0", @@ -3628,7 +3628,7 @@ "rc-slider": "~11.1.8", "rc-steps": "~6.0.1", "rc-switch": "~4.1.0", - "rc-table": "~7.50.3", + "rc-table": "~7.50.4", "rc-tabs": "~15.5.1", "rc-textarea": "~1.9.0", "rc-tooltip": "~6.4.0", @@ -3805,9 +3805,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.20", - "resolved": "https://registry.npmmirror.com/autoprefixer/-/autoprefixer-10.4.20.tgz", - "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", + "version": "10.4.21", + "resolved": "https://registry.npmmirror.com/autoprefixer/-/autoprefixer-10.4.21.tgz", + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", "dev": true, "funding": [ { @@ -3824,11 +3824,11 @@ } ], "dependencies": { - "browserslist": "^4.23.3", - "caniuse-lite": "^1.0.30001646", + "browserslist": "^4.24.4", + "caniuse-lite": "^1.0.30001702", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", - "picocolors": "^1.0.1", + "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "bin": { @@ -4066,9 +4066,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001689", - "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001689.tgz", - "integrity": "sha512-CmeR2VBycfa+5/jOfnp/NpWPGd06nf1XYiefUvhXFfZE4GkRc9jv+eGPS4nT558WS/8lYCzV8SlANCIPvbWP1g==", + "version": "1.0.30001706", + "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001706.tgz", + "integrity": "sha512-3ZczoTApMAZwPKYWmwVbQMFpXBDds3/0VciVoUwPUbldlYyVLmRVuRs/PcUZtHpbLRpzzDvrvnFuREsGt6lUug==", "dev": true, "funding": [ { @@ -4201,9 +4201,9 @@ } }, "node_modules/cron-parser": { - "version": "5.0.4", - "resolved": "https://registry.npmmirror.com/cron-parser/-/cron-parser-5.0.4.tgz", - "integrity": "sha512-ud6L7uGE4a7QxKndq106+99iKMlhG1/gSVlA4SH7qy3xO/R/EUoXFTJFMBOogdk00mZiXPONRI4wFKAcymKp6w==", + "version": "5.0.6", + "resolved": "https://registry.npmmirror.com/cron-parser/-/cron-parser-5.0.6.tgz", + "integrity": "sha512-KtZxEaO4XtQwQ6q2Val3gX09TxM/1Okz0BIqkm6Wwc582gAHTnjBP1rtYEgWcVOUPRIg2CeirOTiUSu7A2I+HQ==", "dependencies": { "luxon": "^3.5.0" }, @@ -4670,12 +4670,12 @@ } }, "node_modules/eslint-config-prettier": { - "version": "10.0.2", - "resolved": "https://registry.npmmirror.com/eslint-config-prettier/-/eslint-config-prettier-10.0.2.tgz", - "integrity": "sha512-1105/17ZIMjmCOJOPNfVdbXafLCLj3hPmkmB7dLgt7XsQ/zkxSuDerE/xgO3RxoHysR1N1whmquY0lSn2O0VLg==", + "version": "10.1.1", + "resolved": "https://registry.npmmirror.com/eslint-config-prettier/-/eslint-config-prettier-10.1.1.tgz", + "integrity": "sha512-4EQQr6wXwS+ZJSzaR5ZCrYgLxqvUjdXctaEtBqHcbkW944B1NQyO4qpdHQbXBONfwxXdkAY81HH4+LUfrg+zPw==", "dev": true, "bin": { - "eslint-config-prettier": "build/bin/cli.js" + "eslint-config-prettier": "bin/cli.js" }, "peerDependencies": { "eslint": ">=7.0.0" @@ -5608,9 +5608,9 @@ } }, "node_modules/i18next": { - "version": "24.2.2", - "resolved": "https://registry.npmmirror.com/i18next/-/i18next-24.2.2.tgz", - "integrity": "sha512-NE6i86lBCKRYZa5TaUDkU5S4HFgLIEJRLr3Whf2psgaxBleQ2LC1YW1Vc+SCgkAW7VEzndT6al6+CzegSUHcTQ==", + "version": "24.2.3", + "resolved": "https://registry.npmmirror.com/i18next/-/i18next-24.2.3.tgz", + "integrity": "sha512-lfbf80OzkocvX7nmZtu7nSTNbrTYR52sLWxPtlXX1zAhVw8WEnFk4puUkCR4B1dNQwbSpEHHHemcZu//7EcB7A==", "funding": [ { "type": "individual", @@ -5626,7 +5626,7 @@ } ], "dependencies": { - "@babel/runtime": "^7.23.2" + "@babel/runtime": "^7.26.10" }, "peerDependencies": { "typescript": "^5" @@ -6324,9 +6324,9 @@ } }, "node_modules/lucide-react": { - "version": "0.477.0", - "resolved": "https://registry.npmmirror.com/lucide-react/-/lucide-react-0.477.0.tgz", - "integrity": "sha512-yCf7aYxerFZAbd8jHJxjwe1j7jEMPptjnaOqdYeirFnEy85cNR3/L+o0I875CYFYya+eEVzZSbNuRk8BZPDpVw==", + "version": "0.483.0", + "resolved": "https://registry.npmmirror.com/lucide-react/-/lucide-react-0.483.0.tgz", + "integrity": "sha512-WldsY17Qb/T3VZdMnVQ9C3DDIP7h1ViDTHVdVGnLZcvHNg30zH/MTQ04RTORjexoGmpsXroiQXZ4QyR0kBy0FA==", "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } @@ -6442,9 +6442,9 @@ } }, "node_modules/nanoid": { - "version": "5.1.2", - "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-5.1.2.tgz", - "integrity": "sha512-b+CiXQCNMUGe0Ri64S9SXFcP9hogjAJ2Rd6GdVxhPLRm7mhGaM7VgOvCAJ1ZshfHbqVDI3uqTI5C8/GaKuLI7g==", + "version": "5.1.5", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-5.1.5.tgz", + "integrity": "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==", "funding": [ { "type": "github", @@ -7470,9 +7470,9 @@ } }, "node_modules/rc-table": { - "version": "7.50.3", - "resolved": "https://registry.npmmirror.com/rc-table/-/rc-table-7.50.3.tgz", - "integrity": "sha512-Z4/zNCzjv7f/XzPRecb+vJU0DJKdsYt4YRkDzNl4G05m7JmxrKGYC2KqN1Ew6jw2zJq7cxVv3z39qyZOHMuf7A==", + "version": "7.50.4", + "resolved": "https://registry.npmmirror.com/rc-table/-/rc-table-7.50.4.tgz", + "integrity": "sha512-Y+YuncnQqoS5e7yHvfvlv8BmCvwDYDX/2VixTBEhkMDk9itS9aBINp4nhzXFKiBP/frG4w0pS9d9Rgisl0T1Bw==", "dependencies": { "@babel/runtime": "^7.10.1", "@rc-component/context": "^1.4.0", @@ -7702,9 +7702,9 @@ } }, "node_modules/react-router": { - "version": "7.2.0", - "resolved": "https://registry.npmmirror.com/react-router/-/react-router-7.2.0.tgz", - "integrity": "sha512-fXyqzPgCPZbqhrk7k3hPcCpYIlQ2ugIXDboHUzhJISFVy2DEPsmHgN588MyGmkIOv3jDgNfUE3kJi83L28s/LQ==", + "version": "7.4.0", + "resolved": "https://registry.npmmirror.com/react-router/-/react-router-7.4.0.tgz", + "integrity": "sha512-Y2g5ObjkvX3VFeVt+0CIPuYd9PpgqCslG7ASSIdN73LwA1nNWzcMLaoMRJfP3prZFI92svxFwbn7XkLJ+UPQ6A==", "dependencies": { "@types/cookie": "^0.6.0", "cookie": "^1.0.1", @@ -7725,11 +7725,11 @@ } }, "node_modules/react-router-dom": { - "version": "7.2.0", - "resolved": "https://registry.npmmirror.com/react-router-dom/-/react-router-dom-7.2.0.tgz", - "integrity": "sha512-cU7lTxETGtQRQbafJubvZKHEn5izNABxZhBY0Jlzdv0gqQhCPQt2J8aN5ZPjS6mQOXn5NnirWNh+FpE8TTYN0Q==", + "version": "7.4.0", + "resolved": "https://registry.npmmirror.com/react-router-dom/-/react-router-dom-7.4.0.tgz", + "integrity": "sha512-VlksBPf3n2bijPvnA7nkTsXxMAKOj+bWp4R9c3i+bnwlSOFAGOkJkKhzy/OsRkWaBMICqcAl1JDzh9ZSOze9CA==", "dependencies": { - "react-router": "7.2.0" + "react-router": "7.4.0" }, "engines": { "node": ">=20.0.0" @@ -9052,9 +9052,9 @@ "dev": true }, "node_modules/vite": { - "version": "6.2.0", - "resolved": "https://registry.npmmirror.com/vite/-/vite-6.2.0.tgz", - "integrity": "sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==", + "version": "6.2.2", + "resolved": "https://registry.npmmirror.com/vite/-/vite-6.2.2.tgz", + "integrity": "sha512-yW7PeMM+LkDzc7CgJuRLMW2Jz0FxMOsVJ8Lv3gpgW9WLcb9cTW+121UEr1hvmfR7w3SegR5ItvYyzVz1vxNJgQ==", "dev": true, "dependencies": { "esbuild": "^0.25.0", diff --git a/ui/package.json b/ui/package.json index d72a318a..d11376fe 100644 --- a/ui/package.json +++ b/ui/package.json @@ -13,23 +13,23 @@ "@ant-design/icons": "^5.6.1", "@ant-design/pro-components": "^2.8.6", "ahooks": "^3.8.4", - "antd": "^5.24.3", + "antd": "^5.24.4", "antd-zod": "^6.0.1", "clsx": "^2.1.1", - "cron-parser": "^5.0.4", + "cron-parser": "^5.0.6", "file-saver": "^2.0.5", - "i18next": "^24.2.2", + "i18next": "^24.2.3", "i18next-browser-languagedetector": "^8.0.4", "immer": "^10.1.1", - "lucide-react": "^0.477.0", - "nanoid": "^5.1.2", + "lucide-react": "^0.483.0", + "nanoid": "^5.1.5", "pocketbase": "^0.25.2", "radash": "^12.1.0", "react": "^18.3.1", "react-copy-to-clipboard": "^5.1.0", "react-dom": "^18.3.1", "react-i18next": "^15.4.1", - "react-router-dom": "^7.2.0", + "react-router-dom": "^7.4.0", "tailwind-merge": "^2.6.0", "zod": "^3.24.2", "zustand": "^5.0.3" @@ -37,17 +37,17 @@ "devDependencies": { "@types/file-saver": "^2.0.7", "@types/fs-extra": "^11.0.4", - "@types/node": "^22.13.9", + "@types/node": "^22.13.10", "@types/react": "^18.3.12", "@types/react-copy-to-clipboard": "^5.0.7", "@types/react-dom": "^18.3.1", - "@typescript-eslint/eslint-plugin": "^8.26.0", - "@typescript-eslint/parser": "^8.26.0", + "@typescript-eslint/eslint-plugin": "^8.27.0", + "@typescript-eslint/parser": "^8.27.0", "@vitejs/plugin-legacy": "^6.0.2", "@vitejs/plugin-react": "^4.3.4", - "autoprefixer": "^10.4.20", + "autoprefixer": "^10.4.21", "eslint": "^8.57.0", - "eslint-config-prettier": "^10.0.2", + "eslint-config-prettier": "^10.1.1", "eslint-import-resolver-typescript": "^3.8.3", "eslint-plugin-import": "^2.31.0", "eslint-plugin-prettier": "^5.2.3", @@ -60,6 +60,6 @@ "tailwindcss": "^3.4.17", "tailwindcss-animate": "^1.0.7", "typescript": "^5.8.2", - "vite": "^6.2.0" + "vite": "^6.2.2" } } diff --git a/ui/public/imgs/providers/dynv6.svg b/ui/public/imgs/providers/dynv6.svg new file mode 100644 index 00000000..652e4e45 --- /dev/null +++ b/ui/public/imgs/providers/dynv6.svg @@ -0,0 +1 @@ + diff --git a/ui/public/imgs/providers/upyun.svg b/ui/public/imgs/providers/upyun.svg new file mode 100644 index 00000000..cc13793d --- /dev/null +++ b/ui/public/imgs/providers/upyun.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ui/src/components/access/AccessForm.tsx b/ui/src/components/access/AccessForm.tsx index 7f2143ac..63a66875 100644 --- a/ui/src/components/access/AccessForm.tsx +++ b/ui/src/components/access/AccessForm.tsx @@ -25,6 +25,7 @@ import AccessFormClouDNSConfig from "./AccessFormClouDNSConfig"; import AccessFormCMCCCloudConfig from "./AccessFormCMCCCloudConfig"; import AccessFormDNSLAConfig from "./AccessFormDNSLAConfig"; import AccessFormDogeCloudConfig from "./AccessFormDogeCloudConfig"; +import AccessFormDynv6Config from "./AccessFormDynv6Config"; import AccessFormEdgioConfig from "./AccessFormEdgioConfig"; import AccessFormGcoreConfig from "./AccessFormGcoreConfig"; import AccessFormGnameConfig from "./AccessFormGnameConfig"; @@ -44,6 +45,7 @@ import AccessFormSafeLineConfig from "./AccessFormSafeLineConfig"; import AccessFormSSHConfig from "./AccessFormSSHConfig"; import AccessFormTencentCloudConfig from "./AccessFormTencentCloudConfig"; import AccessFormUCloudConfig from "./AccessFormUCloudConfig"; +import AccessFormUpyunConfig from "./AccessFormUpyunConfig"; import AccessFormVolcEngineConfig from "./AccessFormVolcEngineConfig"; import AccessFormWebhookConfig from "./AccessFormWebhookConfig"; import AccessFormWestcnConfig from "./AccessFormWestcnConfig"; @@ -132,6 +134,8 @@ const AccessForm = forwardRef(({ className, return ; case ACCESS_PROVIDERS.DOGECLOUD: return ; + case ACCESS_PROVIDERS.DYNV6: + return ; case ACCESS_PROVIDERS.GCORE: return ; case ACCESS_PROVIDERS.GNAME: @@ -170,6 +174,8 @@ const AccessForm = forwardRef(({ className, return ; case ACCESS_PROVIDERS.UCLOUD: return ; + case ACCESS_PROVIDERS.UPYUN: + return ; case ACCESS_PROVIDERS.VOLCENGINE: return ; case ACCESS_PROVIDERS.WEBHOOK: diff --git a/ui/src/components/access/AccessFormAzureConfig.tsx b/ui/src/components/access/AccessFormAzureConfig.tsx index 954d47aa..a5facbf9 100644 --- a/ui/src/components/access/AccessFormAzureConfig.tsx +++ b/ui/src/components/access/AccessFormAzureConfig.tsx @@ -1,5 +1,5 @@ import { useTranslation } from "react-i18next"; -import { Form, type FormInstance, Input } from "antd"; +import { AutoComplete, Form, type FormInstance, Input } from "antd"; import { createSchemaFieldRule } from "antd-zod"; import { z } from "zod"; @@ -92,7 +92,11 @@ const AccessFormAzureConfig = ({ form: formInst, formName, disabled, initialValu rules={[formRule]} tooltip={} > - + ({ value }))} + placeholder={t("access.form.azure_cloud_name.placeholder")} + filterOption={(inputValue, option) => option!.value.toLowerCase().includes(inputValue.toLowerCase())} + /> ); diff --git a/ui/src/components/access/AccessFormDynv6Config.tsx b/ui/src/components/access/AccessFormDynv6Config.tsx new file mode 100644 index 00000000..92385302 --- /dev/null +++ b/ui/src/components/access/AccessFormDynv6Config.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 AccessConfigForDynv6 } from "@/domain/access"; + +type AccessFormDynv6ConfigFieldValues = Nullish; + +export type AccessFormDynv6ConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: AccessFormDynv6ConfigFieldValues; + onValuesChange?: (values: AccessFormDynv6ConfigFieldValues) => void; +}; + +const initFormModel = (): AccessFormDynv6ConfigFieldValues => { + return { + httpToken: "", + }; +}; + +const AccessFormDynv6Config = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormDynv6ConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + httpToken: z + .string() + .min(1, t("access.form.dynv6_http_token.placeholder")) + .max(256, t("common.errmsg.string_max", { max: 256 })) + .trim(), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ } + > + + +
+ ); +}; + +export default AccessFormDynv6Config; diff --git a/ui/src/components/access/AccessFormGcoreConfig.tsx b/ui/src/components/access/AccessFormGcoreConfig.tsx index 8619f7fe..858dac02 100644 --- a/ui/src/components/access/AccessFormGcoreConfig.tsx +++ b/ui/src/components/access/AccessFormGcoreConfig.tsx @@ -28,7 +28,7 @@ const AccessFormGcoreConfig = ({ form: formInst, formName, disabled, initialValu apiToken: z .string() .min(1, t("access.form.gcore_api_token.placeholder")) - .max(64, t("common.errmsg.string_max", { max: 64 })) + .max(256, t("common.errmsg.string_max", { max: 256 })) .trim(), }); const formRule = createSchemaFieldRule(formSchema); diff --git a/ui/src/components/access/AccessFormUpyunConfig.tsx b/ui/src/components/access/AccessFormUpyunConfig.tsx new file mode 100644 index 00000000..8cc06d97 --- /dev/null +++ b/ui/src/components/access/AccessFormUpyunConfig.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 AccessConfigForUpyun } from "@/domain/access"; + +type AccessFormUpyunConfigFieldValues = Nullish; + +export type AccessFormUpyunConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: AccessFormUpyunConfigFieldValues; + onValuesChange?: (values: AccessFormUpyunConfigFieldValues) => void; +}; + +const initFormModel = (): AccessFormUpyunConfigFieldValues => { + return { + username: "", + password: "", + }; +}; + +const AccessFormUpyunConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: AccessFormUpyunConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + username: z + .string() + .trim() + .min(1, t("access.form.upyun_username.placeholder")) + .max(64, t("common.errmsg.string_max", { max: 64 })), + password: z + .string() + .min(1, t("access.form.upyun_password.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 AccessFormUpyunConfig; diff --git a/ui/src/components/workflow/WorkflowRunDetail.tsx b/ui/src/components/workflow/WorkflowRunDetail.tsx index 785624f9..5d8c7f29 100644 --- a/ui/src/components/workflow/WorkflowRunDetail.tsx +++ b/ui/src/components/workflow/WorkflowRunDetail.tsx @@ -1,16 +1,45 @@ import { useState } from "react"; import { useTranslation } from "react-i18next"; -import { SelectOutlined as SelectOutlinedIcon } from "@ant-design/icons"; +import { + CheckCircleOutlined as CheckCircleOutlinedIcon, + CheckOutlined as CheckOutlinedIcon, + ClockCircleOutlined as ClockCircleOutlinedIcon, + CloseCircleOutlined as CloseCircleOutlinedIcon, + RightOutlined as RightOutlinedIcon, + SelectOutlined as SelectOutlinedIcon, + SettingOutlined as SettingOutlinedIcon, + StopOutlined as StopOutlinedIcon, + SyncOutlined as SyncOutlinedIcon, +} from "@ant-design/icons"; import { useRequest } from "ahooks"; -import { Alert, Button, Divider, Empty, Space, Table, type TableProps, Tooltip, Typography, notification } from "antd"; +import { + Button, + Collapse, + Divider, + Dropdown, + Empty, + Flex, + Skeleton, + Space, + Spin, + Table, + type TableProps, + Tooltip, + Typography, + notification, + theme, +} from "antd"; import dayjs from "dayjs"; import { ClientResponseError } from "pocketbase"; import CertificateDetailDrawer from "@/components/certificate/CertificateDetailDrawer"; import Show from "@/components/Show"; import { type CertificateModel } from "@/domain/certificate"; +import type { WorkflowLogModel } from "@/domain/workflowLog"; import { WORKFLOW_RUN_STATUSES, type WorkflowRunModel } from "@/domain/workflowRun"; -import { listByWorkflowRunId as listCertificateByWorkflowRunId } from "@/repository/certificate"; +import { listByWorkflowRunId as listCertificatesByWorkflowRunId } from "@/repository/certificate"; +import { listByWorkflowRunId as listLogsByWorkflowRunId } from "@/repository/workflowLog"; +import { mergeCls } from "@/utils/css"; import { getErrMsg } from "@/utils/error"; export type WorkflowRunDetailProps = { @@ -20,52 +49,213 @@ export type WorkflowRunDetailProps = { }; const WorkflowRunDetail = ({ data, ...props }: WorkflowRunDetailProps) => { - const { t } = useTranslation(); - return (
- - {t("workflow_run.props.status.succeeded")}} /> + + - - {t("workflow_run.props.status.failed")}} /> - - -
- {t("workflow_run.logs")} -
-
- {data.logs?.map((item, i) => { - return ( -
-
{item.nodeName}
-
- {item.records?.map((output, j) => { - return ( -
-
[{dayjs(output.time).format("YYYY-MM-DD HH:mm:ss")}]
- {output.error ?
{output.error}
:
{output.content}
} -
- ); - })} -
-
- ); - })} -
-
-
- - + -
); }; +const WorkflowRunLogs = ({ runId, runStatus }: { runId: string; runStatus: string }) => { + const { t } = useTranslation(); + + const { token: themeToken } = theme.useToken(); + + type Log = Pick; + type LogGroup = { id: string; name: string; records: Log[] }; + const [listData, setListData] = useState([]); + const { loading } = useRequest( + () => { + return listLogsByWorkflowRunId(runId); + }, + { + refreshDeps: [runId, runStatus], + pollingInterval: runStatus === WORKFLOW_RUN_STATUSES.PENDING || runStatus === WORKFLOW_RUN_STATUSES.RUNNING ? 3000 : 0, + pollingWhenHidden: false, + throttleWait: 500, + onSuccess: (res) => { + if (res.items.length === listData.flatMap((e) => e.records).length) return; + + setListData( + res.items.reduce((acc, e) => { + let group = acc.at(-1); + if (!group || group.id !== e.nodeId) { + group = { id: e.nodeId, name: e.nodeName, records: [] }; + acc.push(group); + } + group.records.push({ timestamp: e.timestamp, level: e.level, message: e.message, data: e.data }); + return acc; + }, [] as LogGroup[]) + ); + }, + onError: (err) => { + if (err instanceof ClientResponseError && err.isAbort) { + return; + } + + console.error(err); + + throw err; + }, + } + ); + + const [showTimestamp, setShowTimestamp] = useState(true); + const [showWhitespace, setShowWhitespace] = useState(true); + + const renderBadge = () => { + switch (runStatus) { + case WORKFLOW_RUN_STATUSES.PENDING: + return ( + + + {t("workflow_run.props.status.pending")} + + ); + case WORKFLOW_RUN_STATUSES.RUNNING: + return ( + + + {t("workflow_run.props.status.running")} + + ); + case WORKFLOW_RUN_STATUSES.SUCCEEDED: + return ( + + + {t("workflow_run.props.status.succeeded")} + + ); + case WORKFLOW_RUN_STATUSES.FAILED: + return ( + + + {t("workflow_run.props.status.failed")} + + ); + case WORKFLOW_RUN_STATUSES.CANCELED: + return ( + + + {t("workflow_run.props.status.canceled")} + + ); + } + + return <>; + }; + + const renderRecord = (record: Log) => { + let message = <>{record.message}; + if (record.data != null && Object.keys(record.data).length > 0) { + message = ( +
+ {record.message} + {Object.entries(record.data).map(([key, value]) => ( +
+
{key}:
+
{JSON.stringify(value)}
+
+ ))} +
+ ); + } + + return ( +
+ {showTimestamp ?
[{dayjs(record.timestamp).format("YYYY-MM-DD HH:mm:ss")}]
: <>} +
+ {message} +
+
+ ); + }; + + return ( + <> + {t("workflow_run.logs")} +
+
+
{renderBadge()}
+
+ , + onClick: () => setShowTimestamp(!showTimestamp), + }, + { + key: "show-whitespace", + label: t("workflow_run.logs.menu.show_whitespaces"), + icon: , + onClick: () => setShowWhitespace(!showWhitespace), + }, + ], + }} + trigger={["click"]} + > +
+
+ + + + 0} + fallback={ + + + + } + > +
+ group.id)} + expandIcon={({ isActive }) => } + items={listData.map((group) => { + return { + key: group.id, + classNames: { + header: "text-sm text-stone-200", + body: "text-stone-200", + }, + style: { color: "inherit", border: "none" }, + styles: { + header: { color: "inherit" }, + }, + label: group.name, + children:
{group.records.map((record) => renderRecord(record))}
, + }; + })} + /> +
+
+
+ + ); +}; + const WorkflowRunArtifacts = ({ runId }: { runId: string }) => { const { t } = useTranslation(); @@ -117,13 +307,10 @@ const WorkflowRunArtifacts = ({ runId }: { runId: string }) => { const [tableData, setTableData] = useState([]); const { loading: tableLoading } = useRequest( () => { - return listCertificateByWorkflowRunId(runId); + return listCertificatesByWorkflowRunId(runId); }, { refreshDeps: [runId], - onBefore: () => { - setTableData([]); - }, onSuccess: (res) => { setTableData(res.items); }, diff --git a/ui/src/components/workflow/node/BranchNode.tsx b/ui/src/components/workflow/node/BranchNode.tsx index 4a68f315..f8a755d0 100644 --- a/ui/src/components/workflow/node/BranchNode.tsx +++ b/ui/src/components/workflow/node/BranchNode.tsx @@ -10,8 +10,6 @@ import AddNode from "./AddNode"; import WorkflowElement from "../WorkflowElement"; import { type SharedNodeProps } from "./_SharedNode"; -const { useToken } = theme; - export type BrandNodeProps = SharedNodeProps; const BranchNode = ({ node, disabled }: BrandNodeProps) => { @@ -19,7 +17,7 @@ const BranchNode = ({ node, disabled }: BrandNodeProps) => { const { addBranch } = useWorkflowStore(useZustandShallowSelector(["addBranch"])); - const token = useToken(); + const { token: themeToken } = theme.useToken(); const renderBranch = (node: WorkflowNode, branchNodeId?: string, branchIndex?: number) => { const elements: JSX.Element[] = []; @@ -38,7 +36,7 @@ const BranchNode = ({ node, disabled }: BrandNodeProps) => {
+ +
+ + + + + @@ -349,22 +395,22 @@ Set-ItemProperty -Path $rdpCertPath -Name "SSLCertificateSHA1Hash" -Value "$thum { key: "reload_nginx", label: t("workflow_node.deploy.form.local_preset_scripts.option.reload_nginx.label"), - onClick: () => handlePresetScriptClick("reload_nginx"), + onClick: () => handlePresetPostScriptClick("reload_nginx"), }, { key: "binding_iis", label: t("workflow_node.deploy.form.local_preset_scripts.option.binding_iis.label"), - onClick: () => handlePresetScriptClick("binding_iis"), + onClick: () => handlePresetPostScriptClick("binding_iis"), }, { key: "binding_netsh", label: t("workflow_node.deploy.form.local_preset_scripts.option.binding_netsh.label"), - onClick: () => handlePresetScriptClick("binding_netsh"), + onClick: () => handlePresetPostScriptClick("binding_netsh"), }, { key: "binding_rdp", label: t("workflow_node.deploy.form.local_preset_scripts.option.binding_rdp.label"), - onClick: () => handlePresetScriptClick("binding_rdp"), + onClick: () => handlePresetPostScriptClick("binding_rdp"), }, ], }} diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormQiniuKodoConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormQiniuKodoConfig.tsx new file mode 100644 index 00000000..e7a7dfb7 --- /dev/null +++ b/ui/src/components/workflow/node/DeployNodeConfigFormQiniuKodoConfig.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 DeployNodeConfigFormQiniuKodoConfigFieldValues = Nullish<{ + domain: string; +}>; + +export type DeployNodeConfigFormQiniuKodoConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: DeployNodeConfigFormQiniuKodoConfigFieldValues; + onValuesChange?: (values: DeployNodeConfigFormQiniuKodoConfigFieldValues) => void; +}; + +const initFormModel = (): DeployNodeConfigFormQiniuKodoConfigFieldValues => { + return {}; +}; + +const DeployNodeConfigFormQiniuKodoConfig = ({ + form: formInst, + formName, + disabled, + initialValues, + onValuesChange, +}: DeployNodeConfigFormQiniuKodoConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + domain: z + .string({ message: t("workflow_node.deploy.form.qiniu_kodo_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 DeployNodeConfigFormQiniuKodoConfig; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormSSHConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormSSHConfig.tsx index 1e176d7b..65a7df7b 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigFormSSHConfig.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigFormSSHConfig.tsx @@ -127,7 +127,23 @@ const DeployNodeConfigFormSSHConfig = ({ form: formInst, formName, disabled, ini } }; - const handlePresetScriptClick = (key: string) => { + const handlePresetPreScriptClick = (key: string) => { + switch (key) { + case "backup_files": + { + formInst.setFieldValue( + "preCommand", + `# 请将以下路径替换为实际值 +cp "${formInst.getFieldValue("certPath")}" "${formInst.getFieldValue("certPath")}.bak" 2>/dev/null || : +cp "${formInst.getFieldValue("keyPath")}" "${formInst.getFieldValue("keyPath")}.bak" 2>/dev/null || : + `.trim() + ); + } + break; + } + }; + + const handlePresetPostScriptClick = (key: string) => { switch (key) { case "reload_nginx": { @@ -228,8 +244,36 @@ const DeployNodeConfigFormSSHConfig = ({ form: formInst, formName, disabled, ini +
+ + ); +}; + +export default DeployNodeConfigFormUpyunCDNConfig; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormUpyunFileConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormUpyunFileConfig.tsx new file mode 100644 index 00000000..c5b3902d --- /dev/null +++ b/ui/src/components/workflow/node/DeployNodeConfigFormUpyunFileConfig.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 DeployNodeConfigFormUpyunFileConfigFieldValues = Nullish<{ + domain: string; +}>; + +export type DeployNodeConfigFormUpyunFileConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: DeployNodeConfigFormUpyunFileConfigFieldValues; + onValuesChange?: (values: DeployNodeConfigFormUpyunFileConfigFieldValues) => void; +}; + +const initFormModel = (): DeployNodeConfigFormUpyunFileConfigFieldValues => { + return {}; +}; + +const DeployNodeConfigFormUpyunFileConfig = ({ + form: formInst, + formName, + disabled, + initialValues, + onValuesChange, +}: DeployNodeConfigFormUpyunFileConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + domain: z + .string({ message: t("workflow_node.deploy.form.upyun_file_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 DeployNodeConfigFormUpyunFileConfig; diff --git a/ui/src/components/workflow/node/ExecuteResultBranchNode.tsx b/ui/src/components/workflow/node/ExecuteResultBranchNode.tsx index 10501cf9..098c66d7 100644 --- a/ui/src/components/workflow/node/ExecuteResultBranchNode.tsx +++ b/ui/src/components/workflow/node/ExecuteResultBranchNode.tsx @@ -7,12 +7,10 @@ import AddNode from "./AddNode"; import WorkflowElement from "../WorkflowElement"; import { type SharedNodeProps } from "./_SharedNode"; -const { useToken } = theme; - export type BrandNodeProps = SharedNodeProps; const ExecuteResultBranchNode = ({ node, disabled }: BrandNodeProps) => { - const token = useToken(); + const { token: themeToken } = theme.useToken(); const renderBranch = (node: WorkflowNode, branchNodeId?: string, branchIndex?: number) => { const elements: JSX.Element[] = []; @@ -31,7 +29,7 @@ const ExecuteResultBranchNode = ({ node, disabled }: BrandNodeProps) => {
{node.branches?.map((branch, index) => ( @@ -44,13 +42,13 @@ const ExecuteResultBranchNode = ({ node, disabled }: BrandNodeProps) => {
@@ -60,13 +58,13 @@ const ExecuteResultBranchNode = ({ node, disabled }: BrandNodeProps) => {
diff --git a/ui/src/domain/access.ts b/ui/src/domain/access.ts index 1b5adf45..8c011857 100644 --- a/ui/src/domain/access.ts +++ b/ui/src/domain/access.ts @@ -22,6 +22,7 @@ export interface AccessModel extends BaseModel { | AccessConfigForCMCCCloud | AccessConfigForDNSLA | AccessConfigForDogeCloud + | AccessConfigForDynv6 | AccessConfigForEdgio | AccessConfigForGcore | AccessConfigForGname @@ -40,6 +41,7 @@ export interface AccessModel extends BaseModel { | AccessConfigForSSH | AccessConfigForTencentCloud | AccessConfigForUCloud + | AccessConfigForUpyun | AccessConfigForVolcEngine | AccessConfigForWebhook | AccessConfigForWestcn @@ -131,6 +133,10 @@ export type AccessConfigForDogeCloud = { secretKey: string; }; +export type AccessConfigForDynv6 = { + httpToken: string; +}; + export type AccessConfigForEdgio = { clientId: string; clientSecret: string; @@ -224,6 +230,11 @@ export type AccessConfigForUCloud = { projectId?: string; }; +export type AccessConfigForUpyun = { + username: string; + password: string; +}; + export type AccessConfigForVolcEngine = { accessKeyId: string; secretAccessKey: string; diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts index f3d6deb3..999ae22d 100644 --- a/ui/src/domain/provider.ts +++ b/ui/src/domain/provider.ts @@ -20,6 +20,7 @@ export const ACCESS_PROVIDERS = Object.freeze({ CMCCCLOUD: "cmcccloud", DNSLA: "dnsla", DOGECLOUD: "dogecloud", + DYNV6: "dynv6", GCORE: "gcore", GNAME: "gname", GODADDY: "godaddy", @@ -39,6 +40,7 @@ export const ACCESS_PROVIDERS = Object.freeze({ SSH: "ssh", TENCENTCLOUD: "tencentcloud", UCLOUD: "ucloud", + UPYUN: "upyun", VOLCENGINE: "volcengine", WEBHOOK: "webhook", WESTCN: "westcn", @@ -62,9 +64,9 @@ export type AccessProvider = { export const accessProvidersMap: Map = new Map( /* - 注意:此处的顺序决定显示在前端的顺序。 - NOTICE: The following order determines the order displayed at the frontend. - */ + 注意:此处的顺序决定显示在前端的顺序。 + NOTICE: The following order determines the order displayed at the frontend. + */ [ [ACCESS_PROVIDERS.LOCAL, "provider.local", "/imgs/providers/local.svg", [ACCESS_USAGES.DEPLOY]], [ACCESS_PROVIDERS.SSH, "provider.ssh", "/imgs/providers/ssh.svg", [ACCESS_USAGES.DEPLOY]], @@ -77,9 +79,11 @@ export const accessProvidersMap: Map = new Map( /* - 注意:此处的顺序决定显示在前端的顺序。 - NOTICE: The following order determines the order displayed at the frontend. - */ + 注意:此处的顺序决定显示在前端的顺序。 + NOTICE: The following order determines the order displayed at the frontend. + */ [ [APPLY_DNS_PROVIDERS.ALIYUN_DNS, "provider.aliyun.dns"], [APPLY_DNS_PROVIDERS.TENCENTCLOUD_DNS, "provider.tencentcloud.dns"], @@ -183,6 +188,7 @@ export const applyDNSProvidersMap: Map = new Map( /* - 注意:此处的顺序决定显示在前端的顺序。 - NOTICE: The following order determines the order displayed at the frontend. - */ + 注意:此处的顺序决定显示在前端的顺序。 + NOTICE: The following order determines the order displayed at the frontend. + */ [ [DEPLOY_PROVIDERS.LOCAL, "provider.local", DEPLOY_CATEGORIES.OTHER], [DEPLOY_PROVIDERS.SSH, "provider.ssh", DEPLOY_CATEGORIES.OTHER], @@ -317,6 +330,7 @@ export const deployProvidersMap: Map { + nodeId: string; + nodeName: string; + timestamp: ReturnType; + level: "DEBUG" | "INFO" | "WARN" | "ERROR"; + message: string; + data: Record; +} diff --git a/ui/src/domain/workflowRun.ts b/ui/src/domain/workflowRun.ts index 80872b31..6df4a406 100644 --- a/ui/src/domain/workflowRun.ts +++ b/ui/src/domain/workflowRun.ts @@ -6,27 +6,12 @@ export interface WorkflowRunModel extends BaseModel { trigger: string; startedAt: ISO8601String; endedAt: ISO8601String; - logs?: WorkflowRunLog[]; error?: string; expand?: { - workflowId?: WorkflowModel; + workflowId?: WorkflowModel; // TODO: ugly, maybe to use an alias? }; } -export type WorkflowRunLog = { - nodeId: string; - nodeName: string; - records?: WorkflowRunLogRecord[]; - error?: string; -}; - -export type WorkflowRunLogRecord = { - time: ISO8601String; - level: string; - content: string; - error?: string; -}; - export const WORKFLOW_RUN_STATUSES = Object.freeze({ PENDING: "pending", RUNNING: "running", diff --git a/ui/src/i18n/locales/en/nls.access.json b/ui/src/i18n/locales/en/nls.access.json index b3884dd4..54730ada 100644 --- a/ui/src/i18n/locales/en/nls.access.json +++ b/ui/src/i18n/locales/en/nls.access.json @@ -75,6 +75,12 @@ "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.upyun_username.label": "UPYUN subaccount username", + "access.form.upyun_username.placeholder": "Please enter UPYUN subaccount username", + "access.form.upyun_username.tooltip": "For more information, see https://console.upyun.com/account/subaccount/", + "access.form.upyun_password.label": "UPYUN subaccount password", + "access.form.upyun_password.placeholder": "Please enter UPYUN subaccount password", + "access.form.upyun_password.tooltip": "For more information, see https://console.upyun.com/account/subaccount/", "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": "aaPanel URL", @@ -132,6 +138,9 @@ "access.form.dogecloud_secret_key.label": "Doge Cloud SecretKey", "access.form.dogecloud_secret_key.placeholder": "Please enter Doge Cloud SecretKey", "access.form.dogecloud_secret_key.tooltip": "For more information, see https://console.dogecloud.com/", + "access.form.dynv6_http_token.label": "dynv6 HTTP token", + "access.form.dynv6_http_token.placeholder": "Please enter dynv6 HTTP token", + "access.form.dynv6_http_token.tooltip": "For more information, see https://dynv6.com/keys", "access.form.edgio_client_id.label": "Edgio ClientId", "access.form.edgio_client_id.placeholder": "Please enter Edgio ClientId", "access.form.edgio_client_id.tooltip": "For more information, see https://docs.edg.io/applications/v7/rest_api/authentication#administering-api-clients", diff --git a/ui/src/i18n/locales/en/nls.dashboard.json b/ui/src/i18n/locales/en/nls.dashboard.json index 8ae9d94d..38e20e1b 100644 --- a/ui/src/i18n/locales/en/nls.dashboard.json +++ b/ui/src/i18n/locales/en/nls.dashboard.json @@ -8,7 +8,7 @@ "dashboard.statistics.enabled_workflows": "Enabled workflows", "dashboard.statistics.unit": "", - "dashboard.latest_workflow_run": "Latest workflow run", + "dashboard.latest_workflow_runs": "Latest workflow runs", "dashboard.quick_actions": "Quick actions", "dashboard.quick_actions.create_workflow": "Create workflow", diff --git a/ui/src/i18n/locales/en/nls.provider.json b/ui/src/i18n/locales/en/nls.provider.json index 4c6091e1..d68d813f 100644 --- a/ui/src/i18n/locales/en/nls.provider.json +++ b/ui/src/i18n/locales/en/nls.provider.json @@ -5,6 +5,7 @@ "provider.acmehttpreq": "Http Request (ACME Proxy)", "provider.aliyun": "Alibaba Cloud", "provider.aliyun.alb": "Alibaba Cloud - ALB (Application Load Balancer)", + "provider.aliyun.cas": "Alibaba Cloud - CAS (Certificate Management Service)", "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)", @@ -20,10 +21,12 @@ "provider.akamai": "Akamai", "provider.akamai.cdn": "Akamai - CDN (Content Delivery Network)", "provider.aws": "AWS", + "provider.aws.acm": "AWS - ACM (Amazon Certificate Manager)", "provider.aws.cloudfront": "AWS - CloudFront", "provider.aws.route53": "AWS - Route53", "provider.azure": "Azure", "provider.azure.dns": "Azure - DNS", + "provider.azure.keyvault": "Azure - KeyVault", "provider.baiducloud": "Baidu Cloud", "provider.baiducloud.cdn": "Baidu Cloud - CDN (Content Delivery Network)", "provider.baiducloud.dns": "Baidu Cloud - DNS (Domain Name Service)", @@ -44,6 +47,7 @@ "provider.dnsla": "DNS.LA", "provider.dogecloud": "Doge Cloud", "provider.dogecloud.cdn": "Doge Cloud - CDN (Content Delivery Network)", + "provider.dynv6": "dynv6", "provider.edgio": "Edgio", "provider.edgio.applications": "Edgio - Applications", "provider.fastly": "Fastly", @@ -74,6 +78,7 @@ "provider.powerdns": "PowerDNS", "provider.qiniu": "Qiniu", "provider.qiniu.cdn": "Qiniu - CDN (Content Delivery Network)", + "provider.qiniu.kodo": "Qiniu - Kodo", "provider.qiniu.pili": "Qiniu - Pili", "provider.rainyun": "Rain Yun", "provider.safeline": "SafeLine", @@ -87,12 +92,16 @@ "provider.tencentcloud.ecdn": "Tencent Cloud - ECDN (Enterprise Content Delivery Network)", "provider.tencentcloud.eo": "Tencent Cloud - EdgeOne", "provider.tencentcloud.scf": "Tencent Cloud - SCF (Serverless Cloud Function)", + "provider.tencentcloud.ssl": "Tencent Cloud - SSL Certificate Service", "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)", + "provider.upyun": "UPYUN", + "provider.upyun.cdn": "UPYUN - CDN (Content Delivery Network)", + "provider.upyun.file": "UPYUN - File Storage", "provider.volcengine": "Volcengine", "provider.volcengine.cdn": "Volcengine - CDN (Content Delivery Network)", "provider.volcengine.clb": "Volcengine - CLB (Cloud Load Balancer)", diff --git a/ui/src/i18n/locales/en/nls.settings.json b/ui/src/i18n/locales/en/nls.settings.json index f4b3c85f..74e869bd 100644 --- a/ui/src/i18n/locales/en/nls.settings.json +++ b/ui/src/i18n/locales/en/nls.settings.json @@ -90,5 +90,15 @@ "settings.sslprovider.form.gts_eab_kid.tooltip": "For more information, see https://cloud.google.com/certificate-manager/docs/public-ca-tutorial", "settings.sslprovider.form.gts_eab_hmac_key.label": "EAB HMAC Key", "settings.sslprovider.form.gts_eab_hmac_key.placeholder": "Please enter EAB HMAC Key", - "settings.sslprovider.form.gts_eab_hmac_key.tooltip": "For more information, see https://cloud.google.com/certificate-manager/docs/public-ca-tutorial" + "settings.sslprovider.form.gts_eab_hmac_key.tooltip": "For more information, see https://cloud.google.com/certificate-manager/docs/public-ca-tutorial", + + "settings.persistence.tab": "Persistence", + "settings.persistence.form.workflow_runs_max_days.label": "Max days retention of workflow history runs", + "settings.persistence.form.workflow_runs_max_days.placeholder": "Please enter the maximum retention days of workflow history runs", + "settings.persistence.form.workflow_runs_max_days.unit": "days", + "settings.persistence.form.workflow_runs_max_days.extra": "Set to 0 to disable cleanup workflow history runs. It is recommended to set it to 180 days or more.", + "settings.persistence.form.expired_certificates_max_days.label": "Max days retention of expired certificates", + "settings.persistence.form.expired_certificates_max_days.placeholder": "Please enter the maximum retention days of expired certificates", + "settings.persistence.form.expired_certificates_max_days.unit": "days", + "settings.persistence.form.expired_certificates_max_days.extra": "Set to 0 to disable cleanup expired certificates." } diff --git a/ui/src/i18n/locales/en/nls.workflow.nodes.json b/ui/src/i18n/locales/en/nls.workflow.nodes.json index 893e8ddd..69ddba45 100644 --- a/ui/src/i18n/locales/en/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/en/nls.workflow.nodes.json @@ -88,7 +88,7 @@ "workflow_node.deploy.form.provider_access.guide_for_local": "Tips: Due to the form validations, youe need to select an authorization for local deployment also, even if it means nothing.", "workflow_node.deploy.form.certificate.label": "Certificate", "workflow_node.deploy.form.certificate.placeholder": "Please select certificate", - "workflow_node.deploy.form.certificate.tooltip": "The certificate to be deployed comes from the previous application stage node.", + "workflow_node.deploy.form.certificate.tooltip": "The certificate to be deployed comes from the previous nodes of application or upload.", "workflow_node.deploy.form.params_config.label": "Parameter settings", "workflow_node.deploy.form.1panel_console_auto_restart.label": "Auto restart after deployment", "workflow_node.deploy.form.1panel_site_website_id.label": "1Panel website ID", @@ -110,6 +110,9 @@ "workflow_node.deploy.form.aliyun_alb_snidomain.label": "Alibaba Cloud ALB SNI domain (Optional)", "workflow_node.deploy.form.aliyun_alb_snidomain.placeholder": "Please enter Alibaba Cloud ALB SNI domain name", "workflow_node.deploy.form.aliyun_alb_snidomain.tooltip": "For more information, see https://slb.console.aliyun.com/alb", + "workflow_node.deploy.form.aliyun_cas_region.label": "Alibaba Cloud CAS region", + "workflow_node.deploy.form.aliyun_cas_region.placeholder": "Please enter Alibaba Cloud CAS region (e.g. cn-hangzhou)", + "workflow_node.deploy.form.aliyun_cas_region.tooltip": "For more information, see https://www.alibabacloud.com/help/en/ssl-certificate/developer-reference/endpoints", "workflow_node.deploy.form.aliyun_cas_deploy.guide": "TIPS: You need to go to the Alibaba Cloud console to check the actual deployment results by yourself, because Alibaba Cloud deployment tasks are running asynchronously.", "workflow_node.deploy.form.aliyun_cas_deploy_region.label": "Alibaba Cloud CAS region", "workflow_node.deploy.form.aliyun_cas_deploy_region.placeholder": "Please enter Alibaba Cloud CAS region (e.g. cn-hangzhou)", @@ -199,18 +202,26 @@ "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", + "workflow_node.deploy.form.aliyun_waf_service_version.label": "Alibaba Cloud WAF version", + "workflow_node.deploy.form.aliyun_waf_service_version.placeholder": "Please select Alibaba Cloud WAF version", "workflow_node.deploy.form.aliyun_waf_instance_id.label": "Alibaba Cloud WAF instance ID", "workflow_node.deploy.form.aliyun_waf_instance_id.placeholder": "Please enter Alibaba Cloud WAF instance ID", "workflow_node.deploy.form.aliyun_waf_instance_id.tooltip": "For more information, see https://waf.console.aliyun.com", "workflow_node.deploy.form.aliyun_waf_domain.label": "Alibaba Cloud WAF domain (Optional)", "workflow_node.deploy.form.aliyun_waf_domain.placeholder": "Please enter Alibaba Cloud WAF domain name", "workflow_node.deploy.form.aliyun_waf_domain.tooltip": "For more information, see https://waf.console.aliyun.com", + "workflow_node.deploy.form.aws_acm_region.label": "AWS ACM Region", + "workflow_node.deploy.form.aws_acm_region.placeholder": "Please enter AWS ACM region (e.g. us-east-1)", + "workflow_node.deploy.form.aws_acm_region.tooltip": "For more information, see https://docs.aws.amazon.com/en_us/general/latest/gr/rande.html#regional-endpoints", "workflow_node.deploy.form.aws_cloudfront_region.label": "AWS CloudFront Region", "workflow_node.deploy.form.aws_cloudfront_region.placeholder": "Please enter AWS CloudFront region (e.g. us-east-1)", "workflow_node.deploy.form.aws_cloudfront_region.tooltip": "For more information, see https://docs.aws.amazon.com/en_us/general/latest/gr/rande.html#regional-endpoints", "workflow_node.deploy.form.aws_cloudfront_distribution_id.label": "AWS CloudFront distribution ID", "workflow_node.deploy.form.aws_cloudfront_distribution_id.placeholder": "Please enter AWS CloudFront distribution ID", "workflow_node.deploy.form.aws_cloudfront_distribution_id.tooltip": "For more information, see https://docs.aws.amazon.com/en_us/AmazonCloudFront/latest/DeveloperGuide/distribution-working-with.html", + "workflow_node.deploy.form.azure_keyvault_name.label": "Azure KeyVault name", + "workflow_node.deploy.form.azure_keyvault_name.placeholder": "Please enter Azure KeyVault name", + "workflow_node.deploy.form.azure_keyvault_name.tooltip": "For more information, see https://learn.microsoft.com/en-us/azure/key-vault/general/about-keys-secrets-certificates", "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", @@ -361,6 +372,7 @@ "workflow_node.deploy.form.local_post_command.label": "Post-command (Optional)", "workflow_node.deploy.form.local_post_command.placeholder": "Please enter command to be executed after saving files", "workflow_node.deploy.form.local_preset_scripts.button": "Use preset scripts", + "workflow_node.deploy.form.local_preset_scripts.option.backup_files.label": "POSIX Bash - Backup certificate files", "workflow_node.deploy.form.local_preset_scripts.option.reload_nginx.label": "POSIX Bash - Reload nginx", "workflow_node.deploy.form.local_preset_scripts.option.binding_iis.label": "PowerShell - Binding IIS", "workflow_node.deploy.form.local_preset_scripts.option.binding_netsh.label": "PowerShell - Binding netsh", @@ -368,6 +380,9 @@ "workflow_node.deploy.form.qiniu_cdn_domain.label": "Qiniu CDN domain", "workflow_node.deploy.form.qiniu_cdn_domain.placeholder": "Please enter Qiniu CDN domain name", "workflow_node.deploy.form.qiniu_cdn_domain.tooltip": "For more information, see https://portal.qiniu.com/cdn", + "workflow_node.deploy.form.qiniu_kodo_domain.label": "Qiniu Kodo bucket domain", + "workflow_node.deploy.form.qiniu_kodo_domain.placeholder": "Please enter Qiniu Kodo bucket domain name", + "workflow_node.deploy.form.qiniu_kodo_domain.tooltip": "For more information, see https://portal.qiniu.com/kodo", "workflow_node.deploy.form.qiniu_pili_hub.label": "Qiniu Pili hub", "workflow_node.deploy.form.qiniu_pili_hub.placeholder": "Please enter Qiniu Pili hub name", "workflow_node.deploy.form.qiniu_pili_hub.tooltip": "For more information, see https://portal.qiniu.com/hub", @@ -409,6 +424,7 @@ "workflow_node.deploy.form.ssh_post_command.label": "Post-command (Optional)", "workflow_node.deploy.form.ssh_post_command.placeholder": "Please enter command to be executed after uploading files", "workflow_node.deploy.form.ssh_preset_scripts.button": "Use preset scripts", + "workflow_node.deploy.form.ssh_preset_scripts.option.backup_files.label": "POSIX Bash - Backup certificate files", "workflow_node.deploy.form.ssh_preset_scripts.option.reload_nginx.label": "POSIX Bash - Reload nginx", "workflow_node.deploy.form.ssh_use_scp.label": "Fallback to use SCP", "workflow_node.deploy.form.ssh_use_scp.tooltip": "If the remote server does not support SFTP, please enable this option to fallback to SCP.", @@ -506,6 +522,12 @@ "workflow_node.deploy.form.ucloud_us3_domain.label": "UCloud US3 domain", "workflow_node.deploy.form.ucloud_us3_domain.placeholder": "Please enter UCloud US3 domain name", "workflow_node.deploy.form.ucloud_us3_domain.tooltip": "For more information, see https://console.ucloud-global.com/ufile", + "workflow_node.deploy.form.upyun_cdn_domain.label": "UPYUN CDN domain", + "workflow_node.deploy.form.upyun_cdn_domain.placeholder": "Please enter UPYUN CDN domain name", + "workflow_node.deploy.form.upyun_cdn_domain.tooltip": "For more information, see https://console.upyun.com/services/cdn/", + "workflow_node.deploy.form.upyun_file_domain.label": "UPYUN bucket domain", + "workflow_node.deploy.form.upyun_file_domain.placeholder": "Please enter UPYUN bucket domain name", + "workflow_node.deploy.form.upyun_file_domain.tooltip": "For more information, see https://console.upyun.com/services/file/", "workflow_node.deploy.form.volcengine_cdn_domain.label": "VolcEngine CDN domain", "workflow_node.deploy.form.volcengine_cdn_domain.placeholder": "Please enter VolcEngine CDN domain name", "workflow_node.deploy.form.volcengine_cdn_domain.tooltip": "For more information, see https://console.volcengine.com/cdn/homepage", diff --git a/ui/src/i18n/locales/en/nls.workflow.runs.json b/ui/src/i18n/locales/en/nls.workflow.runs.json index d26ddecd..e177dcb3 100644 --- a/ui/src/i18n/locales/en/nls.workflow.runs.json +++ b/ui/src/i18n/locales/en/nls.workflow.runs.json @@ -19,8 +19,10 @@ "workflow_run.props.ended_at": "Ended at", "workflow_run.logs": "Logs", - "workflow_run.artifacts": "Artifacts", + "workflow_run.logs.menu.show_timestamps": "Show timestamps", + "workflow_run.logs.menu.show_whitespaces": "Show whitespaces", + "workflow_run.artifacts": "Artifacts", "workflow_run_artifact.props.type": "Type", "workflow_run_artifact.props.type.certificate": "Certificate", "workflow_run_artifact.props.name": "Name" diff --git a/ui/src/i18n/locales/zh/nls.access.json b/ui/src/i18n/locales/zh/nls.access.json index d72cd259..12c10595 100644 --- a/ui/src/i18n/locales/zh/nls.access.json +++ b/ui/src/i18n/locales/zh/nls.access.json @@ -132,6 +132,9 @@ "access.form.dogecloud_secret_key.label": "多吉云 SecretKey", "access.form.dogecloud_secret_key.placeholder": "请输入多吉云 SecretKey", "access.form.dogecloud_secret_key.tooltip": "这是什么?请参阅 https://console.dogecloud.com/", + "access.form.dynv6_http_token.label": "dynv6 HTTP Token", + "access.form.dynv6_http_token.placeholder": "请输入 dynv6 HTTP Token", + "access.form.dynv6_http_token.tooltip": "这是什么?请参阅 https://dynv6.com/keys", "access.form.edgio_client_id.label": "Edgio 客户端 ID", "access.form.edgio_client_id.placeholder": "请输入 Edgio 客户端 ID", "access.form.edgio_client_id.tooltip": "这是什么?请参阅 https://docs.edg.io/applications/v7/rest_api/authentication#administering-api-clients", @@ -243,6 +246,12 @@ "access.form.ucloud_project_id.label": "优刻得项目 ID(可选)", "access.form.ucloud_project_id.placeholder": "请输入优刻得项目 ID", "access.form.ucloud_project_id.tooltip": "这是什么?请参阅 https://console.ucloud.cn/uaccount/iam/project_manage", + "access.form.upyun_username.label": "又拍云子账号用户名", + "access.form.upyun_username.placeholder": "请输入又拍云子账号用户名", + "access.form.upyun_username.tooltip": "这是什么?请参阅 https://console.upyun.com/account/subaccount/

请关闭该账号的二次登录验证。", + "access.form.upyun_password.label": "又拍云子账号密码", + "access.form.upyun_password.placeholder": "请输入又拍云子账号密码", + "access.form.upyun_password.tooltip": "这是什么?请参阅 https://console.upyun.com/account/subaccount/

请关闭该账号的二次登录验证。", "access.form.volcengine_access_key_id.label": "火山引擎 AccessKeyId", "access.form.volcengine_access_key_id.placeholder": "请输入火山引擎 AccessKeyId", "access.form.volcengine_access_key_id.tooltip": "这是什么?请参阅 https://www.volcengine.com/docs/6291/216571", diff --git a/ui/src/i18n/locales/zh/nls.dashboard.json b/ui/src/i18n/locales/zh/nls.dashboard.json index badd7cb8..30eb5972 100644 --- a/ui/src/i18n/locales/zh/nls.dashboard.json +++ b/ui/src/i18n/locales/zh/nls.dashboard.json @@ -8,7 +8,7 @@ "dashboard.statistics.enabled_workflows": "已启用工作流", "dashboard.statistics.unit": "个", - "dashboard.latest_workflow_run": "最近执行的工作流", + "dashboard.latest_workflow_runs": "最近执行的工作流", "dashboard.quick_actions": "快捷操作", "dashboard.quick_actions.create_workflow": "新建工作流", diff --git a/ui/src/i18n/locales/zh/nls.provider.json b/ui/src/i18n/locales/zh/nls.provider.json index e8580e41..7b7098f9 100644 --- a/ui/src/i18n/locales/zh/nls.provider.json +++ b/ui/src/i18n/locales/zh/nls.provider.json @@ -5,6 +5,7 @@ "provider.acmehttpreq": "Http Request (ACME Proxy)", "provider.aliyun": "阿里云", "provider.aliyun.alb": "阿里云 - 应用型负载均衡 ALB", + "provider.aliyun.cas": "阿里云 - 数字证书管理服务 CAS", "provider.aliyun.cas_deploy": "阿里云 - 通过数字证书管理服务 CAS 创建部署任务", "provider.aliyun.cdn": "阿里云 - 内容分发网络 CDN", "provider.aliyun.clb": "阿里云 - 传统型负载均衡 CLB", @@ -20,10 +21,12 @@ "provider.akamai": "Akamai", "provider.akamai.cdn": "Akamai - 内容分发网络 CDN", "provider.aws": "AWS", + "provider.aws.acm": "AWS - ACM (Amazon Certificate Manager)", "provider.aws.cloudfront": "AWS - CloudFront", "provider.aws.route53": "AWS - Route53", "provider.azure": "Azure", "provider.azure.dns": "Azure - DNS", + "provider.azure.keyvault": "Azure - KeyVault", "provider.baiducloud": "百度智能云", "provider.baiducloud.cdn": "百度智能云 - 内容分发网络 CDN", "provider.baiducloud.dns": "百度智能云 - 智能云解析 DNS", @@ -44,6 +47,7 @@ "provider.dnsla": "DNS.LA", "provider.dogecloud": "多吉云", "provider.dogecloud.cdn": "多吉云 - 内容分发网络 CDN", + "provider.dynv6": "dynv6", "provider.edgio": "Edgio", "provider.edgio.applications": "Edgio - Applications", "provider.fastly": "Fastly", @@ -74,6 +78,7 @@ "provider.powerdns": "PowerDNS", "provider.qiniu": "七牛云", "provider.qiniu.cdn": "七牛云 - 内容分发网络 CDN", + "provider.qiniu.kodo": "七牛云 - 对象存储 Kodo", "provider.qiniu.pili": "七牛云 - 视频直播 Pili", "provider.rainyun": "雨云", "provider.safeline": "雷池", @@ -87,12 +92,16 @@ "provider.tencentcloud.ecdn": "腾讯云 - 全站加速网络 ECDN", "provider.tencentcloud.eo": "腾讯云 - 边缘安全加速平台 EdgeOne", "provider.tencentcloud.scf": "腾讯云 - 云函数 SCF", + "provider.tencentcloud.ssl": "腾讯云 - SSL 证书服务", "provider.tencentcloud.ssl_deploy": "腾讯云 - 通过 SSL 证书服务创建部署任务", "provider.tencentcloud.vod": "腾讯云 - 云点播 VOD", "provider.tencentcloud.waf": "腾讯云 - Web 应用防火墙 WAF", "provider.ucloud": "优刻得", "provider.ucloud.ucdn": "优刻得 - 内容分发 UCDN", "provider.ucloud.us3": "优刻得 - 对象存储 US3", + "provider.upyun": "又拍云", + "provider.upyun.cdn": "又拍云 - 云分发 CDN", + "provider.upyun.file": "又拍云 - 云存储", "provider.volcengine": "火山引擎", "provider.volcengine.cdn": "火山引擎 - 内容分发网络 CDN", "provider.volcengine.clb": "火山引擎 - 负载均衡 CLB", diff --git a/ui/src/i18n/locales/zh/nls.settings.json b/ui/src/i18n/locales/zh/nls.settings.json index 1fcec35d..0c51d33e 100644 --- a/ui/src/i18n/locales/zh/nls.settings.json +++ b/ui/src/i18n/locales/zh/nls.settings.json @@ -71,7 +71,7 @@ "settings.notification.channel.form.wecom_webhook_url.placeholder": "请输入机器人 Webhook 地址", "settings.notification.channel.form.wecom_webhook_url.tooltip": "这是什么?请参阅 https://open.work.weixin.qq.com/help2/pc/18401", - "settings.sslprovider.tab": "证书颁发机构(CA)", + "settings.sslprovider.tab": "证书颁发机构", "settings.sslprovider.form.provider.label": "ACME 服务商", "settings.sslprovider.form.provider.option.letsencrypt.label": "Let's Encrypt", "settings.sslprovider.form.provider.option.letsencrypt_staging.label": "Let's Encrypt 测试环境", @@ -90,5 +90,15 @@ "settings.sslprovider.form.gts_eab_kid.tooltip": "这是什么?请参阅 https://cloud.google.com/certificate-manager/docs/public-ca-tutorial", "settings.sslprovider.form.gts_eab_hmac_key.label": "EAB HMAC Key", "settings.sslprovider.form.gts_eab_hmac_key.placeholder": "请输入 EAB HMAC Key", - "settings.sslprovider.form.gts_eab_hmac_key.tooltip": "这是什么?请参阅 https://cloud.google.com/certificate-manager/docs/public-ca-tutorial" + "settings.sslprovider.form.gts_eab_hmac_key.tooltip": "这是什么?请参阅 https://cloud.google.com/certificate-manager/docs/public-ca-tutorial", + + "settings.persistence.tab": "数据持久化", + "settings.persistence.form.workflow_runs_max_days.label": "工作流执行历史保留天数", + "settings.persistence.form.workflow_runs_max_days.placeholder": "请输入执行历史保留天数", + "settings.persistence.form.workflow_runs_max_days.unit": "天", + "settings.persistence.form.workflow_runs_max_days.extra": "设置为 0 表示永久保留,不会自动清理。建议设置为 180 天以上。", + "settings.persistence.form.expired_certificates_max_days.label": "证书过期后保留天数", + "settings.persistence.form.expired_certificates_max_days.placeholder": "请输入过期证书保留天数", + "settings.persistence.form.expired_certificates_max_days.unit": "天", + "settings.persistence.form.expired_certificates_max_days.extra": "设置为 0 表示永久保留,不会自动清理。" } diff --git a/ui/src/i18n/locales/zh/nls.workflow.nodes.json b/ui/src/i18n/locales/zh/nls.workflow.nodes.json index a2ff6c8e..afc1db09 100644 --- a/ui/src/i18n/locales/zh/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/zh/nls.workflow.nodes.json @@ -39,7 +39,7 @@ "workflow_node.apply.form.provider_access.button": "新建", "workflow_node.apply.form.aws_route53_region.label": "AWS Route53 服务区域", "workflow_node.apply.form.aws_route53_region.placeholder": "请输入 AWS Route53 服务区域(例如:us-east-1)", - "workflow_node.apply.form.aws_route53_region.tooltip": "这是什么?请参阅 https://docs.aws.amazon.com/zh_cn/general/latest/gr/rande.html#regional-endpoints", + "workflow_node.apply.form.aws_route53_region.tooltip": "这是什么?请参阅 https://docs.aws.amazon.com/zh_cn/general/latest/gr/rande.html#regional-endpoints", "workflow_node.apply.form.aws_route53_hosted_zone_id.label": "AWS Route53 托管区域 ID", "workflow_node.apply.form.aws_route53_hosted_zone_id.placeholder": "请输入 AWS Route53 托管区域 ID", "workflow_node.apply.form.aws_route53_hosted_zone_id.tooltip": "这是什么?请参阅 https://docs.aws.amazon.com/zh_cn/Route53/latest/DeveloperGuide/hosted-zones-working-with.html", @@ -85,10 +85,10 @@ "workflow_node.deploy.form.provider_access.placeholder": "请选择主机提供商授权", "workflow_node.deploy.form.provider_access.tooltip": "用于部署证书,注意与申请阶段所需的 DNS 提供商相区分。", "workflow_node.deploy.form.provider_access.button": "新建", - "workflow_node.deploy.form.provider_access.guide_for_local": "小贴士:由于表单限制,你同样需要为本地部署选择一个授权 —— 即使它是空白的。
请注意:如果你使用 Docker 安装 Certimate,“本地部署”将会部署到容器内而非宿主机上。", + "workflow_node.deploy.form.provider_access.guide_for_local": "小贴士:由于表单限制,你同样需要为本地部署选择一个授权 —— 即使它是空白的。
请注意,如果你使用 Docker 安装 Certimate,“本地部署”将会部署到容器内而非宿主机上。", "workflow_node.deploy.form.certificate.label": "待部署证书", "workflow_node.deploy.form.certificate.placeholder": "请选择待部署证书", - "workflow_node.deploy.form.certificate.tooltip": "待部署证书来自之前的申请阶段。如果选项为空请先确保前序节点配置正确。", + "workflow_node.deploy.form.certificate.tooltip": "待部署证书来自之前的申请或上传节点。如果选项为空请先确保前序节点配置正确。", "workflow_node.deploy.form.params_config.label": "参数设置", "workflow_node.deploy.form.1panel_console_auto_restart.label": "部署后自动重启面板服务", "workflow_node.deploy.form.1panel_site_website_id.label": "1Panel 网站 ID", @@ -110,6 +110,9 @@ "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.tooltip": "这是什么?请参阅 https://slb.console.aliyun.com/alb

不填写时,将替换监听器的默认证书。", + "workflow_node.deploy.form.aliyun_cas_region.label": "阿里云 CAS 服务地域", + "workflow_node.deploy.form.aliyun_cas_region.placeholder": "请输入阿里云 CAS 服务地域(例如:cn-hangzhou)", + "workflow_node.deploy.form.aliyun_cas_region.tooltip": "这是什么?请参阅 https://help.aliyun.com/zh/ssl-certificate/developer-reference/endpoints", "workflow_node.deploy.form.aliyun_cas_deploy.guide": "小贴士:由于阿里云证书部署任务是异步的,此节点若执行成功仅代表已创建部署任务,实际部署结果需要你自行前往阿里云控制台查询。", "workflow_node.deploy.form.aliyun_cas_deploy_region.label": "阿里云 CAS 服务地域", "workflow_node.deploy.form.aliyun_cas_deploy_region.placeholder": "请输入阿里云 CAS 服务地域(例如:cn-hangzhou)", @@ -199,18 +202,26 @@ "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", + "workflow_node.deploy.form.aliyun_waf_service_version.label": "阿里云 WAF 服务版本", + "workflow_node.deploy.form.aliyun_waf_service_version.placeholder": "请选择阿里云 WAF 服务版本", "workflow_node.deploy.form.aliyun_waf_instance_id.label": "阿里云 WAF 实例 ID", "workflow_node.deploy.form.aliyun_waf_instance_id.placeholder": "请输入阿里云 WAF 实例 ID", "workflow_node.deploy.form.aliyun_waf_instance_id.tooltip": "这是什么?请参阅 https://waf.console.aliyun.com

仅支持 CNAME 接入。", "workflow_node.deploy.form.aliyun_waf_domain.label": "阿里云 WAF 接入域名(可选)", "workflow_node.deploy.form.aliyun_waf_domain.placeholder": "请输入阿里云 WAF 接入域名(支持泛域名)", "workflow_node.deploy.form.aliyun_waf_domain.tooltip": "这是什么?请参阅 waf.console.aliyun.com

不填写时,将替换实例的默认证书。", + "workflow_node.deploy.form.aws_acm_region.label": "AWS ACM 服务区域", + "workflow_node.deploy.form.aws_acm_region.placeholder": "请输入 AWS ACM 服务区域(例如:us-east-1)", + "workflow_node.deploy.form.aws_acm_region.tooltip": "这是什么?请参阅 https://docs.aws.amazon.com/zh_cn/general/latest/gr/rande.html#regional-endpoints", "workflow_node.deploy.form.aws_cloudfront_region.label": "AWS CloudFront 服务区域", "workflow_node.deploy.form.aws_cloudfront_region.placeholder": "请输入 AWS CloudFront 服务区域(例如:us-east-1)", - "workflow_node.deploy.form.aws_cloudfront_region.tooltip": "这是什么?请参阅 https://docs.aws.amazon.com/zh_cn/general/latest/gr/rande.html#regional-endpoints", + "workflow_node.deploy.form.aws_cloudfront_region.tooltip": "这是什么?请参阅 https://docs.aws.amazon.com/zh_cn/general/latest/gr/rande.html#regional-endpoints", "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.azure_keyvault_name.label": "Azure KeyVault 名称", + "workflow_node.deploy.form.azure_keyvault_name.placeholder": "请输入 Azure KeyVault 名称", + "workflow_node.deploy.form.azure_keyvault_name.tooltip": "这是什么?请参阅 https://learn.microsoft.com/zh-cn/azure/key-vault/general/about-keys-secrets-certificates", "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", @@ -361,6 +372,7 @@ "workflow_node.deploy.form.local_post_command.label": "后置命令(可选)", "workflow_node.deploy.form.local_post_command.placeholder": "请输入保存文件后执行的命令", "workflow_node.deploy.form.local_preset_scripts.button": "使用预设脚本", + "workflow_node.deploy.form.local_preset_scripts.option.backup_files.label": "POSIX Bash - 备份原证书文件", "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(需管理员权限)", @@ -368,6 +380,9 @@ "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_kodo_domain.label": "七牛云对象存储加速域名", + "workflow_node.deploy.form.qiniu_kodo_domain.placeholder": "请输入七牛云对象存储加速域名", + "workflow_node.deploy.form.qiniu_kodo_domain.tooltip": "这是什么?请参阅 https://portal.qiniu.com/kodo", "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", @@ -409,6 +424,7 @@ "workflow_node.deploy.form.ssh_post_command.label": "后置命令(可选)", "workflow_node.deploy.form.ssh_post_command.placeholder": "请输入保存文件后执行的命令", "workflow_node.deploy.form.ssh_preset_scripts.button": "使用预设脚本", + "workflow_node.deploy.form.ssh_preset_scripts.option.backup_files.label": "POSIX Bash - 备份原证书文件", "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。", @@ -506,6 +522,12 @@ "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.upyun_cdn_domain.label": "又拍云 CDN 加速域名", + "workflow_node.deploy.form.upyun_cdn_domain.placeholder": "请输入又拍云 CDN 加速域名(支持泛域名)", + "workflow_node.deploy.form.upyun_cdn_domain.tooltip": "这是什么?请参阅 https://console.upyun.com/services/cdn/", + "workflow_node.deploy.form.upyun_file_domain.label": "又拍云云存储加速域名", + "workflow_node.deploy.form.upyun_file_domain.placeholder": "请输入又拍云云存储加速域名", + "workflow_node.deploy.form.upyun_file_domain.tooltip": "这是什么?请参阅 https://console.upyun.com/services/file/", "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", diff --git a/ui/src/i18n/locales/zh/nls.workflow.runs.json b/ui/src/i18n/locales/zh/nls.workflow.runs.json index e3928f24..79d46abe 100644 --- a/ui/src/i18n/locales/zh/nls.workflow.runs.json +++ b/ui/src/i18n/locales/zh/nls.workflow.runs.json @@ -19,8 +19,10 @@ "workflow_run.props.ended_at": "完成时间", "workflow_run.logs": "日志", - "workflow_run.artifacts": "输出产物", + "workflow_run.logs.menu.show_timestamps": "显示日期时间", + "workflow_run.logs.menu.show_whitespaces": "显示转义换行符", + "workflow_run.artifacts": "输出产物", "workflow_run_artifact.props.type": "类型", "workflow_run_artifact.props.type.certificate": "证书", "workflow_run_artifact.props.name": "名称" diff --git a/ui/src/pages/certificates/CertificateList.tsx b/ui/src/pages/certificates/CertificateList.tsx index 265f0185..049069a3 100644 --- a/ui/src/pages/certificates/CertificateList.tsx +++ b/ui/src/pages/certificates/CertificateList.tsx @@ -28,7 +28,7 @@ import { ClientResponseError } from "pocketbase"; import CertificateDetailDrawer from "@/components/certificate/CertificateDetailDrawer"; import { CERTIFICATE_SOURCES, type CertificateModel } from "@/domain/certificate"; -import { type ListCertificateRequest, list as listCertificate, remove as removeCertificate } from "@/repository/certificate"; +import { list as listCertificates, type ListRequest as listCertificatesRequest, remove as removeCertificate } from "@/repository/certificate"; import { getErrMsg } from "@/utils/error"; const CertificateList = () => { @@ -223,9 +223,9 @@ const CertificateList = () => { run: refreshData, } = useRequest( () => { - return listCertificate({ + return listCertificates({ keyword: filters["keyword"] as string, - state: filters["state"] as ListCertificateRequest["state"], + state: filters["state"] as listCertificatesRequest["state"], page: page, perPage: pageSize, }); diff --git a/ui/src/pages/dashboard/Dashboard.tsx b/ui/src/pages/dashboard/Dashboard.tsx index ea7a21cb..83f8cd47 100644 --- a/ui/src/pages/dashboard/Dashboard.tsx +++ b/ui/src/pages/dashboard/Dashboard.tsx @@ -275,7 +275,7 @@ const Dashboard = () => { - + columns={tableColumns} dataSource={tableData} diff --git a/ui/src/pages/settings/Settings.tsx b/ui/src/pages/settings/Settings.tsx index dcd4ef14..be72efc0 100644 --- a/ui/src/pages/settings/Settings.tsx +++ b/ui/src/pages/settings/Settings.tsx @@ -3,6 +3,7 @@ import { useTranslation } from "react-i18next"; import { Outlet, useLocation, useNavigate } from "react-router-dom"; import { ApiOutlined as ApiOutlinedIcon, + DatabaseOutlined as DatabaseOutlinedIcon, LockOutlined as LockOutlinedIcon, SendOutlined as SendOutlinedIcon, UserOutlined as UserOutlinedIcon, @@ -69,6 +70,15 @@ const Settings = () => { ), }, + { + key: "persistence", + label: ( + + + + + ), + }, ]} activeTabKey={tabValue} onTabChange={(key) => { diff --git a/ui/src/pages/settings/SettingsAccount.tsx b/ui/src/pages/settings/SettingsAccount.tsx index aedd746a..734e8bce 100644 --- a/ui/src/pages/settings/SettingsAccount.tsx +++ b/ui/src/pages/settings/SettingsAccount.tsx @@ -18,7 +18,7 @@ const SettingsAccount = () => { const [notificationApi, NotificationContextHolder] = notification.useNotification(); const formSchema = z.object({ - username: z.string({ message: "settings.account.form.email.placeholder" }).email({ message: t("common.errmsg.email_invalid") }), + username: z.string({ message: t("settings.account.form.email.placeholder") }).email({ message: t("common.errmsg.email_invalid") }), }); const formRule = createSchemaFieldRule(formSchema); const { diff --git a/ui/src/pages/settings/SettingsPersistence.tsx b/ui/src/pages/settings/SettingsPersistence.tsx new file mode 100644 index 00000000..e75ed8a3 --- /dev/null +++ b/ui/src/pages/settings/SettingsPersistence.tsx @@ -0,0 +1,132 @@ +import { useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { Button, Form, InputNumber, Skeleton, message, notification } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { produce } from "immer"; +import { z } from "zod"; + +import Show from "@/components/Show"; +import { type PersistenceSettingsContent, SETTINGS_NAMES, type SettingsModel } from "@/domain/settings"; +import { useAntdForm } from "@/hooks"; +import { get as getSettings, save as saveSettings } from "@/repository/settings"; +import { getErrMsg } from "@/utils/error"; + +const SettingsPersistence = () => { + const { t } = useTranslation(); + + const [messageApi, MessageContextHolder] = message.useMessage(); + const [notificationApi, NotificationContextHolder] = notification.useNotification(); + + const [settings, setSettings] = useState>(); + const [loading, setLoading] = useState(true); + useEffect(() => { + const fetchData = async () => { + setLoading(true); + + const settings = await getSettings(SETTINGS_NAMES.PERSISTENCE); + setSettings(settings); + + setLoading(false); + }; + + fetchData(); + }, []); + + const formSchema = z.object({ + workflowRunsMaxDaysRetention: z + .number({ message: t("settings.persistence.form.workflow_runs_max_days.placeholder") }) + .gte(0, t("settings.persistence.form.workflow_runs_max_days.placeholder")), + expiredCertificatesMaxDaysRetention: z + .number({ message: t("settings.persistence.form.expired_certificates_max_days.placeholder") }) + .gte(0, t("settings.persistence.form.expired_certificates_max_days.placeholder")), + }); + const formRule = createSchemaFieldRule(formSchema); + const { + form: formInst, + formPending, + formProps, + } = useAntdForm>({ + initialValues: { + workflowRunsMaxDaysRetention: settings?.content?.workflowRunsMaxDaysRetention ?? 0, + expiredCertificatesMaxDaysRetention: settings?.content?.expiredCertificatesMaxDaysRetention ?? 0, + }, + onSubmit: async (values) => { + try { + await saveSettings( + produce(settings!, (draft) => { + draft.content ??= {} as PersistenceSettingsContent; + draft.content.workflowRunsMaxDaysRetention = values.workflowRunsMaxDaysRetention; + draft.content.expiredCertificatesMaxDaysRetention = values.expiredCertificatesMaxDaysRetention; + }) + ); + + messageApi.success(t("common.text.operation_succeeded")); + } catch (err) { + notificationApi.error({ message: t("common.text.request_error"), description: getErrMsg(err) }); + + throw err; + } + }, + }); + const [formChanged, setFormChanged] = useState(false); + + const handleInputChange = () => { + const changed = + formInst.getFieldValue("workflowRunsMaxDaysRetention") !== formProps.initialValues?.workflowRunsMaxDaysRetention || + formInst.getFieldValue("expiredCertificatesMaxDaysRetention") !== formProps.initialValues?.workflowRunsMaxDaysRetention; + setFormChanged(changed); + }; + + return ( + <> + {MessageContextHolder} + {NotificationContextHolder} + + }> +
+
+ } + rules={[formRule]} + > + + + + } + rules={[formRule]} + > + + + + + + +
+
+
+ + ); +}; + +export default SettingsPersistence; diff --git a/ui/src/pages/workflows/WorkflowList.tsx b/ui/src/pages/workflows/WorkflowList.tsx index 18a8b577..09bca7fc 100644 --- a/ui/src/pages/workflows/WorkflowList.tsx +++ b/ui/src/pages/workflows/WorkflowList.tsx @@ -41,7 +41,7 @@ import { ClientResponseError } from "pocketbase"; import { WORKFLOW_TRIGGERS, type WorkflowModel, isAllNodesValidated } from "@/domain/workflow"; import { WORKFLOW_RUN_STATUSES } from "@/domain/workflowRun"; -import { list as listWorkflow, remove as removeWorkflow, save as saveWorkflow } from "@/repository/workflow"; +import { list as listWorkflows, remove as removeWorkflow, save as saveWorkflow } from "@/repository/workflow"; import { getErrMsg } from "@/utils/error"; const WorkflowList = () => { @@ -253,7 +253,7 @@ const WorkflowList = () => { run: refreshData, } = useRequest( () => { - return listWorkflow({ + return listWorkflows({ keyword: filters["keyword"] as string, enabled: (filters["state"] as string) === "enabled" ? true : (filters["state"] as string) === "disabled" ? false : undefined, page: page, diff --git a/ui/src/repository/_pocketbase.ts b/ui/src/repository/_pocketbase.ts index 983c4987..85068f50 100644 --- a/ui/src/repository/_pocketbase.ts +++ b/ui/src/repository/_pocketbase.ts @@ -14,3 +14,4 @@ export const COLLECTION_NAME_SETTINGS = "settings"; export const COLLECTION_NAME_WORKFLOW = "workflow"; export const COLLECTION_NAME_WORKFLOW_RUN = "workflow_run"; export const COLLECTION_NAME_WORKFLOW_OUTPUT = "workflow_output"; +export const COLLECTION_NAME_WORKFLOW_LOG = "workflow_logs"; diff --git a/ui/src/repository/certificate.ts b/ui/src/repository/certificate.ts index b6b8d55e..95b9fb82 100644 --- a/ui/src/repository/certificate.ts +++ b/ui/src/repository/certificate.ts @@ -3,14 +3,14 @@ import dayjs from "dayjs"; import { type CertificateModel } from "@/domain/certificate"; import { COLLECTION_NAME_CERTIFICATE, getPocketBase } from "./_pocketbase"; -export type ListCertificateRequest = { +export type ListRequest = { keyword?: string; state?: "expireSoon" | "expired"; page?: number; perPage?: number; }; -export const list = async (request: ListCertificateRequest) => { +export const list = async (request: ListRequest) => { const pb = getPocketBase(); const filters: string[] = ["deleted=null"]; @@ -39,7 +39,7 @@ export const listByWorkflowRunId = async (workflowRunId: string) => { const list = await pb.collection(COLLECTION_NAME_CERTIFICATE).getFullList({ batch: 65535, filter: pb.filter("workflowRunId={:workflowRunId}", { workflowRunId: workflowRunId }), - sort: "-created", + sort: "created", requestKey: null, }); diff --git a/ui/src/repository/workflow.ts b/ui/src/repository/workflow.ts index 0b35a5e2..5701927c 100644 --- a/ui/src/repository/workflow.ts +++ b/ui/src/repository/workflow.ts @@ -3,14 +3,14 @@ import { type RecordSubscription } from "pocketbase"; import { type WorkflowModel } from "@/domain/workflow"; import { COLLECTION_NAME_WORKFLOW, getPocketBase } from "./_pocketbase"; -export type ListWorkflowRequest = { +export type ListRequest = { keyword?: string; enabled?: boolean; page?: number; perPage?: number; }; -export const list = async (request: ListWorkflowRequest) => { +export const list = async (request: ListRequest) => { const pb = getPocketBase(); const filters: string[] = []; diff --git a/ui/src/repository/workflowLog.ts b/ui/src/repository/workflowLog.ts new file mode 100644 index 00000000..683b4b03 --- /dev/null +++ b/ui/src/repository/workflowLog.ts @@ -0,0 +1,19 @@ +import { type WorkflowLogModel } from "@/domain/workflowLog"; + +import { COLLECTION_NAME_WORKFLOW_LOG, getPocketBase } from "./_pocketbase"; + +export const listByWorkflowRunId = async (workflowRunId: string) => { + const pb = getPocketBase(); + + const list = await pb.collection(COLLECTION_NAME_WORKFLOW_LOG).getFullList({ + batch: 65535, + filter: pb.filter("runId={:runId}", { runId: workflowRunId }), + sort: "timestamp", + requestKey: null, + }); + + return { + totalItems: list.length, + items: list, + }; +}; diff --git a/ui/src/repository/workflowRun.ts b/ui/src/repository/workflowRun.ts index 51038f18..22c69802 100644 --- a/ui/src/repository/workflowRun.ts +++ b/ui/src/repository/workflowRun.ts @@ -4,14 +4,14 @@ import { type WorkflowRunModel } from "@/domain/workflowRun"; import { COLLECTION_NAME_WORKFLOW_RUN, getPocketBase } from "./_pocketbase"; -export type ListWorkflowRunsRequest = { +export type ListRequest = { workflowId?: string; page?: number; perPage?: number; expand?: boolean; }; -export const list = async (request: ListWorkflowRunsRequest) => { +export const list = async (request: ListRequest) => { const pb = getPocketBase(); const filters: string[] = []; diff --git a/ui/src/router.tsx b/ui/src/router.tsx index 0bfa8b41..923f7f6f 100644 --- a/ui/src/router.tsx +++ b/ui/src/router.tsx @@ -10,6 +10,7 @@ import Settings from "./pages/settings/Settings"; import SettingsAccount from "./pages/settings/SettingsAccount"; import SettingsNotification from "./pages/settings/SettingsNotification"; import SettingsPassword from "./pages/settings/SettingsPassword"; +import SettingsPersistence from "./pages/settings/SettingsPersistence"; import SettingsSSLProvider from "./pages/settings/SettingsSSLProvider"; import WorkflowDetail from "./pages/workflows/WorkflowDetail"; import WorkflowList from "./pages/workflows/WorkflowList"; @@ -64,6 +65,10 @@ export const router = createHashRouter([ path: "/settings/ssl-provider", element: , }, + { + path: "/settings/persistence", + element: , + }, ], }, ], diff --git a/ui/src/stores/access/index.ts b/ui/src/stores/access/index.ts index 61601978..55d8835a 100644 --- a/ui/src/stores/access/index.ts +++ b/ui/src/stores/access/index.ts @@ -2,7 +2,7 @@ import { create } from "zustand"; import { type AccessModel } from "@/domain/access"; -import { list as listAccess, remove as removeAccess, save as saveAccess } from "@/repository/access"; +import { list as listAccesses, remove as removeAccess, save as saveAccess } from "@/repository/access"; export interface AccessesState { accesses: AccessModel[]; @@ -24,7 +24,7 @@ export const useAccessesStore = create((set) => { loadedAtOnce: false, fetchAccesses: async () => { - fetcher ??= listAccess().then((res) => res.items); + fetcher ??= listAccesses().then((res) => res.items); try { set({ loading: true });