From 369c146ecad2182f2371498c0455509a8768e320 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Thu, 31 Oct 2024 13:24:43 +0800 Subject: [PATCH] feat: support tencent clb deployment in multiple ways --- go.mod | 7 +- go.sum | 7 +- internal/deployer/huaweicloud_cdn.go | 30 +- internal/deployer/huaweicloud_elb.go | 6 +- internal/deployer/tencent_clb.go | 207 ++++++++++- .../certimate/DeployToTencentCLB.tsx | 320 ++++++++---------- ui/src/i18n/locales/en/nls.common.json | 2 +- ui/src/i18n/locales/en/nls.domain.json | 15 +- ui/src/i18n/locales/zh/nls.common.json | 3 +- ui/src/i18n/locales/zh/nls.domain.json | 30 +- 10 files changed, 394 insertions(+), 233 deletions(-) diff --git a/go.mod b/go.mod index a567360f..7c710d35 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,6 @@ require ( github.com/alibabacloud-go/nlb-20220430/v2 v2.0.3 github.com/alibabacloud-go/slb-20140515/v4 v4.0.9 github.com/alibabacloud-go/tea v1.2.2 - github.com/alibabacloud-go/tea-utils/v2 v2.0.6 github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible github.com/go-acme/lego/v4 v4.19.2 github.com/gojek/heimdall/v7 v7.0.3 @@ -25,7 +24,8 @@ require ( github.com/pocketbase/pocketbase v0.22.18 github.com/qiniu/go-sdk/v7 v7.22.0 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1017 - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1030 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1031 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1031 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.992 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1030 golang.org/x/crypto v0.28.0 @@ -41,6 +41,7 @@ require ( github.com/alibabacloud-go/tea-fileform v1.1.1 // indirect github.com/alibabacloud-go/tea-oss-sdk v1.1.3 // indirect github.com/alibabacloud-go/tea-oss-utils v1.1.0 // indirect + github.com/alibabacloud-go/tea-utils/v2 v2.0.6 // indirect github.com/aws/aws-sdk-go-v2/service/route53 v1.43.2 // indirect github.com/blinkbean/dingtalk v1.1.3 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect @@ -141,7 +142,7 @@ require ( github.com/ncruces/go-strftime v0.1.9 // indirect github.com/nrdcg/namesilo v0.2.1 // indirect github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect - github.com/pkg/errors v0.9.1 // indirect + github.com/pkg/errors v0.9.1 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/spf13/cast v1.6.0 // indirect github.com/spf13/cobra v1.8.1 // indirect diff --git a/go.sum b/go.sum index 08ae184b..d93ba3da 100644 --- a/go.sum +++ b/go.sum @@ -204,8 +204,6 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I= -github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s= github.com/gabriel-vasile/mimetype v1.4.6 h1:3+PzJTKLkvgjeTbts6msPJt4DixhT4YtFNf1gtGe3zc= github.com/gabriel-vasile/mimetype v1.4.6/go.mod h1:JX1qVKqZd40hUPpAfiNTe0Sne7hdfKSbOqqmkq8GCXc= github.com/gammazero/toposort v0.1.1/go.mod h1:H2cozTnNpMw0hg2VHAYsAxmkHXBYroNangj2NTBQDvw= @@ -460,11 +458,14 @@ 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.1017 h1:OymmfmyFkvHirY3WHsoRT3cdTEsqygLbMn8jM41erK4= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1017/go.mod h1:gnLxGXlLmF+jDqWR1/RVoF/UUwxQxomQhkc0oN7KeuI= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1031 h1:/eVMCl+jadCex6HxNN6/hFbC0iWl+e8s4PSIcI8aqS4= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1031/go.mod h1:8Km0fRIaDS7PssuyxDFvRRFBUFmECqG+ICpViCs/Vak= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.992/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1002/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1017/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1030 h1:kwiUoCkooUgy7iPyhEEbio7WT21kGJUeZ5JeJfb/dYk= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1030/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1031 h1:3ouglYKE5cwhx2vwICGeW7pAlwyCLnpQd7O0l3hCSTg= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1031/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1002 h1:QwE0dRkAAbdf+eACnkNULgDn9ZKUJpPWRyXdqJolP5E= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1002/go.mod h1:WdC0FYbqYhJwQ3kbqri6hVP5HAEp+rzX9FToItTAzUg= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.992 h1:A6O89OlCJQUpNxGqC/E5By04UNKBryIt5olQIGOx8mg= diff --git a/internal/deployer/huaweicloud_cdn.go b/internal/deployer/huaweicloud_cdn.go index ff7b4328..3406b65a 100644 --- a/internal/deployer/huaweicloud_cdn.go +++ b/internal/deployer/huaweicloud_cdn.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "fmt" - "time" "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/global" hcCdn "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/cdn/v2" @@ -67,6 +66,14 @@ func (d *HuaweiCloudCDNDeployer) GetInfos() []string { } func (d *HuaweiCloudCDNDeployer) Deploy(ctx context.Context) error { + // 上传证书到 SCM + upres, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey) + if err != nil { + return err + } + + d.infos = append(d.infos, toStr("已上传证书", upres)) + // 查询加速域名配置 // REF: https://support.huaweicloud.com/api-cdn/ShowDomainFullConfig.html showDomainFullConfigReq := &hcCdnModel.ShowDomainFullConfigRequest{ @@ -85,24 +92,9 @@ func (d *HuaweiCloudCDNDeployer) Deploy(ctx context.Context) error { updateDomainMultiCertificatesReqBodyContent := &hcCdnEx.UpdateDomainMultiCertificatesExRequestBodyContent{} updateDomainMultiCertificatesReqBodyContent.DomainName = d.option.DeployConfig.GetConfigAsString("domain") updateDomainMultiCertificatesReqBodyContent.HttpsSwitch = 1 - if d.option.DeployConfig.GetConfigAsBool("useSCM") { - // 上传证书到 SCM - upres, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey) - if err != nil { - return err - } - - d.infos = append(d.infos, toStr("已上传证书", upres)) - - updateDomainMultiCertificatesReqBodyContent.CertificateType = cast.Int32Ptr(2) - updateDomainMultiCertificatesReqBodyContent.SCMCertificateId = cast.StringPtr(upres.CertId) - updateDomainMultiCertificatesReqBodyContent.CertName = cast.StringPtr(upres.CertName) - } else { - updateDomainMultiCertificatesReqBodyContent.CertificateType = cast.Int32Ptr(0) - updateDomainMultiCertificatesReqBodyContent.CertName = cast.StringPtr(fmt.Sprintf("certimate-%d", time.Now().UnixMilli())) - updateDomainMultiCertificatesReqBodyContent.Certificate = cast.StringPtr(d.option.Certificate.Certificate) - updateDomainMultiCertificatesReqBodyContent.PrivateKey = cast.StringPtr(d.option.Certificate.PrivateKey) - } + updateDomainMultiCertificatesReqBodyContent.CertificateType = cast.Int32Ptr(2) + updateDomainMultiCertificatesReqBodyContent.SCMCertificateId = cast.StringPtr(upres.CertId) + updateDomainMultiCertificatesReqBodyContent.CertName = cast.StringPtr(upres.CertName) updateDomainMultiCertificatesReqBodyContent = updateDomainMultiCertificatesReqBodyContent.MergeConfig(showDomainFullConfigResp.Configs) updateDomainMultiCertificatesReq := &hcCdnEx.UpdateDomainMultiCertificatesExRequest{ Body: &hcCdnEx.UpdateDomainMultiCertificatesExRequestBody{ diff --git a/internal/deployer/huaweicloud_elb.go b/internal/deployer/huaweicloud_elb.go index 05b94956..e813610f 100644 --- a/internal/deployer/huaweicloud_elb.go +++ b/internal/deployer/huaweicloud_elb.go @@ -268,7 +268,7 @@ func (d *HuaweiCloudELBDeployer) deployToLoadbalancer(ctx context.Context) error // 批量更新监听器证书 var errs []error for _, hcListenerId := range hcListenerIds { - if err := d.updateListenerCertificate(ctx, hcListenerId, upres.CertId); err != nil { + if err := d.modifyListenerCertificate(ctx, hcListenerId, upres.CertId); err != nil { errs = append(errs, err) } } @@ -294,14 +294,14 @@ func (d *HuaweiCloudELBDeployer) deployToListener(ctx context.Context) error { d.infos = append(d.infos, toStr("已上传证书", upres)) // 更新监听器证书 - if err := d.updateListenerCertificate(ctx, hcListenerId, upres.CertId); err != nil { + if err := d.modifyListenerCertificate(ctx, hcListenerId, upres.CertId); err != nil { return err } return nil } -func (d *HuaweiCloudELBDeployer) updateListenerCertificate(ctx context.Context, hcListenerId string, hcCertId string) error { +func (d *HuaweiCloudELBDeployer) modifyListenerCertificate(ctx context.Context, hcListenerId string, hcCertId string) error { // 查询监听器详情 // REF: https://support.huaweicloud.com/api-elb/ShowListener.html showListenerReq := &hcElbModel.ShowListenerRequest{ diff --git a/internal/deployer/tencent_clb.go b/internal/deployer/tencent_clb.go index e773a346..51b2bfb1 100644 --- a/internal/deployer/tencent_clb.go +++ b/internal/deployer/tencent_clb.go @@ -7,6 +7,7 @@ import ( "fmt" xerrors "github.com/pkg/errors" + tcClb "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb/v20180317" "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" @@ -25,6 +26,7 @@ type TencentCLBDeployer struct { type tencentCLBDeployerSdkClients struct { ssl *tcSsl.Client + clb *tcClb.Client } func NewTencentCLBDeployer(option *DeployerOption) (Deployer, error) { @@ -69,10 +71,30 @@ func (d *TencentCLBDeployer) GetInfos() []string { func (d *TencentCLBDeployer) Deploy(ctx context.Context) error { // TODO: 直接部署方式 - // 通过 SSL 服务部署到云资源实例 - err := d.deployToInstanceUseSsl(ctx) - if err != nil { - return err + switch d.option.DeployConfig.GetConfigAsString("resourceType") { + case "ssl-deploy": + // 通过 SSL 服务部署到云资源实例 + err := d.deployToInstanceUseSsl(ctx) + if err != nil { + return err + } + case "loadbalancer": + // 部署到指定负载均衡器 + if err := d.deployToLoadbalancer(ctx); err != nil { + return err + } + case "listener": + // 部署到指定监听器 + if err := d.deployToListener(ctx); err != nil { + return err + } + case "ruledomain": + // 部署到指定七层监听转发规则域名 + if err := d.deployToRuleDomain(ctx); err != nil { + return err + } + default: + return errors.New("unsupported resource type") } return nil @@ -86,14 +108,20 @@ func (d *TencentCLBDeployer) createSdkClients(secretId, secretKey, region string return nil, err } + clbClient, err := tcClb.NewClient(credential, region, profile.NewClientProfile()) + if err != nil { + return nil, err + } + return &tencentCLBDeployerSdkClients{ ssl: sslClient, + clb: clbClient, }, nil } func (d *TencentCLBDeployer) deployToInstanceUseSsl(ctx context.Context) error { - tcLoadbalancerId := d.option.DeployConfig.GetConfigAsString("clbId") - tcListenerId := d.option.DeployConfig.GetConfigAsString("lsnId") + tcLoadbalancerId := d.option.DeployConfig.GetConfigAsString("loadbalancerId") + tcListenerId := d.option.DeployConfig.GetConfigAsString("listenerId") tcDomain := d.option.DeployConfig.GetConfigAsString("domain") if tcLoadbalancerId == "" { return errors.New("`loadbalancerId` is required") @@ -132,3 +160,170 @@ func (d *TencentCLBDeployer) deployToInstanceUseSsl(ctx context.Context) error { return nil } + +func (d *TencentCLBDeployer) deployToLoadbalancer(ctx context.Context) error { + tcLoadbalancerId := d.option.DeployConfig.GetConfigAsString("loadbalancerId") + tcListenerIds := make([]string, 0) + if tcLoadbalancerId == "" { + return errors.New("`loadbalancerId` is required") + } + + // 查询负载均衡器详细信息 + // REF: https://cloud.tencent.com/document/api/214/46916 + describeLoadBalancersDetailReq := tcClb.NewDescribeLoadBalancersDetailRequest() + describeLoadBalancersDetailResp, err := d.sdkClients.clb.DescribeLoadBalancersDetail(describeLoadBalancersDetailReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'clb.DescribeLoadBalancersDetail'") + } + + d.infos = append(d.infos, toStr("已查询到负载均衡详细信息", describeLoadBalancersDetailResp)) + + // 查询监听器列表 + // REF: https://cloud.tencent.com/document/api/214/30686 + describeListenersReq := tcClb.NewDescribeListenersRequest() + describeListenersReq.LoadBalancerId = common.StringPtr(tcLoadbalancerId) + describeListenersResp, err := d.sdkClients.clb.DescribeListeners(describeListenersReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'clb.DescribeListeners'") + } else { + if describeListenersResp.Response.Listeners != nil { + for _, listener := range describeListenersResp.Response.Listeners { + if listener.Protocol == nil || (*listener.Protocol != "HTTPS" && *listener.Protocol != "TCP_SSL" && *listener.Protocol != "QUIC") { + continue + } + + tcListenerIds = append(tcListenerIds, *listener.ListenerId) + } + } + } + + d.infos = append(d.infos, toStr("已查询到负载均衡器下的监听器", tcListenerIds)) + + // 上传证书到 SCM + upres, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey) + if err != nil { + return err + } + + d.infos = append(d.infos, toStr("已上传证书", upres)) + + // 批量更新监听器证书 + var errs []error + for _, tcListenerId := range tcListenerIds { + if err := d.modifyListenerCertificate(ctx, tcLoadbalancerId, tcListenerId, upres.CertId); err != nil { + errs = append(errs, err) + } + } + if len(errs) > 0 { + return errors.Join(errs...) + } + + return nil +} + +func (d *TencentCLBDeployer) deployToListener(ctx context.Context) error { + tcLoadbalancerId := d.option.DeployConfig.GetConfigAsString("loadbalancerId") + tcListenerId := d.option.DeployConfig.GetConfigAsString("listenerId") + if tcLoadbalancerId == "" { + return errors.New("`loadbalancerId` is required") + } + if tcListenerId == "" { + return errors.New("`listenerId` is required") + } + + // 上传证书到 SSL + upres, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey) + if err != nil { + return err + } + + d.infos = append(d.infos, toStr("已上传证书", upres)) + + // 更新监听器证书 + if err := d.modifyListenerCertificate(ctx, tcLoadbalancerId, tcListenerId, upres.CertId); err != nil { + return err + } + + return nil +} + +func (d *TencentCLBDeployer) deployToRuleDomain(ctx context.Context) error { + tcLoadbalancerId := d.option.DeployConfig.GetConfigAsString("loadbalancerId") + tcListenerId := d.option.DeployConfig.GetConfigAsString("listenerId") + tcDomain := d.option.DeployConfig.GetConfigAsString("domain") + if tcLoadbalancerId == "" { + return errors.New("`loadbalancerId` is required") + } + if tcListenerId == "" { + return errors.New("`listenerId` is required") + } + if tcDomain == "" { + return errors.New("`domain` is required") + } + + // 上传证书到 SSL + upres, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey) + if err != nil { + return err + } + + d.infos = append(d.infos, toStr("已上传证书", upres)) + + // 修改负载均衡七层监听器转发规则的域名级别属性 + // REF: https://cloud.tencent.com/document/api/214/38092 + modifyDomainAttributesReq := tcClb.NewModifyDomainAttributesRequest() + modifyDomainAttributesReq.LoadBalancerId = common.StringPtr(tcLoadbalancerId) + modifyDomainAttributesReq.ListenerId = common.StringPtr(tcListenerId) + modifyDomainAttributesReq.Domain = common.StringPtr(tcDomain) + modifyDomainAttributesReq.Certificate = &tcClb.CertificateInput{ + SSLMode: common.StringPtr("UNIDIRECTIONAL"), + CertId: common.StringPtr(upres.CertId), + } + modifyDomainAttributesResp, err := d.sdkClients.clb.ModifyDomainAttributes(modifyDomainAttributesReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'clb.ModifyDomainAttributes'") + } + + d.infos = append(d.infos, toStr("已修改七层监听器转发规则的域名级别属性", modifyDomainAttributesResp.Response)) + + return nil +} + +func (d *TencentCLBDeployer) modifyListenerCertificate(ctx context.Context, tcLoadbalancerId, tcListenerId, tcCertId string) error { + // 查询监听器列表 + // REF: https://cloud.tencent.com/document/api/214/30686 + describeListenersReq := tcClb.NewDescribeListenersRequest() + describeListenersReq.LoadBalancerId = common.StringPtr(tcLoadbalancerId) + describeListenersReq.ListenerIds = common.StringPtrs([]string{tcListenerId}) + describeListenersResp, err := d.sdkClients.clb.DescribeListeners(describeListenersReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'clb.DescribeListeners'") + } + if len(describeListenersResp.Response.Listeners) == 0 { + d.infos = append(d.infos, toStr("未找到监听器", nil)) + return errors.New("listener not found") + } + + d.infos = append(d.infos, toStr("已查询到监听器属性", describeListenersResp.Response)) + + // 修改监听器属性 + // REF: https://cloud.tencent.com/document/product/214/30681 + modifyListenerReq := tcClb.NewModifyListenerRequest() + modifyListenerReq.LoadBalancerId = common.StringPtr(tcLoadbalancerId) + modifyListenerReq.ListenerId = common.StringPtr(tcListenerId) + modifyListenerReq.Certificate = &tcClb.CertificateInput{CertId: common.StringPtr(tcCertId)} + if describeListenersResp.Response.Listeners[0].Certificate != nil && describeListenersResp.Response.Listeners[0].Certificate.SSLMode != nil { + modifyListenerReq.Certificate.SSLMode = describeListenersResp.Response.Listeners[0].Certificate.SSLMode + modifyListenerReq.Certificate.CertCaId = describeListenersResp.Response.Listeners[0].Certificate.CertCaId + } else { + modifyListenerReq.Certificate.SSLMode = common.StringPtr("UNIDIRECTIONAL") + } + modifyListenerResp, err := d.sdkClients.clb.ModifyListener(modifyListenerReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'clb.ModifyListener'") + } + + d.infos = append(d.infos, toStr("已修改监听器属性", modifyListenerResp.Response)) + + return nil +} diff --git a/ui/src/components/certimate/DeployToTencentCLB.tsx b/ui/src/components/certimate/DeployToTencentCLB.tsx index 80c6e761..a3828a78 100644 --- a/ui/src/components/certimate/DeployToTencentCLB.tsx +++ b/ui/src/components/certimate/DeployToTencentCLB.tsx @@ -5,106 +5,76 @@ import { produce } from "immer"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; +import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { useDeployEditContext } from "./DeployEdit"; const DeployToTencentCLB = () => { - const { deploy: data, setDeploy, error, setError } = useDeployEditContext(); - const { t } = useTranslation(); - useEffect(() => { - setError({}); - }, []); - - useEffect(() => { - const resp = domainSchema.safeParse(data.config?.domain); - if (!resp.success) { - setError({ - ...error, - domain: JSON.parse(resp.error.message)[0].message, - }); - } else { - setError({ - ...error, - domain: "", - }); - } - }, [data]); - - useEffect(() => { - const clbIdresp = clbIdSchema.safeParse(data.config?.clbId); - if (!clbIdresp.success) { - setError({ - ...error, - clbId: JSON.parse(clbIdresp.error.message)[0].message, - }); - } else { - setError({ - ...error, - clbId: "", - }); - } - }, [data]); - - useEffect(() => { - const lsnIdresp = lsnIdSchema.safeParse(data.config?.lsnId); - if (!lsnIdresp.success) { - setError({ - ...error, - lsnId: JSON.parse(lsnIdresp.error.message)[0].message, - }); - } else { - setError({ - ...error, - lsnId: "", - }); - } - }, [data]); - - useEffect(() => { - const regionResp = regionSchema.safeParse(data.config?.region); - if (!regionResp.success) { - setError({ - ...error, - region: JSON.parse(regionResp.error.message)[0].message, - }); - } else { - setError({ - ...error, - region: "", - }); - } - }, []); + const { deploy: data, setDeploy, error, setError } = useDeployEditContext(); useEffect(() => { if (!data.id) { setDeploy({ ...data, config: { - lsnId: "", - clbId: "", + region: "ap-guangzhou", + resourceType: "", + loadbalancerId: "", + listenerId: "", domain: "", - region: "", }, }); } }, []); - const regionSchema = z.string().regex(/^ap-[a-z]+$/, { - message: t("domain.deployment.form.tencent_clb_region.placeholder"), - }); + useEffect(() => { + setError({}); + }, []); - const domainSchema = z.string().regex(/^$|^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, { - message: t("common.errmsg.domain_invalid"), - }); + const formSchema = z + .object({ + region: z.string().min(1, t("domain.deployment.form.tencent_clb_region.placeholder")), + resourceType: z.union([z.literal("ssl-deploy"), z.literal("loadbalancer"), z.literal("listener"), z.literal("ruledomain")], { + message: t("domain.deployment.form.tencent_clb_resource_type.placeholder"), + }), + loadbalancerId: z.string().min(1, t("domain.deployment.form.tencent_clb_loadbalancer_id.placeholder")), + listenerId: z.string().optional(), + domain: z.string().regex(/^$|^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, { + message: t("common.errmsg.domain_invalid"), + }), + }) + .refine( + (data) => { + switch (data.resourceType) { + case "ssl-deploy": + case "listener": + case "ruledomain": + return !!data.listenerId?.trim(); + } + return true; + }, + { + message: t("domain.deployment.form.tencent_clb_listener_id.placeholder"), + path: ["listenerId"], + } + ) + .refine((data) => (data.resourceType === "ruledomain" ? !!data.domain?.trim() : true), { + message: t("domain.deployment.form.tencent_clb_ruledomain.placeholder"), + path: ["domain"], + }); - const clbIdSchema = z.string().regex(/^lb-[a-zA-Z0-9]{8}$/, { - message: t("domain.deployment.form.tencent_clb_id.placeholder"), - }); - - const lsnIdSchema = z.string().regex(/^lbl-.{8}$/, { - message: t("domain.deployment.form.tencent_clb_listener.placeholder"), - }); + useEffect(() => { + const res = formSchema.safeParse(data.config); + setError({ + ...error, + region: res.error?.errors?.find((e) => e.path[0] === "region")?.message, + resourceType: res.error?.errors?.find((e) => e.path[0] === "resourceType")?.message, + loadbalancerId: res.error?.errors?.find((e) => e.path[0] === "loadbalancerId")?.message, + listenerId: res.error?.errors?.find((e) => e.path[0] === "listenerId")?.message, + domain: res.error?.errors?.find((e) => e.path[0] === "domain")?.message, + }); + }, [data]); return (
@@ -115,26 +85,9 @@ const DeployToTencentCLB = () => { className="w-full mt-1" value={data?.config?.region} onChange={(e) => { - const temp = e.target.value; - - const resp = regionSchema.safeParse(temp); - if (!resp.success) { - setError({ - ...error, - region: JSON.parse(resp.error.message)[0].message, - }); - } else { - setError({ - ...error, - region: "", - }); - } - const newData = produce(data, (draft) => { - if (!draft.config) { - draft.config = {}; - } - draft.config.region = temp; + draft.config ??= {}; + draft.config.region = e.target.value?.trim(); }); setDeploy(newData); }} @@ -143,106 +96,111 @@ const DeployToTencentCLB = () => {
- - { - const temp = e.target.value; - - const resp = clbIdSchema.safeParse(temp); - if (!resp.success) { - setError({ - ...error, - clbId: JSON.parse(resp.error.message)[0].message, - }); - } else { - setError({ - ...error, - clbId: "", - }); - } - + + +
{error?.resourceType}
- + { - const temp = e.target.value; - - const resp = lsnIdSchema.safeParse(temp); - if (!resp.success) { - setError({ - ...error, - lsnId: JSON.parse(resp.error.message)[0].message, - }); - } else { - setError({ - ...error, - lsnId: "", - }); - } - const newData = produce(data, (draft) => { - if (!draft.config) { - draft.config = {}; - } - draft.config.lsnId = temp; + draft.config ??= {}; + draft.config.loadbalancerId = e.target.value?.trim(); }); setDeploy(newData); }} /> -
{error?.lsnId}
+
{error?.loadbalancerId}
-
- - { - const temp = e.target.value; - - const resp = domainSchema.safeParse(temp); - if (!resp.success) { - setError({ - ...error, - domain: JSON.parse(resp.error.message)[0].message, + {data?.config?.resourceType === "ssl-deploy" || data?.config?.resourceType === "listener" || data?.config?.resourceType === "ruledomain" ? ( +
+ + { + const newData = produce(data, (draft) => { + draft.config ??= {}; + draft.config.listenerId = e.target.value?.trim(); }); - } else { - setError({ - ...error, - domain: "", - }); - } + setDeploy(newData); + }} + /> +
{error?.listenerId}
+
+ ) : ( + <> + )} - const newData = produce(data, (draft) => { - if (!draft.config) { - draft.config = {}; - } - draft.config.domain = temp; - }); - setDeploy(newData); - }} - /> -
{error?.domain}
-
+ {data?.config?.resourceType === "ssl-deploy" ? ( +
+ + { + const newData = produce(data, (draft) => { + draft.config ??= {}; + draft.config.domain = e.target.value?.trim(); + }); + setDeploy(newData); + }} + /> +
{error?.domain}
+
+ ) : ( + <> + )} + + {data?.config?.resourceType === "ruledomain" ? ( +
+ + { + const newData = produce(data, (draft) => { + draft.config ??= {}; + draft.config.domain = e.target.value?.trim(); + }); + setDeploy(newData); + }} + /> +
{error?.domain}
+
+ ) : ( + <> + )} ); }; diff --git a/ui/src/i18n/locales/en/nls.common.json b/ui/src/i18n/locales/en/nls.common.json index 6870c616..4111fa21 100644 --- a/ui/src/i18n/locales/en/nls.common.json +++ b/ui/src/i18n/locales/en/nls.common.json @@ -65,7 +65,7 @@ "common.provider.tencent.ecdn": "Tencent Cloud - ECDN", "common.provider.tencent.clb": "Tencent Cloud - CLB", "common.provider.tencent.cos": "Tencent Cloud - COS", - "common.provider.tencent.teo": "Tencent Cloud - TEO", + "common.provider.tencent.teo": "Tencent Cloud - EdgeOne", "common.provider.huaweicloud": "Huawei Cloud", "common.provider.huaweicloud.cdn": "Huawei Cloud - CDN", "common.provider.huaweicloud.elb": "Huawei Cloud - ELB", diff --git a/ui/src/i18n/locales/en/nls.domain.json b/ui/src/i18n/locales/en/nls.domain.json index 3ea712ab..5e1d77e2 100644 --- a/ui/src/i18n/locales/en/nls.domain.json +++ b/ui/src/i18n/locales/en/nls.domain.json @@ -97,12 +97,19 @@ "domain.deployment.form.tencent_cos_bucket.placeholder": "Please enter bucket", "domain.deployment.form.tencent_clb_region.label": "Region", "domain.deployment.form.tencent_clb_region.placeholder": "Please enter region (e.g. ap-guangzhou)", - "domain.deployment.form.tencent_clb_id.label": "CLB ID", - "domain.deployment.form.tencent_clb_id.placeholder": "Please enter CLB ID (e.g. lb-xxxxxxxx)", - "domain.deployment.form.tencent_clb_listener.label": "Listener ID", - "domain.deployment.form.tencent_clb_listener.placeholder": "Please enter listener ID (e.g. lbl-xxxxxxxx). The specific listener should have set the corresponding domain HTTPS forwarding, and the original certificate domain should be consistent with the certificate to be deployed.", + "domain.deployment.form.tencent_clb_resource_type.label": "Resource Type", + "domain.deployment.form.tencent_clb_resource_type.placeholder": "Please select CLB resource type", + "domain.deployment.form.tencent_clb_resource_type.option.ssl_deploy.label": "Through SSL Deploy", + "domain.deployment.form.tencent_clb_resource_type.option.loadbalancer.label": "CLB LoadBalancer", + "domain.deployment.form.tencent_clb_resource_type.option.listener.label": "CLB Listener", + "domain.deployment.form.tencent_clb_loadbalancer_id.label": "Loadbalancer ID", + "domain.deployment.form.tencent_clb_loadbalancer_id.placeholder": "Please enter Loadbalancer ID", + "domain.deployment.form.tencent_clb_listener_id.label": "Listener ID", + "domain.deployment.form.tencent_clb_listener_id.placeholder": "Please enter listener ID. The specific listener should have set the corresponding domain HTTPS forwarding, and the original certificate domain should be consistent with the certificate to be deployed.", "domain.deployment.form.tencent_clb_domain.label": "Deploy to domain (Wildcard domain is also supported)", "domain.deployment.form.tencent_clb_domain.placeholder": "Please enter domain to be deployed. If SNI is not enabled, you can leave it blank.", + "domain.deployment.form.tencent_clb_ruledomain.label": "Rule Domain", + "domain.deployment.form.tencent_clb_ruledomain.placeholder": "Please enter rule domain", "domain.deployment.form.tencent_teo_zone_id.label": "Zone ID", "domain.deployment.form.tencent_teo_zone_id.placeholder": "Please enter zone id, e.g. zone-xxxxxxxxx", "domain.deployment.form.tencent_teo_domain.label": "Deploy to domain (Wildcard domain is also supported, but should be same as the config on server, one domain each line)", diff --git a/ui/src/i18n/locales/zh/nls.common.json b/ui/src/i18n/locales/zh/nls.common.json index 12fcd58a..28777f3a 100644 --- a/ui/src/i18n/locales/zh/nls.common.json +++ b/ui/src/i18n/locales/zh/nls.common.json @@ -65,7 +65,7 @@ "common.provider.tencent.cdn": "腾讯云 - 内容分发网络 CDN", "common.provider.tencent.ecdn": "腾讯云 - 全站加速网络 ECDN", "common.provider.tencent.clb": "腾讯云 - 负载均衡 CLB", - "common.provider.tencent.teo": "腾讯云 - 边缘安全加速平台 EO", + "common.provider.tencent.teo": "腾讯云 - 边缘安全加速平台 EdgeOne", "common.provider.huaweicloud": "华为云", "common.provider.huaweicloud.cdn": "华为云 - 内容分发网络 CDN", "common.provider.huaweicloud.elb": "华为云 - 弹性负载均衡 ELB", @@ -88,4 +88,3 @@ "common.provider.lark": "飞书", "common.provider.mail": "电子邮件" } - diff --git a/ui/src/i18n/locales/zh/nls.domain.json b/ui/src/i18n/locales/zh/nls.domain.json index 1df7795b..c5ef365a 100644 --- a/ui/src/i18n/locales/zh/nls.domain.json +++ b/ui/src/i18n/locales/zh/nls.domain.json @@ -65,7 +65,7 @@ "domain.deployment.form.aliyun_clb_region.placeholder": "请输入地域(如 cn-hangzhou)", "domain.deployment.form.aliyun_clb_resource_type.label": "替换方式", "domain.deployment.form.aliyun_clb_resource_type.placeholder": "请选择替换方式", - "domain.deployment.form.aliyun_clb_resource_type.option.loadbalancer.label": "替换指定负载均衡器的全部监听的证书(仅支持 HTTPS 监听)", + "domain.deployment.form.aliyun_clb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 HTTPS 监听的证书", "domain.deployment.form.aliyun_clb_resource_type.option.listener.label": "替换指定负载均衡监听的证书", "domain.deployment.form.aliyun_clb_loadbalancer_id.label": "负载均衡器 ID", "domain.deployment.form.aliyun_clb_loadbalancer_id.placeholder": "请输入负载均衡器 ID", @@ -75,8 +75,8 @@ "domain.deployment.form.aliyun_alb_region.placeholder": "请输入地域(如 cn-hangzhou)", "domain.deployment.form.aliyun_alb_resource_type.label": "替换方式", "domain.deployment.form.aliyun_alb_resource_type.placeholder": "请选择替换方式", - "domain.deployment.form.aliyun_alb_resource_type.option.loadbalancer.label": "替换指定负载均衡器的全部监听的证书(仅支持 HTTPS/QUIC 监听)", - "domain.deployment.form.aliyun_alb_resource_type.option.listener.label": "替换指定监听器的证书", + "domain.deployment.form.aliyun_alb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 HTTPS/QUIC 监听的证书", + "domain.deployment.form.aliyun_alb_resource_type.option.listener.label": "替换指定负载均衡监听器的证书", "domain.deployment.form.aliyun_alb_loadbalancer_id.label": "负载均衡器 ID", "domain.deployment.form.aliyun_alb_loadbalancer_id.placeholder": "请输入负载均衡器 ID", "domain.deployment.form.aliyun_alb_listener_id.label": "监听器 ID", @@ -85,8 +85,8 @@ "domain.deployment.form.aliyun_nlb_region.placeholder": "请输入地域(如 cn-hangzhou)", "domain.deployment.form.aliyun_nlb_resource_type.label": "替换方式", "domain.deployment.form.aliyun_nlb_resource_type.placeholder": "请选择替换方式", - "domain.deployment.form.aliyun_nlb_resource_type.option.loadbalancer.label": "替换指定负载均衡器的全部监听的证书(仅支持 TCPSSL 监听)", - "domain.deployment.form.aliyun_nlb_resource_type.option.listener.label": "替换指定监听器的证书", + "domain.deployment.form.aliyun_nlb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 TCPSSL 监听的证书", + "domain.deployment.form.aliyun_nlb_resource_type.option.listener.label": "替换指定负载均衡监听器的证书", "domain.deployment.form.aliyun_nlb_loadbalancer_id.label": "负载均衡器 ID", "domain.deployment.form.aliyun_nlb_loadbalancer_id.placeholder": "请输入负载均衡器 ID", "domain.deployment.form.aliyun_nlb_listener_id.label": "监听器 ID", @@ -97,12 +97,20 @@ "domain.deployment.form.tencent_cos_bucket.placeholder": "请输入存储桶名", "domain.deployment.form.tencent_clb_region.label": "地域", "domain.deployment.form.tencent_clb_region.placeholder": "请输入地域(如 ap-guangzhou)", - "domain.deployment.form.tencent_clb_id.label": "负载均衡器 ID", - "domain.deployment.form.tencent_clb_id.placeholder": "请输入负载均衡器实例 ID(如 lb-xxxxxxxx)", - "domain.deployment.form.tencent_clb_listener.label": "监听器 ID(对应监听器应已设置对应域名 HTTPS 转发, 且原证书对应域名应与待部署证书的一致)", - "domain.deployment.form.tencent_clb_listener.placeholder": "请输入监听器 ID(如 lb-xxxxxxxx)", + "domain.deployment.form.tencent_clb_resource_type.label": "替换方式", + "domain.deployment.form.tencent_clb_resource_type.placeholder": "请选择替换方式", + "domain.deployment.form.tencent_clb_resource_type.option.ssl_deploy.label": "通过 SSL 服务部署到云资源实例", + "domain.deployment.form.tencent_clb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 HTTPS/TCPSSL/QUIC 监听器的证书", + "domain.deployment.form.tencent_clb_resource_type.option.listener.label": "替换指定负载均衡监听器的证书", + "domain.deployment.form.tencent_clb_resource_type.option.ruledomain.label": "替换指定七层监听转发规则域名的证书", + "domain.deployment.form.tencent_clb_loadbalancer_id.label": "负载均衡器 ID", + "domain.deployment.form.tencent_clb_loadbalancer_id.placeholder": "请输入负载均衡器实例 ID", + "domain.deployment.form.tencent_clb_listener_id.label": "监听器 ID", + "domain.deployment.form.tencent_clb_listener_id.placeholder": "请输入监听器 ID", "domain.deployment.form.tencent_clb_domain.label": "部署到域名(支持泛域名)", "domain.deployment.form.tencent_clb_domain.placeholder": "请输入部署到的域名, 如未开启 SNI, 可置空忽略此项", + "domain.deployment.form.tencent_clb_ruledomain.label": "转发域名", + "domain.deployment.form.tencent_clb_ruledomain.placeholder": "请输入七层监听转发规则域名", "domain.deployment.form.tencent_teo_zone_id.label": "Zone ID", "domain.deployment.form.tencent_teo_zone_id.placeholder": "请输入 Zone ID", "domain.deployment.form.tencent_teo_domain.label": "部署到域名(支持泛域名, 应与服务器上配置的域名完全一致, 每行一个域名)", @@ -112,8 +120,8 @@ "domain.deployment.form.huaweicloud_elb_resource_type.label": "替换方式", "domain.deployment.form.huaweicloud_elb_resource_type.placeholder": "请选择替换方式", "domain.deployment.form.huaweicloud_elb_resource_type.option.certificate.label": "替换指定证书", - "domain.deployment.form.huaweicloud_elb_resource_type.option.loadbalancer.label": "替换指定负载均衡器的全部监听器的证书(仅支持 HTTPS 监听)", - "domain.deployment.form.huaweicloud_elb_resource_type.option.listener.label": "替换指定监听器", + "domain.deployment.form.huaweicloud_elb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 HTTPS 监听器的证书", + "domain.deployment.form.huaweicloud_elb_resource_type.option.listener.label": "替换指定监听器的证书", "domain.deployment.form.huaweicloud_elb_certificate_id.label": "证书 ID", "domain.deployment.form.huaweicloud_elb_certificate_id.placeholder": "请输入证书 ID", "domain.deployment.form.huaweicloud_elb_loadbalancer_id.label": "负载均衡器 ID",