From e1a3a3e7c7a42d247cfb220f2d25463d5468b93b Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Mon, 28 Oct 2024 14:15:33 +0800 Subject: [PATCH 01/18] refactor: clean code --- internal/deployer/aliyun_alb.go | 24 ++--- internal/deployer/aliyun_cdn.go | 59 +++++------ internal/deployer/aliyun_clb.go | 24 ++--- internal/deployer/aliyun_dcdn.go | 94 ++++++++++++++++++ internal/deployer/aliyun_esa.go | 97 ------------------- internal/deployer/aliyun_nlb.go | 20 ++-- internal/deployer/aliyun_oss.go | 53 ++++++---- internal/deployer/deployer.go | 8 +- internal/deployer/k8s_secret.go | 34 +++---- .../pkg/core/uploader/uploader_aliyun_cas.go | 33 +++---- .../pkg/core/uploader/uploader_aliyun_slb.go | 29 +++--- 11 files changed, 241 insertions(+), 234 deletions(-) create mode 100644 internal/deployer/aliyun_dcdn.go delete mode 100644 internal/deployer/aliyun_esa.go diff --git a/internal/deployer/aliyun_alb.go b/internal/deployer/aliyun_alb.go index b676e043..4ee68a7a 100644 --- a/internal/deployer/aliyun_alb.go +++ b/internal/deployer/aliyun_alb.go @@ -6,8 +6,8 @@ import ( "errors" "fmt" - alb20200616 "github.com/alibabacloud-go/alb-20200616/v2/client" - openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client" + aliyunAlb "github.com/alibabacloud-go/alb-20200616/v2/client" + aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client" "github.com/alibabacloud-go/tea/tea" "github.com/usual2970/certimate/internal/domain" @@ -18,7 +18,7 @@ type AliyunALBDeployer struct { option *DeployerOption infos []string - sdkClient *alb20200616.Client + sdkClient *aliyunAlb.Client sslUploader uploader.Uploader } @@ -77,12 +77,12 @@ func (d *AliyunALBDeployer) Deploy(ctx context.Context) error { return nil } -func (d *AliyunALBDeployer) createSdkClient(accessKeyId, accessKeySecret, region string) (*alb20200616.Client, error) { +func (d *AliyunALBDeployer) createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunAlb.Client, error) { if region == "" { region = "cn-hangzhou" // ALB 服务默认区域:华东一杭州 } - aConfig := &openapi.Config{ + aConfig := &aliyunOpen.Config{ AccessKeyId: tea.String(accessKeyId), AccessKeySecret: tea.String(accessKeySecret), } @@ -96,7 +96,7 @@ func (d *AliyunALBDeployer) createSdkClient(accessKeyId, accessKeySecret, region } aConfig.Endpoint = tea.String(endpoint) - client, err := alb20200616.NewClient(aConfig) + client, err := aliyunAlb.NewClient(aConfig) if err != nil { return nil, err } @@ -114,7 +114,7 @@ func (d *AliyunALBDeployer) deployToLoadbalancer(ctx context.Context) error { // 查询负载均衡实例的详细信息 // REF: https://help.aliyun.com/zh/slb/application-load-balancer/developer-reference/api-alb-2020-06-16-getloadbalancerattribute - getLoadBalancerAttributeReq := &alb20200616.GetLoadBalancerAttributeRequest{ + getLoadBalancerAttributeReq := &aliyunAlb.GetLoadBalancerAttributeRequest{ LoadBalancerId: tea.String(aliLoadbalancerId), } getLoadBalancerAttributeResp, err := d.sdkClient.GetLoadBalancerAttribute(getLoadBalancerAttributeReq) @@ -130,7 +130,7 @@ func (d *AliyunALBDeployer) deployToLoadbalancer(ctx context.Context) error { listListenersLimit := int32(100) var listListenersToken *string = nil for { - listListenersReq := &alb20200616.ListListenersRequest{ + listListenersReq := &aliyunAlb.ListListenersRequest{ MaxResults: tea.Int32(listListenersLimit), NextToken: listListenersToken, LoadBalancerIds: []*string{tea.String(aliLoadbalancerId)}, @@ -162,7 +162,7 @@ func (d *AliyunALBDeployer) deployToLoadbalancer(ctx context.Context) error { listListenersPage = 1 listListenersToken = nil for { - listListenersReq := &alb20200616.ListListenersRequest{ + listListenersReq := &aliyunAlb.ListListenersRequest{ MaxResults: tea.Int32(listListenersLimit), NextToken: listListenersToken, LoadBalancerIds: []*string{tea.String(aliLoadbalancerId)}, @@ -236,7 +236,7 @@ func (d *AliyunALBDeployer) deployToListener(ctx context.Context) error { func (d *AliyunALBDeployer) updateListenerCertificate(ctx context.Context, aliListenerId string, aliCertId string) error { // 查询监听的属性 // REF: https://help.aliyun.com/zh/slb/application-load-balancer/developer-reference/api-alb-2020-06-16-getlistenerattribute - getListenerAttributeReq := &alb20200616.GetListenerAttributeRequest{ + getListenerAttributeReq := &aliyunAlb.GetListenerAttributeRequest{ ListenerId: tea.String(aliListenerId), } getListenerAttributeResp, err := d.sdkClient.GetListenerAttribute(getListenerAttributeReq) @@ -248,9 +248,9 @@ func (d *AliyunALBDeployer) updateListenerCertificate(ctx context.Context, aliLi // 修改监听的属性 // REF: https://help.aliyun.com/zh/slb/application-load-balancer/developer-reference/api-alb-2020-06-16-updatelistenerattribute - updateListenerAttributeReq := &alb20200616.UpdateListenerAttributeRequest{ + updateListenerAttributeReq := &aliyunAlb.UpdateListenerAttributeRequest{ ListenerId: tea.String(aliListenerId), - Certificates: []*alb20200616.UpdateListenerAttributeRequestCertificates{{ + Certificates: []*aliyunAlb.UpdateListenerAttributeRequestCertificates{{ CertificateId: tea.String(aliCertId), }}, } diff --git a/internal/deployer/aliyun_cdn.go b/internal/deployer/aliyun_cdn.go index 97ac0d83..2b633182 100644 --- a/internal/deployer/aliyun_cdn.go +++ b/internal/deployer/aliyun_cdn.go @@ -5,9 +5,8 @@ import ( "encoding/json" "fmt" - cdn20180510 "github.com/alibabacloud-go/cdn-20180510/v5/client" - openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client" - util "github.com/alibabacloud-go/tea-utils/v2/service" + aliyunCdn "github.com/alibabacloud-go/cdn-20180510/v5/client" + aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client" "github.com/alibabacloud-go/tea/tea" "github.com/usual2970/certimate/internal/domain" @@ -15,28 +14,28 @@ import ( ) type AliyunCDNDeployer struct { - client *cdn20180510.Client option *DeployerOption infos []string + + sdkClient *aliyunCdn.Client } -func NewAliyunCDNDeployer(option *DeployerOption) (*AliyunCDNDeployer, error) { +func NewAliyunCDNDeployer(option *DeployerOption) (Deployer, error) { access := &domain.AliyunAccess{} json.Unmarshal([]byte(option.Access), access) - d := &AliyunCDNDeployer{ - option: option, - } - - client, err := d.createClient(access.AccessKeyId, access.AccessKeySecret) + client, err := (&AliyunCDNDeployer{}).createSdkClient( + access.AccessKeyId, + access.AccessKeySecret, + ) if err != nil { return nil, err } return &AliyunCDNDeployer{ - client: client, - option: option, - infos: make([]string, 0), + option: option, + infos: make([]string, 0), + sdkClient: client, }, nil } @@ -50,35 +49,39 @@ func (d *AliyunCDNDeployer) GetInfo() []string { func (d *AliyunCDNDeployer) Deploy(ctx context.Context) error { certName := fmt.Sprintf("%s-%s-%s", d.option.Domain, d.option.DomainId, rand.RandStr(6)) - setCdnDomainSSLCertificateRequest := &cdn20180510.SetCdnDomainSSLCertificateRequest{ - DomainName: tea.String(getDeployString(d.option.DeployConfig, "domain")), + + // 设置 CDN 域名域名证书 + // REF: https://help.aliyun.com/zh/cdn/developer-reference/api-cdn-2018-05-10-setcdndomainsslcertificate + setCdnDomainSSLCertificateReq := &aliyunCdn.SetCdnDomainSSLCertificateRequest{ + DomainName: tea.String(d.option.DeployConfig.GetConfigAsString("domain")), + CertRegion: tea.String(d.option.DeployConfig.GetConfigOrDefaultAsString("region", "cn-hangzhou")), CertName: tea.String(certName), CertType: tea.String("upload"), SSLProtocol: tea.String("on"), SSLPub: tea.String(d.option.Certificate.Certificate), SSLPri: tea.String(d.option.Certificate.PrivateKey), - CertRegion: tea.String("cn-hangzhou"), } - - runtime := &util.RuntimeOptions{} - - resp, err := d.client.SetCdnDomainSSLCertificateWithOptions(setCdnDomainSSLCertificateRequest, runtime) + setCdnDomainSSLCertificateResp, err := d.sdkClient.SetCdnDomainSSLCertificate(setCdnDomainSSLCertificateReq) if err != nil { - return err + return fmt.Errorf("failed to execute sdk request 'cdn.SetCdnDomainSSLCertificate': %w", err) } - d.infos = append(d.infos, toStr("cdn设置证书", resp)) + d.infos = append(d.infos, toStr("已设置 CDN 域名证书", setCdnDomainSSLCertificateResp)) return nil } -func (d *AliyunCDNDeployer) createClient(accessKeyId, accessKeySecret string) (_result *cdn20180510.Client, _err error) { - config := &openapi.Config{ +func (d *AliyunCDNDeployer) createSdkClient(accessKeyId, accessKeySecret string) (*aliyunCdn.Client, error) { + aConfig := &aliyunOpen.Config{ AccessKeyId: tea.String(accessKeyId), AccessKeySecret: tea.String(accessKeySecret), + Endpoint: tea.String("cdn.aliyuncs.com"), } - config.Endpoint = tea.String("cdn.aliyuncs.com") - _result = &cdn20180510.Client{} - _result, _err = cdn20180510.NewClient(config) - return _result, _err + + client, err := aliyunCdn.NewClient(aConfig) + if err != nil { + return nil, err + } + + return client, nil } diff --git a/internal/deployer/aliyun_clb.go b/internal/deployer/aliyun_clb.go index 11384ba8..87f68a02 100644 --- a/internal/deployer/aliyun_clb.go +++ b/internal/deployer/aliyun_clb.go @@ -6,8 +6,8 @@ import ( "errors" "fmt" - openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client" - slb20140515 "github.com/alibabacloud-go/slb-20140515/v4/client" + aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client" + aliyunSlb "github.com/alibabacloud-go/slb-20140515/v4/client" "github.com/alibabacloud-go/tea/tea" "github.com/usual2970/certimate/internal/domain" @@ -18,7 +18,7 @@ type AliyunCLBDeployer struct { option *DeployerOption infos []string - sdkClient *slb20140515.Client + sdkClient *aliyunSlb.Client sslUploader uploader.Uploader } @@ -77,12 +77,12 @@ func (d *AliyunCLBDeployer) Deploy(ctx context.Context) error { return nil } -func (d *AliyunCLBDeployer) createSdkClient(accessKeyId, accessKeySecret, region string) (*slb20140515.Client, error) { +func (d *AliyunCLBDeployer) createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunSlb.Client, error) { if region == "" { region = "cn-hangzhou" // CLB(SLB) 服务默认区域:华东一杭州 } - aConfig := &openapi.Config{ + aConfig := &aliyunOpen.Config{ AccessKeyId: tea.String(accessKeyId), AccessKeySecret: tea.String(accessKeySecret), } @@ -99,7 +99,7 @@ func (d *AliyunCLBDeployer) createSdkClient(accessKeyId, accessKeySecret, region } aConfig.Endpoint = tea.String(endpoint) - client, err := slb20140515.NewClient(aConfig) + client, err := aliyunSlb.NewClient(aConfig) if err != nil { return nil, err } @@ -117,7 +117,7 @@ func (d *AliyunCLBDeployer) deployToLoadbalancer(ctx context.Context) error { // 查询负载均衡实例的详细信息 // REF: https://help.aliyun.com/zh/slb/classic-load-balancer/developer-reference/api-slb-2014-05-15-describeloadbalancerattribute - describeLoadBalancerAttributeReq := &slb20140515.DescribeLoadBalancerAttributeRequest{ + describeLoadBalancerAttributeReq := &aliyunSlb.DescribeLoadBalancerAttributeRequest{ RegionId: tea.String(d.option.DeployConfig.GetConfigAsString("region")), LoadBalancerId: tea.String(aliLoadbalancerId), } @@ -134,7 +134,7 @@ func (d *AliyunCLBDeployer) deployToLoadbalancer(ctx context.Context) error { listListenersLimit := int32(100) var listListenersToken *string = nil for { - describeLoadBalancerListenersReq := &slb20140515.DescribeLoadBalancerListenersRequest{ + describeLoadBalancerListenersReq := &aliyunSlb.DescribeLoadBalancerListenersRequest{ RegionId: tea.String(d.option.DeployConfig.GetConfigAsString("region")), MaxResults: tea.Int32(listListenersLimit), NextToken: listListenersToken, @@ -214,7 +214,7 @@ func (d *AliyunCLBDeployer) deployToListener(ctx context.Context) error { func (d *AliyunCLBDeployer) updateListenerCertificate(ctx context.Context, aliLoadbalancerId string, aliListenerPort int32, aliCertId string) error { // 查询监听配置 // REF: https://help.aliyun.com/zh/slb/classic-load-balancer/developer-reference/api-slb-2014-05-15-describeloadbalancerhttpslistenerattribute - describeLoadBalancerHTTPSListenerAttributeReq := &slb20140515.DescribeLoadBalancerHTTPSListenerAttributeRequest{ + describeLoadBalancerHTTPSListenerAttributeReq := &aliyunSlb.DescribeLoadBalancerHTTPSListenerAttributeRequest{ LoadBalancerId: tea.String(aliLoadbalancerId), ListenerPort: tea.Int32(aliListenerPort), } @@ -227,7 +227,7 @@ func (d *AliyunCLBDeployer) updateListenerCertificate(ctx context.Context, aliLo // 查询扩展域名 // REF: https://help.aliyun.com/zh/slb/classic-load-balancer/developer-reference/api-slb-2014-05-15-describedomainextensions - describeDomainExtensionsReq := &slb20140515.DescribeDomainExtensionsRequest{ + describeDomainExtensionsReq := &aliyunSlb.DescribeDomainExtensionsRequest{ RegionId: tea.String(d.option.DeployConfig.GetConfigAsString("region")), LoadBalancerId: tea.String(aliLoadbalancerId), ListenerPort: tea.Int32(aliListenerPort), @@ -249,7 +249,7 @@ func (d *AliyunCLBDeployer) updateListenerCertificate(ctx context.Context, aliLo break } - setDomainExtensionAttributeReq := &slb20140515.SetDomainExtensionAttributeRequest{ + setDomainExtensionAttributeReq := &aliyunSlb.SetDomainExtensionAttributeRequest{ RegionId: tea.String(d.option.DeployConfig.GetConfigAsString("region")), DomainExtensionId: tea.String(*domainExtension.DomainExtensionId), ServerCertificateId: tea.String(aliCertId), @@ -265,7 +265,7 @@ func (d *AliyunCLBDeployer) updateListenerCertificate(ctx context.Context, aliLo // REF: https://help.aliyun.com/zh/slb/classic-load-balancer/developer-reference/api-slb-2014-05-15-setloadbalancerhttpslistenerattribute // // 注意修改监听配置要放在修改扩展域名之后 - setLoadBalancerHTTPSListenerAttributeReq := &slb20140515.SetLoadBalancerHTTPSListenerAttributeRequest{ + setLoadBalancerHTTPSListenerAttributeReq := &aliyunSlb.SetLoadBalancerHTTPSListenerAttributeRequest{ RegionId: tea.String(d.option.DeployConfig.GetConfigAsString("region")), LoadBalancerId: tea.String(aliLoadbalancerId), ListenerPort: tea.Int32(aliListenerPort), diff --git a/internal/deployer/aliyun_dcdn.go b/internal/deployer/aliyun_dcdn.go new file mode 100644 index 00000000..f760e92f --- /dev/null +++ b/internal/deployer/aliyun_dcdn.go @@ -0,0 +1,94 @@ +package deployer + +import ( + "context" + "encoding/json" + "fmt" + "strings" + + aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client" + aliyunDcdn "github.com/alibabacloud-go/dcdn-20180115/v3/client" + "github.com/alibabacloud-go/tea/tea" + + "github.com/usual2970/certimate/internal/domain" + "github.com/usual2970/certimate/internal/utils/rand" +) + +type AliyunDCDNDeployer struct { + option *DeployerOption + infos []string + + sdkClient *aliyunDcdn.Client +} + +func NewAliyunDCDNDeployer(option *DeployerOption) (Deployer, error) { + access := &domain.AliyunAccess{} + json.Unmarshal([]byte(option.Access), access) + + client, err := (&AliyunDCDNDeployer{}).createSdkClient( + access.AccessKeyId, + access.AccessKeySecret, + ) + if err != nil { + return nil, err + } + + return &AliyunDCDNDeployer{ + option: option, + infos: make([]string, 0), + sdkClient: client, + }, nil +} + +func (d *AliyunDCDNDeployer) GetID() string { + return fmt.Sprintf("%s-%s", d.option.AccessRecord.GetString("name"), d.option.AccessRecord.Id) +} + +func (d *AliyunDCDNDeployer) GetInfo() []string { + return d.infos +} + +func (d *AliyunDCDNDeployer) Deploy(ctx context.Context) error { + certName := fmt.Sprintf("%s-%s-%s", d.option.Domain, d.option.DomainId, rand.RandStr(6)) + + // 支持泛解析域名,在 Aliyun DCDN 中泛解析域名表示为 .example.com + domain := d.option.DeployConfig.GetConfigAsString("domain") + if strings.HasPrefix(domain, "*") { + domain = strings.TrimPrefix(domain, "*") + } + + // 配置域名证书 + // REF: https://help.aliyun.com/zh/edge-security-acceleration/dcdn/developer-reference/api-dcdn-2018-01-15-setdcdndomainsslcertificate + setDcdnDomainSSLCertificateReq := &aliyunDcdn.SetDcdnDomainSSLCertificateRequest{ + DomainName: tea.String(domain), + CertRegion: tea.String(d.option.DeployConfig.GetConfigOrDefaultAsString("region", "cn-hangzhou")), + CertName: tea.String(certName), + CertType: tea.String("upload"), + SSLProtocol: tea.String("on"), + SSLPub: tea.String(d.option.Certificate.Certificate), + SSLPri: tea.String(d.option.Certificate.PrivateKey), + } + setDcdnDomainSSLCertificateResp, err := d.sdkClient.SetDcdnDomainSSLCertificate(setDcdnDomainSSLCertificateReq) + if err != nil { + return fmt.Errorf("failed to execute sdk request 'dcdn.SetDcdnDomainSSLCertificate': %w", err) + } + + d.infos = append(d.infos, toStr("已配置 DCDN 域名证书", setDcdnDomainSSLCertificateResp)) + + return nil +} + +func (d *AliyunDCDNDeployer) createSdkClient(accessKeyId, accessKeySecret string) (*aliyunDcdn.Client, error) { + aConfig := &aliyunOpen.Config{ + AccessKeyId: tea.String(accessKeyId), + AccessKeySecret: tea.String(accessKeySecret), + Endpoint: tea.String("dcdn.aliyuncs.com"), + } + + client, err := aliyunDcdn.NewClient(aConfig) + if err != nil { + return nil, err + } + + return client, nil +} diff --git a/internal/deployer/aliyun_esa.go b/internal/deployer/aliyun_esa.go deleted file mode 100644 index 012ca887..00000000 --- a/internal/deployer/aliyun_esa.go +++ /dev/null @@ -1,97 +0,0 @@ -/* - * @Author: Bin - * @Date: 2024-09-17 - * @FilePath: /certimate/internal/deployer/aliyun_esa.go - */ -package deployer - -import ( - "context" - "encoding/json" - "fmt" - "strings" - - openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client" - dcdn20180115 "github.com/alibabacloud-go/dcdn-20180115/v3/client" - util "github.com/alibabacloud-go/tea-utils/v2/service" - "github.com/alibabacloud-go/tea/tea" - - "github.com/usual2970/certimate/internal/domain" - "github.com/usual2970/certimate/internal/utils/rand" -) - -type AliyunESADeployer struct { - client *dcdn20180115.Client - option *DeployerOption - infos []string -} - -func NewAliyunESADeployer(option *DeployerOption) (*AliyunESADeployer, error) { - access := &domain.AliyunAccess{} - json.Unmarshal([]byte(option.Access), access) - - d := &AliyunESADeployer{ - option: option, - } - - client, err := d.createClient(access.AccessKeyId, access.AccessKeySecret) - if err != nil { - return nil, err - } - - return &AliyunESADeployer{ - client: client, - option: option, - infos: make([]string, 0), - }, nil -} - -func (d *AliyunESADeployer) GetID() string { - return fmt.Sprintf("%s-%s", d.option.AccessRecord.GetString("name"), d.option.AccessRecord.Id) -} - -func (d *AliyunESADeployer) GetInfo() []string { - return d.infos -} - -func (d *AliyunESADeployer) Deploy(ctx context.Context) error { - certName := fmt.Sprintf("%s-%s-%s", d.option.Domain, d.option.DomainId, rand.RandStr(6)) - - // 支持泛解析域名,在 Aliyun DCND 中泛解析域名表示为 .example.com - domain := getDeployString(d.option.DeployConfig, "domain") - if strings.HasPrefix(domain, "*") { - domain = strings.TrimPrefix(domain, "*") - } - - setDcdnDomainSSLCertificateRequest := &dcdn20180115.SetDcdnDomainSSLCertificateRequest{ - DomainName: tea.String(domain), - CertName: tea.String(certName), - CertType: tea.String("upload"), - SSLProtocol: tea.String("on"), - SSLPub: tea.String(d.option.Certificate.Certificate), - SSLPri: tea.String(d.option.Certificate.PrivateKey), - CertRegion: tea.String("cn-hangzhou"), - } - - runtime := &util.RuntimeOptions{} - - resp, err := d.client.SetDcdnDomainSSLCertificateWithOptions(setDcdnDomainSSLCertificateRequest, runtime) - if err != nil { - return err - } - - d.infos = append(d.infos, toStr("dcdn设置证书", resp)) - - return nil -} - -func (d *AliyunESADeployer) createClient(accessKeyId, accessKeySecret string) (_result *dcdn20180115.Client, _err error) { - config := &openapi.Config{ - AccessKeyId: tea.String(accessKeyId), - AccessKeySecret: tea.String(accessKeySecret), - } - config.Endpoint = tea.String("dcdn.aliyuncs.com") - _result = &dcdn20180115.Client{} - _result, _err = dcdn20180115.NewClient(config) - return _result, _err -} diff --git a/internal/deployer/aliyun_nlb.go b/internal/deployer/aliyun_nlb.go index 514657e6..59cc0163 100644 --- a/internal/deployer/aliyun_nlb.go +++ b/internal/deployer/aliyun_nlb.go @@ -6,8 +6,8 @@ import ( "errors" "fmt" - openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client" - nlb20220430 "github.com/alibabacloud-go/nlb-20220430/v2/client" + aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client" + aliyunNlb "github.com/alibabacloud-go/nlb-20220430/v2/client" "github.com/alibabacloud-go/tea/tea" "github.com/usual2970/certimate/internal/domain" @@ -18,7 +18,7 @@ type AliyunNLBDeployer struct { option *DeployerOption infos []string - sdkClient *nlb20220430.Client + sdkClient *aliyunNlb.Client sslUploader uploader.Uploader } @@ -77,12 +77,12 @@ func (d *AliyunNLBDeployer) Deploy(ctx context.Context) error { return nil } -func (d *AliyunNLBDeployer) createSdkClient(accessKeyId, accessKeySecret, region string) (*nlb20220430.Client, error) { +func (d *AliyunNLBDeployer) createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunNlb.Client, error) { if region == "" { region = "cn-hangzhou" // NLB 服务默认区域:华东一杭州 } - aConfig := &openapi.Config{ + aConfig := &aliyunOpen.Config{ AccessKeyId: tea.String(accessKeyId), AccessKeySecret: tea.String(accessKeySecret), } @@ -94,7 +94,7 @@ func (d *AliyunNLBDeployer) createSdkClient(accessKeyId, accessKeySecret, region } aConfig.Endpoint = tea.String(endpoint) - client, err := nlb20220430.NewClient(aConfig) + client, err := aliyunNlb.NewClient(aConfig) if err != nil { return nil, err } @@ -112,7 +112,7 @@ func (d *AliyunNLBDeployer) deployToLoadbalancer(ctx context.Context) error { // 查询负载均衡实例的详细信息 // REF: https://help.aliyun.com/zh/slb/network-load-balancer/developer-reference/api-nlb-2022-04-30-getloadbalancerattribute - getLoadBalancerAttributeReq := &nlb20220430.GetLoadBalancerAttributeRequest{ + getLoadBalancerAttributeReq := &aliyunNlb.GetLoadBalancerAttributeRequest{ LoadBalancerId: tea.String(aliLoadbalancerId), } getLoadBalancerAttributeResp, err := d.sdkClient.GetLoadBalancerAttribute(getLoadBalancerAttributeReq) @@ -128,7 +128,7 @@ func (d *AliyunNLBDeployer) deployToLoadbalancer(ctx context.Context) error { listListenersLimit := int32(100) var listListenersToken *string = nil for { - listListenersReq := &nlb20220430.ListListenersRequest{ + listListenersReq := &aliyunNlb.ListListenersRequest{ MaxResults: tea.Int32(listListenersLimit), NextToken: listListenersToken, LoadBalancerIds: []*string{tea.String(aliLoadbalancerId)}, @@ -202,7 +202,7 @@ func (d *AliyunNLBDeployer) deployToListener(ctx context.Context) error { func (d *AliyunNLBDeployer) updateListenerCertificate(ctx context.Context, aliListenerId string, aliCertId string) error { // 查询监听的属性 // REF: https://help.aliyun.com/zh/slb/network-load-balancer/developer-reference/api-nlb-2022-04-30-getlistenerattribute - getListenerAttributeReq := &nlb20220430.GetListenerAttributeRequest{ + getListenerAttributeReq := &aliyunNlb.GetListenerAttributeRequest{ ListenerId: tea.String(aliListenerId), } getListenerAttributeResp, err := d.sdkClient.GetListenerAttribute(getListenerAttributeReq) @@ -214,7 +214,7 @@ func (d *AliyunNLBDeployer) updateListenerCertificate(ctx context.Context, aliLi // 修改监听的属性 // REF: https://help.aliyun.com/zh/slb/network-load-balancer/developer-reference/api-nlb-2022-04-30-updatelistenerattribute - updateListenerAttributeReq := &nlb20220430.UpdateListenerAttributeRequest{ + updateListenerAttributeReq := &aliyunNlb.UpdateListenerAttributeRequest{ ListenerId: tea.String(aliListenerId), CertificateIds: []*string{tea.String(aliCertId)}, } diff --git a/internal/deployer/aliyun_oss.go b/internal/deployer/aliyun_oss.go index 9626e3bc..47173d0e 100644 --- a/internal/deployer/aliyun_oss.go +++ b/internal/deployer/aliyun_oss.go @@ -3,6 +3,7 @@ package deployer import ( "context" "encoding/json" + "errors" "fmt" "github.com/aliyun/aliyun-oss-go-sdk/oss" @@ -11,27 +12,30 @@ import ( ) type AliyunOSSDeployer struct { - client *oss.Client option *DeployerOption infos []string + + sdkClient *oss.Client } func NewAliyunOSSDeployer(option *DeployerOption) (Deployer, error) { access := &domain.AliyunAccess{} json.Unmarshal([]byte(option.Access), access) - d := &AliyunOSSDeployer{ - option: option, - infos: make([]string, 0), - } - - client, err := d.createClient(access.AccessKeyId, access.AccessKeySecret) + client, err := (&AliyunOSSDeployer{}).createSdkClient( + access.AccessKeyId, + access.AccessKeySecret, + option.DeployConfig.GetConfigAsString("endpoint"), + ) if err != nil { return nil, err } - d.client = client - return d, nil + return &AliyunOSSDeployer{ + option: option, + infos: make([]string, 0), + sdkClient: client, + }, nil } func (d *AliyunOSSDeployer) GetID() string { @@ -43,8 +47,15 @@ func (d *AliyunOSSDeployer) GetInfo() []string { } func (d *AliyunOSSDeployer) Deploy(ctx context.Context) error { - err := d.client.PutBucketCnameWithCertificate(getDeployString(d.option.DeployConfig, "bucket"), oss.PutBucketCname{ - Cname: getDeployString(d.option.DeployConfig, "domain"), + aliBucket := d.option.DeployConfig.GetConfigAsString("bucket") + if aliBucket == "" { + return errors.New("`bucket` is required") + } + + // 为存储空间绑定自定义域名 + // REF: https://help.aliyun.com/zh/oss/developer-reference/putcname + err := d.sdkClient.PutBucketCnameWithCertificate(aliBucket, oss.PutBucketCname{ + Cname: d.option.DeployConfig.GetConfigAsString("domain"), CertificateConfiguration: &oss.CertificateConfiguration{ Certificate: d.option.Certificate.Certificate, PrivateKey: d.option.Certificate.PrivateKey, @@ -52,19 +63,21 @@ func (d *AliyunOSSDeployer) Deploy(ctx context.Context) error { }, }) if err != nil { - return fmt.Errorf("deploy aliyun oss error: %w", err) + return fmt.Errorf("failed to execute sdk request 'oss.PutBucketCnameWithCertificate': %w", err) } + return nil } -func (d *AliyunOSSDeployer) createClient(accessKeyId, accessKeySecret string) (*oss.Client, error) { - client, err := oss.New( - getDeployString(d.option.DeployConfig, "endpoint"), - accessKeyId, - accessKeySecret, - ) - if err != nil { - return nil, fmt.Errorf("create aliyun client error: %w", err) +func (d *AliyunOSSDeployer) createSdkClient(accessKeyId, accessKeySecret, endpoint string) (*oss.Client, error) { + if endpoint == "" { + endpoint = "oss.aliyuncs.com" } + + client, err := oss.New(endpoint, accessKeyId, accessKeySecret) + if err != nil { + return nil, err + } + return client, nil } diff --git a/internal/deployer/deployer.go b/internal/deployer/deployer.go index c4530df4..eae80d5a 100644 --- a/internal/deployer/deployer.go +++ b/internal/deployer/deployer.go @@ -17,7 +17,7 @@ import ( const ( targetAliyunOSS = "aliyun-oss" targetAliyunCDN = "aliyun-cdn" - targetAliyunESA = "aliyun-dcdn" + targetAliyunDCDN = "aliyun-dcdn" targetAliyunCLB = "aliyun-clb" targetAliyunALB = "aliyun-alb" targetAliyunNLB = "aliyun-nlb" @@ -109,8 +109,8 @@ func getWithDeployConfig(record *models.Record, cert *applicant.Certificate, dep return NewAliyunOSSDeployer(option) case targetAliyunCDN: return NewAliyunCDNDeployer(option) - case targetAliyunESA: - return NewAliyunESADeployer(option) + case targetAliyunDCDN: + return NewAliyunDCDNDeployer(option) case targetAliyunCLB: return NewAliyunCLBDeployer(option) case targetAliyunALB: @@ -118,7 +118,7 @@ func getWithDeployConfig(record *models.Record, cert *applicant.Certificate, dep case targetAliyunNLB: return NewAliyunNLBDeployer(option) case targetTencentCDN: - return NewTencentCDNDeployer(option) + return NewTencentCDNDeployer(option) case targetTencentECDN: return NewTencentECDNDeployer(option) case targetTencentCLB: diff --git a/internal/deployer/k8s_secret.go b/internal/deployer/k8s_secret.go index dfc56889..6468a0d2 100644 --- a/internal/deployer/k8s_secret.go +++ b/internal/deployer/k8s_secret.go @@ -6,8 +6,8 @@ import ( "fmt" "strings" - corev1 "k8s.io/api/core/v1" - k8sMetaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" + k8sCore "k8s.io/api/core/v1" + k8sMeta "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" @@ -49,46 +49,46 @@ func (d *K8sSecretDeployer) Deploy(ctx context.Context) error { d.infos = append(d.infos, toStr("kubeClient create success.", nil)) - namespace := getDeployString(d.option.DeployConfig, "namespace") + namespace := d.option.DeployConfig.GetConfigAsString("namespace") if namespace == "" { namespace = "default" } - secretName := getDeployString(d.option.DeployConfig, "secretName") + secretName := d.option.DeployConfig.GetConfigAsString("secretName") if secretName == "" { return fmt.Errorf("k8s secret name is empty") } - secretDataKeyForCrt := getDeployString(d.option.DeployConfig, "secretDataKeyForCrt") + secretDataKeyForCrt := d.option.DeployConfig.GetConfigAsString("secretDataKeyForCrt") if secretDataKeyForCrt == "" { namespace = "tls.crt" } - secretDataKeyForKey := getDeployString(d.option.DeployConfig, "secretDataKeyForKey") + secretDataKeyForKey := d.option.DeployConfig.GetConfigAsString("secretDataKeyForKey") if secretDataKeyForKey == "" { namespace = "tls.key" } - certificate, err := x509.ParseCertificateFromPEM(d.option.Certificate.Certificate) + certX509, err := x509.ParseCertificateFromPEM(d.option.Certificate.Certificate) if err != nil { return fmt.Errorf("failed to parse certificate: %w", err) } - secretPayload := corev1.Secret{ - TypeMeta: k8sMetaV1.TypeMeta{ + secretPayload := k8sCore.Secret{ + TypeMeta: k8sMeta.TypeMeta{ Kind: "Secret", APIVersion: "v1", }, - ObjectMeta: k8sMetaV1.ObjectMeta{ + ObjectMeta: k8sMeta.ObjectMeta{ Name: secretName, Annotations: map[string]string{ "certimate/domains": d.option.Domain, - "certimate/alt-names": strings.Join(certificate.DNSNames, ","), - "certimate/common-name": certificate.Subject.CommonName, - "certimate/issuer-organization": strings.Join(certificate.Issuer.Organization, ","), + "certimate/alt-names": strings.Join(certX509.DNSNames, ","), + "certimate/common-name": certX509.Subject.CommonName, + "certimate/issuer-organization": strings.Join(certX509.Issuer.Organization, ","), }, }, - Type: corev1.SecretType("kubernetes.io/tls"), + Type: k8sCore.SecretType("kubernetes.io/tls"), } secretPayload.Data = make(map[string][]byte) @@ -96,9 +96,9 @@ func (d *K8sSecretDeployer) Deploy(ctx context.Context) error { secretPayload.Data[secretDataKeyForKey] = []byte(d.option.Certificate.PrivateKey) // 获取 Secret 实例 - _, err = client.CoreV1().Secrets(namespace).Get(context.TODO(), secretName, k8sMetaV1.GetOptions{}) + _, err = client.CoreV1().Secrets(namespace).Get(context.TODO(), secretName, k8sMeta.GetOptions{}) if err != nil { - _, err = client.CoreV1().Secrets(namespace).Create(context.TODO(), &secretPayload, k8sMetaV1.CreateOptions{}) + _, err = client.CoreV1().Secrets(namespace).Create(context.TODO(), &secretPayload, k8sMeta.CreateOptions{}) if err != nil { return fmt.Errorf("failed to create k8s secret: %w", err) } else { @@ -108,7 +108,7 @@ func (d *K8sSecretDeployer) Deploy(ctx context.Context) error { } // 更新 Secret 实例 - _, err = client.CoreV1().Secrets(namespace).Update(ctx, &secretPayload, k8sMetaV1.UpdateOptions{}) + _, err = client.CoreV1().Secrets(namespace).Update(ctx, &secretPayload, k8sMeta.UpdateOptions{}) if err != nil { return fmt.Errorf("failed to update k8s secret: %w", err) } diff --git a/internal/pkg/core/uploader/uploader_aliyun_cas.go b/internal/pkg/core/uploader/uploader_aliyun_cas.go index b6a1f792..6a90331d 100644 --- a/internal/pkg/core/uploader/uploader_aliyun_cas.go +++ b/internal/pkg/core/uploader/uploader_aliyun_cas.go @@ -6,9 +6,8 @@ import ( "strings" "time" - cas20200407 "github.com/alibabacloud-go/cas-20200407/v3/client" - openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client" - util "github.com/alibabacloud-go/tea-utils/v2/service" + aliyunCas "github.com/alibabacloud-go/cas-20200407/v3/client" + aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client" "github.com/alibabacloud-go/tea/tea" "github.com/usual2970/certimate/internal/pkg/utils/x509" @@ -21,9 +20,8 @@ type AliyunCASUploaderConfig struct { } type AliyunCASUploader struct { - config *AliyunCASUploaderConfig - sdkClient *cas20200407.Client - sdkRuntime *util.RuntimeOptions + config *AliyunCASUploaderConfig + sdkClient *aliyunCas.Client } func NewAliyunCASUploader(config *AliyunCASUploaderConfig) (Uploader, error) { @@ -37,9 +35,8 @@ func NewAliyunCASUploader(config *AliyunCASUploaderConfig) (Uploader, error) { } return &AliyunCASUploader{ - config: config, - sdkClient: client, - sdkRuntime: &util.RuntimeOptions{}, + config: config, + sdkClient: client, }, nil } @@ -56,12 +53,12 @@ func (u *AliyunCASUploader) Upload(ctx context.Context, certPem string, privkeyP listUserCertificateOrderPage := int64(1) listUserCertificateOrderLimit := int64(50) for { - listUserCertificateOrderReq := &cas20200407.ListUserCertificateOrderRequest{ + listUserCertificateOrderReq := &aliyunCas.ListUserCertificateOrderRequest{ CurrentPage: tea.Int64(listUserCertificateOrderPage), ShowSize: tea.Int64(listUserCertificateOrderLimit), OrderType: tea.String("CERT"), } - listUserCertificateOrderResp, err := u.sdkClient.ListUserCertificateOrderWithOptions(listUserCertificateOrderReq, u.sdkRuntime) + listUserCertificateOrderResp, err := u.sdkClient.ListUserCertificateOrder(listUserCertificateOrderReq) if err != nil { return nil, fmt.Errorf("failed to execute sdk request 'cas.ListUserCertificateOrder': %w", err) } @@ -69,10 +66,10 @@ func (u *AliyunCASUploader) Upload(ctx context.Context, certPem string, privkeyP if listUserCertificateOrderResp.Body.CertificateOrderList != nil { for _, certDetail := range listUserCertificateOrderResp.Body.CertificateOrderList { if strings.EqualFold(certX509.SerialNumber.Text(16), *certDetail.SerialNo) { - getUserCertificateDetailReq := &cas20200407.GetUserCertificateDetailRequest{ + getUserCertificateDetailReq := &aliyunCas.GetUserCertificateDetailRequest{ CertId: certDetail.CertificateId, } - getUserCertificateDetailResp, err := u.sdkClient.GetUserCertificateDetailWithOptions(getUserCertificateDetailReq, u.sdkRuntime) + getUserCertificateDetailResp, err := u.sdkClient.GetUserCertificateDetail(getUserCertificateDetailReq) if err != nil { return nil, fmt.Errorf("failed to execute sdk request 'cas.GetUserCertificateDetail': %w", err) } @@ -116,12 +113,12 @@ func (u *AliyunCASUploader) Upload(ctx context.Context, certPem string, privkeyP // 上传新证书 // REF: https://help.aliyun.com/zh/ssl-certificate/developer-reference/api-cas-2020-04-07-uploadusercertificate - uploadUserCertificateReq := &cas20200407.UploadUserCertificateRequest{ + uploadUserCertificateReq := &aliyunCas.UploadUserCertificateRequest{ Name: tea.String(certName), Cert: tea.String(certPem), Key: tea.String(privkeyPem), } - uploadUserCertificateResp, err := u.sdkClient.UploadUserCertificateWithOptions(uploadUserCertificateReq, u.sdkRuntime) + uploadUserCertificateResp, err := u.sdkClient.UploadUserCertificate(uploadUserCertificateReq) if err != nil { return nil, fmt.Errorf("failed to execute sdk request 'cas.UploadUserCertificate': %w", err) } @@ -133,12 +130,12 @@ func (u *AliyunCASUploader) Upload(ctx context.Context, certPem string, privkeyP }, nil } -func (u *AliyunCASUploader) createSdkClient(accessKeyId, accessKeySecret, region string) (*cas20200407.Client, error) { +func (u *AliyunCASUploader) createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunCas.Client, error) { if region == "" { region = "cn-hangzhou" // CAS 服务默认区域:华东一杭州 } - aConfig := &openapi.Config{ + aConfig := &aliyunOpen.Config{ AccessKeyId: tea.String(accessKeyId), AccessKeySecret: tea.String(accessKeySecret), } @@ -152,7 +149,7 @@ func (u *AliyunCASUploader) createSdkClient(accessKeyId, accessKeySecret, region } aConfig.Endpoint = tea.String(endpoint) - client, err := cas20200407.NewClient(aConfig) + client, err := aliyunCas.NewClient(aConfig) if err != nil { return nil, err } diff --git a/internal/pkg/core/uploader/uploader_aliyun_slb.go b/internal/pkg/core/uploader/uploader_aliyun_slb.go index 99f3c484..2028a04b 100644 --- a/internal/pkg/core/uploader/uploader_aliyun_slb.go +++ b/internal/pkg/core/uploader/uploader_aliyun_slb.go @@ -8,9 +8,8 @@ import ( "strings" "time" - openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client" - slb20140515 "github.com/alibabacloud-go/slb-20140515/v4/client" - util "github.com/alibabacloud-go/tea-utils/v2/service" + aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client" + aliyunSlb "github.com/alibabacloud-go/slb-20140515/v4/client" "github.com/alibabacloud-go/tea/tea" "github.com/usual2970/certimate/internal/pkg/utils/x509" @@ -23,9 +22,8 @@ type AliyunSLBUploaderConfig struct { } type AliyunSLBUploader struct { - config *AliyunSLBUploaderConfig - sdkClient *slb20140515.Client - sdkRuntime *util.RuntimeOptions + config *AliyunSLBUploaderConfig + sdkClient *aliyunSlb.Client } func NewAliyunSLBUploader(config *AliyunSLBUploaderConfig) (Uploader, error) { @@ -39,9 +37,8 @@ func NewAliyunSLBUploader(config *AliyunSLBUploaderConfig) (Uploader, error) { } return &AliyunSLBUploader{ - config: config, - sdkClient: client, - sdkRuntime: &util.RuntimeOptions{}, + config: config, + sdkClient: client, }, nil } @@ -54,10 +51,10 @@ func (u *AliyunSLBUploader) Upload(ctx context.Context, certPem string, privkeyP // 查询证书列表,避免重复上传 // REF: https://help.aliyun.com/zh/slb/classic-load-balancer/developer-reference/api-slb-2014-05-15-describeservercertificates - describeServerCertificatesReq := &slb20140515.DescribeServerCertificatesRequest{ + describeServerCertificatesReq := &aliyunSlb.DescribeServerCertificatesRequest{ RegionId: tea.String(u.config.Region), } - describeServerCertificatesResp, err := u.sdkClient.DescribeServerCertificatesWithOptions(describeServerCertificatesReq, u.sdkRuntime) + describeServerCertificatesResp, err := u.sdkClient.DescribeServerCertificates(describeServerCertificatesReq) if err != nil { return nil, fmt.Errorf("failed to execute sdk request 'slb.DescribeServerCertificates': %w", err) } @@ -85,13 +82,13 @@ func (u *AliyunSLBUploader) Upload(ctx context.Context, certPem string, privkeyP // 上传新证书 // REF: https://help.aliyun.com/zh/slb/classic-load-balancer/developer-reference/api-slb-2014-05-15-uploadservercertificate - uploadServerCertificateReq := &slb20140515.UploadServerCertificateRequest{ + uploadServerCertificateReq := &aliyunSlb.UploadServerCertificateRequest{ RegionId: tea.String(u.config.Region), ServerCertificateName: tea.String(certName), ServerCertificate: tea.String(certPem), PrivateKey: tea.String(privkeyPem), } - uploadServerCertificateResp, err := u.sdkClient.UploadServerCertificateWithOptions(uploadServerCertificateReq, u.sdkRuntime) + uploadServerCertificateResp, err := u.sdkClient.UploadServerCertificate(uploadServerCertificateReq) if err != nil { return nil, fmt.Errorf("failed to execute sdk request 'slb.UploadServerCertificate': %w", err) } @@ -103,12 +100,12 @@ func (u *AliyunSLBUploader) Upload(ctx context.Context, certPem string, privkeyP }, nil } -func (u *AliyunSLBUploader) createSdkClient(accessKeyId, accessKeySecret, region string) (*slb20140515.Client, error) { +func (u *AliyunSLBUploader) createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunSlb.Client, error) { if region == "" { region = "cn-hangzhou" // SLB 服务默认区域:华东一杭州 } - aConfig := &openapi.Config{ + aConfig := &aliyunOpen.Config{ AccessKeyId: tea.String(accessKeyId), AccessKeySecret: tea.String(accessKeySecret), } @@ -125,7 +122,7 @@ func (u *AliyunSLBUploader) createSdkClient(accessKeyId, accessKeySecret, region } aConfig.Endpoint = tea.String(endpoint) - client, err := slb20140515.NewClient(aConfig) + client, err := aliyunSlb.NewClient(aConfig) if err != nil { return nil, err } From 26fa8e75bdb347479ca8334207cd161ef9a035ba Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Tue, 29 Oct 2024 21:32:48 +0800 Subject: [PATCH 02/18] refactor: clean code --- internal/deployer/aliyun_alb.go | 31 +++++---- internal/deployer/aliyun_cdn.go | 9 ++- internal/deployer/aliyun_clb.go | 33 +++++----- internal/deployer/aliyun_dcdn.go | 9 ++- internal/deployer/aliyun_nlb.go | 29 +++++---- internal/deployer/aliyun_oss.go | 9 ++- internal/deployer/deployer.go | 2 +- internal/deployer/huaweicloud_cdn.go | 15 +++-- internal/deployer/huaweicloud_elb.go | 22 ++++--- internal/deployer/k8s_secret.go | 65 +++++++++---------- internal/deployer/local.go | 30 ++++----- internal/deployer/qiniu_cdn.go | 4 +- .../pkg/core/uploader/uploader_aliyun_cas.go | 9 +-- .../pkg/core/uploader/uploader_aliyun_slb.go | 7 +- .../core/uploader/uploader_huaweicloud_elb.go | 12 ++-- .../core/uploader/uploader_huaweicloud_scm.go | 9 +-- .../uploader/uploader_tencentcloud_ssl.go | 42 ++++++------ internal/pkg/utils/fs/fs.go | 9 +-- internal/pkg/utils/x509/x509.go | 18 ++--- 19 files changed, 192 insertions(+), 172 deletions(-) diff --git a/internal/deployer/aliyun_alb.go b/internal/deployer/aliyun_alb.go index 4ee68a7a..91f6f0c7 100644 --- a/internal/deployer/aliyun_alb.go +++ b/internal/deployer/aliyun_alb.go @@ -9,6 +9,7 @@ import ( aliyunAlb "github.com/alibabacloud-go/alb-20200616/v2/client" aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client" "github.com/alibabacloud-go/tea/tea" + xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/domain" "github.com/usual2970/certimate/internal/pkg/core/uploader" @@ -24,7 +25,9 @@ type AliyunALBDeployer struct { func NewAliyunALBDeployer(option *DeployerOption) (Deployer, error) { access := &domain.AliyunAccess{} - json.Unmarshal([]byte(option.Access), access) + if err := json.Unmarshal([]byte(option.Access), access); err != nil { + return nil, xerrors.Wrap(err, "failed to get access") + } client, err := (&AliyunALBDeployer{}).createSdkClient( access.AccessKeyId, @@ -32,7 +35,7 @@ func NewAliyunALBDeployer(option *DeployerOption) (Deployer, error) { option.DeployConfig.GetConfigAsString("region"), ) if err != nil { - return nil, err + return nil, xerrors.Wrap(err, "failed to create sdk client") } uploader, err := uploader.NewAliyunCASUploader(&uploader.AliyunCASUploaderConfig{ @@ -41,7 +44,7 @@ func NewAliyunALBDeployer(option *DeployerOption) (Deployer, error) { Region: option.DeployConfig.GetConfigAsString("region"), }) if err != nil { - return nil, err + return nil, xerrors.Wrap(err, "failed to create ssl uploader") } return &AliyunALBDeployer{ @@ -119,7 +122,7 @@ func (d *AliyunALBDeployer) deployToLoadbalancer(ctx context.Context) error { } getLoadBalancerAttributeResp, err := d.sdkClient.GetLoadBalancerAttribute(getLoadBalancerAttributeReq) if err != nil { - return fmt.Errorf("failed to execute sdk request 'alb.GetLoadBalancerAttribute': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'alb.GetLoadBalancerAttribute'") } d.infos = append(d.infos, toStr("已查询到 ALB 负载均衡实例", getLoadBalancerAttributeResp)) @@ -138,7 +141,7 @@ func (d *AliyunALBDeployer) deployToLoadbalancer(ctx context.Context) error { } listListenersResp, err := d.sdkClient.ListListeners(listListenersReq) if err != nil { - return fmt.Errorf("failed to execute sdk request 'alb.ListListeners': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'alb.ListListeners'") } if listListenersResp.Body.Listeners != nil { @@ -170,7 +173,7 @@ func (d *AliyunALBDeployer) deployToLoadbalancer(ctx context.Context) error { } listListenersResp, err := d.sdkClient.ListListeners(listListenersReq) if err != nil { - return fmt.Errorf("failed to execute sdk request 'alb.ListListeners': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'alb.ListListeners'") } if listListenersResp.Body.Listeners != nil { @@ -190,17 +193,17 @@ func (d *AliyunALBDeployer) deployToLoadbalancer(ctx context.Context) error { d.infos = append(d.infos, toStr("已查询到 ALB 负载均衡实例下的全部 QUIC 监听", aliListenerIds)) // 上传证书到 SSL - uploadResult, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey) + 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("已上传证书", uploadResult)) + d.infos = append(d.infos, toStr("已上传证书", upres)) // 批量更新监听证书 var errs []error for _, aliListenerId := range aliListenerIds { - if err := d.updateListenerCertificate(ctx, aliListenerId, uploadResult.CertId); err != nil { + if err := d.updateListenerCertificate(ctx, aliListenerId, upres.CertId); err != nil { errs = append(errs, err) } } @@ -218,15 +221,15 @@ func (d *AliyunALBDeployer) deployToListener(ctx context.Context) error { } // 上传证书到 SSL - uploadResult, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey) + 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("已上传证书", uploadResult)) + d.infos = append(d.infos, toStr("已上传证书", upres)) // 更新监听 - if err := d.updateListenerCertificate(ctx, aliListenerId, uploadResult.CertId); err != nil { + if err := d.updateListenerCertificate(ctx, aliListenerId, upres.CertId); err != nil { return err } @@ -241,7 +244,7 @@ func (d *AliyunALBDeployer) updateListenerCertificate(ctx context.Context, aliLi } getListenerAttributeResp, err := d.sdkClient.GetListenerAttribute(getListenerAttributeReq) if err != nil { - return fmt.Errorf("failed to execute sdk request 'alb.GetListenerAttribute': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'alb.GetListenerAttribute'") } d.infos = append(d.infos, toStr("已查询到 ALB 监听配置", getListenerAttributeResp)) @@ -256,7 +259,7 @@ func (d *AliyunALBDeployer) updateListenerCertificate(ctx context.Context, aliLi } updateListenerAttributeResp, err := d.sdkClient.UpdateListenerAttribute(updateListenerAttributeReq) if err != nil { - return fmt.Errorf("failed to execute sdk request 'alb.UpdateListenerAttribute': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'alb.UpdateListenerAttribute'") } d.infos = append(d.infos, toStr("已更新 ALB 监听配置", updateListenerAttributeResp)) diff --git a/internal/deployer/aliyun_cdn.go b/internal/deployer/aliyun_cdn.go index 2b633182..29e9bf15 100644 --- a/internal/deployer/aliyun_cdn.go +++ b/internal/deployer/aliyun_cdn.go @@ -8,6 +8,7 @@ import ( aliyunCdn "github.com/alibabacloud-go/cdn-20180510/v5/client" aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client" "github.com/alibabacloud-go/tea/tea" + xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/domain" "github.com/usual2970/certimate/internal/utils/rand" @@ -22,14 +23,16 @@ type AliyunCDNDeployer struct { func NewAliyunCDNDeployer(option *DeployerOption) (Deployer, error) { access := &domain.AliyunAccess{} - json.Unmarshal([]byte(option.Access), access) + if err := json.Unmarshal([]byte(option.Access), access); err != nil { + return nil, xerrors.Wrap(err, "failed to get access") + } client, err := (&AliyunCDNDeployer{}).createSdkClient( access.AccessKeyId, access.AccessKeySecret, ) if err != nil { - return nil, err + return nil, xerrors.Wrap(err, "failed to create sdk client") } return &AliyunCDNDeployer{ @@ -63,7 +66,7 @@ func (d *AliyunCDNDeployer) Deploy(ctx context.Context) error { } setCdnDomainSSLCertificateResp, err := d.sdkClient.SetCdnDomainSSLCertificate(setCdnDomainSSLCertificateReq) if err != nil { - return fmt.Errorf("failed to execute sdk request 'cdn.SetCdnDomainSSLCertificate': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'cdn.SetCdnDomainSSLCertificate'") } d.infos = append(d.infos, toStr("已设置 CDN 域名证书", setCdnDomainSSLCertificateResp)) diff --git a/internal/deployer/aliyun_clb.go b/internal/deployer/aliyun_clb.go index 87f68a02..8af40687 100644 --- a/internal/deployer/aliyun_clb.go +++ b/internal/deployer/aliyun_clb.go @@ -9,6 +9,7 @@ import ( aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client" aliyunSlb "github.com/alibabacloud-go/slb-20140515/v4/client" "github.com/alibabacloud-go/tea/tea" + xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/domain" "github.com/usual2970/certimate/internal/pkg/core/uploader" @@ -24,7 +25,9 @@ type AliyunCLBDeployer struct { func NewAliyunCLBDeployer(option *DeployerOption) (Deployer, error) { access := &domain.AliyunAccess{} - json.Unmarshal([]byte(option.Access), access) + if err := json.Unmarshal([]byte(option.Access), access); err != nil { + return nil, xerrors.Wrap(err, "failed to get access") + } client, err := (&AliyunCLBDeployer{}).createSdkClient( access.AccessKeyId, @@ -32,7 +35,7 @@ func NewAliyunCLBDeployer(option *DeployerOption) (Deployer, error) { option.DeployConfig.GetConfigAsString("region"), ) if err != nil { - return nil, err + return nil, xerrors.Wrap(err, "failed to create sdk client") } uploader, err := uploader.NewAliyunSLBUploader(&uploader.AliyunSLBUploaderConfig{ @@ -41,7 +44,7 @@ func NewAliyunCLBDeployer(option *DeployerOption) (Deployer, error) { Region: option.DeployConfig.GetConfigAsString("region"), }) if err != nil { - return nil, err + return nil, xerrors.Wrap(err, "failed to create ssl uploader") } return &AliyunCLBDeployer{ @@ -123,7 +126,7 @@ func (d *AliyunCLBDeployer) deployToLoadbalancer(ctx context.Context) error { } describeLoadBalancerAttributeResp, err := d.sdkClient.DescribeLoadBalancerAttribute(describeLoadBalancerAttributeReq) if err != nil { - return fmt.Errorf("failed to execute sdk request 'slb.DescribeLoadBalancerAttribute': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'slb.DescribeLoadBalancerAttribute'") } d.infos = append(d.infos, toStr("已查询到 CLB 负载均衡实例", describeLoadBalancerAttributeResp)) @@ -143,7 +146,7 @@ func (d *AliyunCLBDeployer) deployToLoadbalancer(ctx context.Context) error { } describeLoadBalancerListenersResp, err := d.sdkClient.DescribeLoadBalancerListeners(describeLoadBalancerListenersReq) if err != nil { - return fmt.Errorf("failed to execute sdk request 'slb.DescribeLoadBalancerListeners': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'slb.DescribeLoadBalancerListeners'") } if describeLoadBalancerListenersResp.Body.Listeners != nil { @@ -163,17 +166,17 @@ func (d *AliyunCLBDeployer) deployToLoadbalancer(ctx context.Context) error { d.infos = append(d.infos, toStr("已查询到 CLB 负载均衡实例下的全部 HTTPS 监听", aliListenerPorts)) // 上传证书到 SLB - uploadResult, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey) + 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("已上传证书", uploadResult)) + d.infos = append(d.infos, toStr("已上传证书", upres)) // 批量更新监听证书 var errs []error for _, aliListenerPort := range aliListenerPorts { - if err := d.updateListenerCertificate(ctx, aliLoadbalancerId, aliListenerPort, uploadResult.CertId); err != nil { + if err := d.updateListenerCertificate(ctx, aliLoadbalancerId, aliListenerPort, upres.CertId); err != nil { errs = append(errs, err) } } @@ -196,15 +199,15 @@ func (d *AliyunCLBDeployer) deployToListener(ctx context.Context) error { } // 上传证书到 SLB - uploadResult, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey) + 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("已上传证书", uploadResult)) + d.infos = append(d.infos, toStr("已上传证书", upres)) // 更新监听 - if err := d.updateListenerCertificate(ctx, aliLoadbalancerId, aliListenerPort, uploadResult.CertId); err != nil { + if err := d.updateListenerCertificate(ctx, aliLoadbalancerId, aliListenerPort, upres.CertId); err != nil { return err } @@ -220,7 +223,7 @@ func (d *AliyunCLBDeployer) updateListenerCertificate(ctx context.Context, aliLo } describeLoadBalancerHTTPSListenerAttributeResp, err := d.sdkClient.DescribeLoadBalancerHTTPSListenerAttribute(describeLoadBalancerHTTPSListenerAttributeReq) if err != nil { - return fmt.Errorf("failed to execute sdk request 'slb.DescribeLoadBalancerHTTPSListenerAttribute': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'slb.DescribeLoadBalancerHTTPSListenerAttribute'") } d.infos = append(d.infos, toStr("已查询到 CLB HTTPS 监听配置", describeLoadBalancerHTTPSListenerAttributeResp)) @@ -234,7 +237,7 @@ func (d *AliyunCLBDeployer) updateListenerCertificate(ctx context.Context, aliLo } describeDomainExtensionsResp, err := d.sdkClient.DescribeDomainExtensions(describeDomainExtensionsReq) if err != nil { - return fmt.Errorf("failed to execute sdk request 'slb.DescribeDomainExtensions': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'slb.DescribeDomainExtensions'") } d.infos = append(d.infos, toStr("已查询到 CLB 扩展域名", describeDomainExtensionsResp)) @@ -256,7 +259,7 @@ func (d *AliyunCLBDeployer) updateListenerCertificate(ctx context.Context, aliLo } _, err := d.sdkClient.SetDomainExtensionAttribute(setDomainExtensionAttributeReq) if err != nil { - return fmt.Errorf("failed to execute sdk request 'slb.SetDomainExtensionAttribute': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'slb.SetDomainExtensionAttribute'") } } } @@ -273,7 +276,7 @@ func (d *AliyunCLBDeployer) updateListenerCertificate(ctx context.Context, aliLo } setLoadBalancerHTTPSListenerAttributeResp, err := d.sdkClient.SetLoadBalancerHTTPSListenerAttribute(setLoadBalancerHTTPSListenerAttributeReq) if err != nil { - return fmt.Errorf("failed to execute sdk request 'slb.SetLoadBalancerHTTPSListenerAttribute': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'slb.SetLoadBalancerHTTPSListenerAttribute'") } d.infos = append(d.infos, toStr("已更新 CLB HTTPS 监听配置", setLoadBalancerHTTPSListenerAttributeResp)) diff --git a/internal/deployer/aliyun_dcdn.go b/internal/deployer/aliyun_dcdn.go index f760e92f..37641016 100644 --- a/internal/deployer/aliyun_dcdn.go +++ b/internal/deployer/aliyun_dcdn.go @@ -9,6 +9,7 @@ import ( aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client" aliyunDcdn "github.com/alibabacloud-go/dcdn-20180115/v3/client" "github.com/alibabacloud-go/tea/tea" + xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/domain" "github.com/usual2970/certimate/internal/utils/rand" @@ -23,14 +24,16 @@ type AliyunDCDNDeployer struct { func NewAliyunDCDNDeployer(option *DeployerOption) (Deployer, error) { access := &domain.AliyunAccess{} - json.Unmarshal([]byte(option.Access), access) + if err := json.Unmarshal([]byte(option.Access), access); err != nil { + return nil, xerrors.Wrap(err, "failed to get access") + } client, err := (&AliyunDCDNDeployer{}).createSdkClient( access.AccessKeyId, access.AccessKeySecret, ) if err != nil { - return nil, err + return nil, xerrors.Wrap(err, "failed to create sdk client") } return &AliyunDCDNDeployer{ @@ -70,7 +73,7 @@ func (d *AliyunDCDNDeployer) Deploy(ctx context.Context) error { } setDcdnDomainSSLCertificateResp, err := d.sdkClient.SetDcdnDomainSSLCertificate(setDcdnDomainSSLCertificateReq) if err != nil { - return fmt.Errorf("failed to execute sdk request 'dcdn.SetDcdnDomainSSLCertificate': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'dcdn.SetDcdnDomainSSLCertificate'") } d.infos = append(d.infos, toStr("已配置 DCDN 域名证书", setDcdnDomainSSLCertificateResp)) diff --git a/internal/deployer/aliyun_nlb.go b/internal/deployer/aliyun_nlb.go index 59cc0163..36034036 100644 --- a/internal/deployer/aliyun_nlb.go +++ b/internal/deployer/aliyun_nlb.go @@ -9,6 +9,7 @@ import ( aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client" aliyunNlb "github.com/alibabacloud-go/nlb-20220430/v2/client" "github.com/alibabacloud-go/tea/tea" + xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/domain" "github.com/usual2970/certimate/internal/pkg/core/uploader" @@ -24,7 +25,9 @@ type AliyunNLBDeployer struct { func NewAliyunNLBDeployer(option *DeployerOption) (Deployer, error) { access := &domain.AliyunAccess{} - json.Unmarshal([]byte(option.Access), access) + if err := json.Unmarshal([]byte(option.Access), access); err != nil { + return nil, xerrors.Wrap(err, "failed to get access") + } client, err := (&AliyunNLBDeployer{}).createSdkClient( access.AccessKeyId, @@ -32,7 +35,7 @@ func NewAliyunNLBDeployer(option *DeployerOption) (Deployer, error) { option.DeployConfig.GetConfigAsString("region"), ) if err != nil { - return nil, err + return nil, xerrors.Wrap(err, "failed to create sdk client") } uploader, err := uploader.NewAliyunCASUploader(&uploader.AliyunCASUploaderConfig{ @@ -41,7 +44,7 @@ func NewAliyunNLBDeployer(option *DeployerOption) (Deployer, error) { Region: option.DeployConfig.GetConfigAsString("region"), }) if err != nil { - return nil, err + return nil, xerrors.Wrap(err, "failed to create ssl uploader") } return &AliyunNLBDeployer{ @@ -117,7 +120,7 @@ func (d *AliyunNLBDeployer) deployToLoadbalancer(ctx context.Context) error { } getLoadBalancerAttributeResp, err := d.sdkClient.GetLoadBalancerAttribute(getLoadBalancerAttributeReq) if err != nil { - return fmt.Errorf("failed to execute sdk request 'nlb.GetLoadBalancerAttribute': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'nlb.GetLoadBalancerAttribute'") } d.infos = append(d.infos, toStr("已查询到 NLB 负载均衡实例", getLoadBalancerAttributeResp)) @@ -136,7 +139,7 @@ func (d *AliyunNLBDeployer) deployToLoadbalancer(ctx context.Context) error { } listListenersResp, err := d.sdkClient.ListListeners(listListenersReq) if err != nil { - return fmt.Errorf("failed to execute sdk request 'nlb.ListListeners': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'nlb.ListListeners'") } if listListenersResp.Body.Listeners != nil { @@ -156,17 +159,17 @@ func (d *AliyunNLBDeployer) deployToLoadbalancer(ctx context.Context) error { d.infos = append(d.infos, toStr("已查询到 NLB 负载均衡实例下的全部 TCPSSL 监听", aliListenerIds)) // 上传证书到 SSL - uploadResult, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey) + 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("已上传证书", uploadResult)) + d.infos = append(d.infos, toStr("已上传证书", upres)) // 批量更新监听证书 var errs []error for _, aliListenerId := range aliListenerIds { - if err := d.updateListenerCertificate(ctx, aliListenerId, uploadResult.CertId); err != nil { + if err := d.updateListenerCertificate(ctx, aliListenerId, upres.CertId); err != nil { errs = append(errs, err) } } @@ -184,15 +187,15 @@ func (d *AliyunNLBDeployer) deployToListener(ctx context.Context) error { } // 上传证书到 SSL - uploadResult, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey) + 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("已上传证书", uploadResult)) + d.infos = append(d.infos, toStr("已上传证书", upres)) // 更新监听 - if err := d.updateListenerCertificate(ctx, aliListenerId, uploadResult.CertId); err != nil { + if err := d.updateListenerCertificate(ctx, aliListenerId, upres.CertId); err != nil { return err } @@ -207,7 +210,7 @@ func (d *AliyunNLBDeployer) updateListenerCertificate(ctx context.Context, aliLi } getListenerAttributeResp, err := d.sdkClient.GetListenerAttribute(getListenerAttributeReq) if err != nil { - return fmt.Errorf("failed to execute sdk request 'nlb.GetListenerAttribute': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'nlb.GetListenerAttribute'") } d.infos = append(d.infos, toStr("已查询到 NLB 监听配置", getListenerAttributeResp)) @@ -220,7 +223,7 @@ func (d *AliyunNLBDeployer) updateListenerCertificate(ctx context.Context, aliLi } updateListenerAttributeResp, err := d.sdkClient.UpdateListenerAttribute(updateListenerAttributeReq) if err != nil { - return fmt.Errorf("failed to execute sdk request 'nlb.UpdateListenerAttribute': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'nlb.UpdateListenerAttribute'") } d.infos = append(d.infos, toStr("已更新 NLB 监听配置", updateListenerAttributeResp)) diff --git a/internal/deployer/aliyun_oss.go b/internal/deployer/aliyun_oss.go index 47173d0e..f0ee5f56 100644 --- a/internal/deployer/aliyun_oss.go +++ b/internal/deployer/aliyun_oss.go @@ -7,6 +7,7 @@ import ( "fmt" "github.com/aliyun/aliyun-oss-go-sdk/oss" + xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/domain" ) @@ -20,7 +21,9 @@ type AliyunOSSDeployer struct { func NewAliyunOSSDeployer(option *DeployerOption) (Deployer, error) { access := &domain.AliyunAccess{} - json.Unmarshal([]byte(option.Access), access) + if err := json.Unmarshal([]byte(option.Access), access); err != nil { + return nil, xerrors.Wrap(err, "failed to get access") + } client, err := (&AliyunOSSDeployer{}).createSdkClient( access.AccessKeyId, @@ -28,7 +31,7 @@ func NewAliyunOSSDeployer(option *DeployerOption) (Deployer, error) { option.DeployConfig.GetConfigAsString("endpoint"), ) if err != nil { - return nil, err + return nil, xerrors.Wrap(err, "failed to create sdk client") } return &AliyunOSSDeployer{ @@ -63,7 +66,7 @@ func (d *AliyunOSSDeployer) Deploy(ctx context.Context) error { }, }) if err != nil { - return fmt.Errorf("failed to execute sdk request 'oss.PutBucketCnameWithCertificate': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'oss.PutBucketCnameWithCertificate'") } return nil diff --git a/internal/deployer/deployer.go b/internal/deployer/deployer.go index 100f6753..57ae4568 100644 --- a/internal/deployer/deployer.go +++ b/internal/deployer/deployer.go @@ -204,7 +204,7 @@ func convertPEMToPFX(certificate string, privateKey string, password string) ([] pfxData, err := pkcs12.LegacyRC2.Encode(privkey, cert, nil, password) if err != nil { - return nil, fmt.Errorf("failed to encode as pfx %w", err) + return nil, err } return pfxData, nil diff --git a/internal/deployer/huaweicloud_cdn.go b/internal/deployer/huaweicloud_cdn.go index ab6e936b..e8f35171 100644 --- a/internal/deployer/huaweicloud_cdn.go +++ b/internal/deployer/huaweicloud_cdn.go @@ -10,6 +10,7 @@ import ( hcCdn "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/cdn/v2" hcCdnModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/cdn/v2/model" hcCdnRegion "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/cdn/v2/region" + xerrors "github.com/pkg/errors" "github.com/usual2970/certimate/internal/domain" "github.com/usual2970/certimate/internal/pkg/core/uploader" @@ -27,7 +28,7 @@ type HuaweiCloudCDNDeployer struct { func NewHuaweiCloudCDNDeployer(option *DeployerOption) (Deployer, error) { access := &domain.HuaweiCloudAccess{} if err := json.Unmarshal([]byte(option.Access), access); err != nil { - return nil, err + return nil, xerrors.Wrap(err, "failed to get access") } client, err := (&HuaweiCloudCDNDeployer{}).createSdkClient( @@ -36,7 +37,7 @@ func NewHuaweiCloudCDNDeployer(option *DeployerOption) (Deployer, error) { option.DeployConfig.GetConfigAsString("region"), ) if err != nil { - return nil, err + return nil, xerrors.Wrap(err, "failed to create sdk client") } // TODO: SCM 服务与 DNS 服务所支持的区域可能不一致,这里暂时不传而是使用默认值,仅支持华为云国内版 @@ -46,7 +47,7 @@ func NewHuaweiCloudCDNDeployer(option *DeployerOption) (Deployer, error) { Region: "", }) if err != nil { - return nil, err + return nil, xerrors.Wrap(err, "failed to create ssl uploader") } return &HuaweiCloudCDNDeployer{ @@ -87,16 +88,16 @@ func (d *HuaweiCloudCDNDeployer) Deploy(ctx context.Context) error { var updateDomainMultiCertificatesResp *hcCdnModel.UpdateDomainMultiCertificatesResponse if d.option.DeployConfig.GetConfigAsBool("useSCM") { // 上传证书到 SCM - uploadResult, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey) + 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("已上传证书", uploadResult)) + d.infos = append(d.infos, toStr("已上传证书", upres)) updateDomainMultiCertificatesReqBodyContent.CertificateType = cast.Int32Ptr(2) - updateDomainMultiCertificatesReqBodyContent.SCMCertificateId = cast.StringPtr(uploadResult.CertId) - updateDomainMultiCertificatesReqBodyContent.CertName = cast.StringPtr(uploadResult.CertName) + 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())) diff --git a/internal/deployer/huaweicloud_elb.go b/internal/deployer/huaweicloud_elb.go index f9f26338..9bf9f40e 100644 --- a/internal/deployer/huaweicloud_elb.go +++ b/internal/deployer/huaweicloud_elb.go @@ -16,6 +16,7 @@ import ( 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/domain" "github.com/usual2970/certimate/internal/pkg/core/uploader" @@ -33,7 +34,7 @@ type HuaweiCloudELBDeployer struct { func NewHuaweiCloudELBDeployer(option *DeployerOption) (Deployer, error) { access := &domain.HuaweiCloudAccess{} if err := json.Unmarshal([]byte(option.Access), access); err != nil { - return nil, err + return nil, xerrors.Wrap(err, "failed to get access") } client, err := (&HuaweiCloudELBDeployer{}).createSdkClient( @@ -42,7 +43,7 @@ func NewHuaweiCloudELBDeployer(option *DeployerOption) (Deployer, error) { option.DeployConfig.GetConfigAsString("region"), ) if err != nil { - return nil, err + return nil, xerrors.Wrap(err, "failed to create sdk client") } uploader, err := uploader.NewHuaweiCloudELBUploader(&uploader.HuaweiCloudELBUploaderConfig{ @@ -51,7 +52,7 @@ func NewHuaweiCloudELBDeployer(option *DeployerOption) (Deployer, error) { Region: option.DeployConfig.GetConfigAsString("region"), }) if err != nil { - return nil, err + return nil, xerrors.Wrap(err, "failed to create ssl uploader") } return &HuaweiCloudELBDeployer{ @@ -73,14 +74,17 @@ func (d *HuaweiCloudELBDeployer) GetInfo() []string { func (d *HuaweiCloudELBDeployer) Deploy(ctx context.Context) error { switch d.option.DeployConfig.GetConfigAsString("resourceType") { case "certificate": + // 部署到指定证书 if err := d.deployToCertificate(ctx); 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 } @@ -254,17 +258,17 @@ func (d *HuaweiCloudELBDeployer) deployToLoadbalancer(ctx context.Context) error d.infos = append(d.infos, toStr("已查询到 ELB 负载均衡器下的监听器", hcListenerIds)) // 上传证书到 SCM - uploadResult, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey) + 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("已上传证书", uploadResult)) + d.infos = append(d.infos, toStr("已上传证书", upres)) // 批量更新监听器证书 var errs []error for _, hcListenerId := range hcListenerIds { - if err := d.updateListenerCertificate(ctx, hcListenerId, uploadResult.CertId); err != nil { + if err := d.updateListenerCertificate(ctx, hcListenerId, upres.CertId); err != nil { errs = append(errs, err) } } @@ -282,15 +286,15 @@ func (d *HuaweiCloudELBDeployer) deployToListener(ctx context.Context) error { } // 上传证书到 SCM - uploadResult, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey) + 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("已上传证书", uploadResult)) + d.infos = append(d.infos, toStr("已上传证书", upres)) // 更新监听器证书 - if err := d.updateListenerCertificate(ctx, hcListenerId, uploadResult.CertId); err != nil { + if err := d.updateListenerCertificate(ctx, hcListenerId, upres.CertId); err != nil { return err } diff --git a/internal/deployer/k8s_secret.go b/internal/deployer/k8s_secret.go index 85471ef3..0b5945b9 100644 --- a/internal/deployer/k8s_secret.go +++ b/internal/deployer/k8s_secret.go @@ -3,9 +3,11 @@ package deployer import ( "context" "encoding/json" + "errors" "fmt" "strings" + xerrors "github.com/pkg/errors" k8sCore "k8s.io/api/core/v1" k8sMeta "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" @@ -19,12 +21,25 @@ import ( type K8sSecretDeployer struct { option *DeployerOption infos []string + + k8sClient *kubernetes.Clientset } func NewK8sSecretDeployer(option *DeployerOption) (Deployer, error) { + access := &domain.KubernetesAccess{} + if err := json.Unmarshal([]byte(option.Access), access); err != nil { + return nil, xerrors.Wrap(err, "failed to get access") + } + + client, err := (&K8sSecretDeployer{}).createK8sClient(access) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create k8s client") + } + return &K8sSecretDeployer{ - option: option, - infos: make([]string, 0), + option: option, + infos: make([]string, 0), + k8sClient: client, }, nil } @@ -37,41 +52,20 @@ func (d *K8sSecretDeployer) GetInfo() []string { } func (d *K8sSecretDeployer) Deploy(ctx context.Context) error { - access := &domain.KubernetesAccess{} - if err := json.Unmarshal([]byte(d.option.Access), access); err != nil { - return err - } - - client, err := d.createClient(access) - if err != nil { - return err - } - - d.infos = append(d.infos, toStr("kubeClient create success.", nil)) - namespace := d.option.DeployConfig.GetConfigAsString("namespace") + secretName := d.option.DeployConfig.GetConfigAsString("secretName") + secretDataKeyForCrt := d.option.DeployConfig.GetConfigOrDefaultAsString("secretDataKeyForCrt", "tls.crt") + secretDataKeyForKey := d.option.DeployConfig.GetConfigOrDefaultAsString("secretDataKeyForKey", "tls.key") if namespace == "" { namespace = "default" } - - secretName := d.option.DeployConfig.GetConfigAsString("secretName") if secretName == "" { - return fmt.Errorf("k8s secret name is empty") - } - - secretDataKeyForCrt := d.option.DeployConfig.GetConfigAsString("secretDataKeyForCrt") - if secretDataKeyForCrt == "" { - namespace = "tls.crt" - } - - secretDataKeyForKey := d.option.DeployConfig.GetConfigAsString("secretDataKeyForKey") - if secretDataKeyForKey == "" { - namespace = "tls.key" + return errors.New("`secretName` is required") } certX509, err := x509.ParseCertificateFromPEM(d.option.Certificate.Certificate) if err != nil { - return fmt.Errorf("failed to parse certificate: %w", err) + return err } secretPayload := k8sCore.Secret{ @@ -90,17 +84,16 @@ func (d *K8sSecretDeployer) Deploy(ctx context.Context) error { }, Type: k8sCore.SecretType("kubernetes.io/tls"), } - secretPayload.Data = make(map[string][]byte) secretPayload.Data[secretDataKeyForCrt] = []byte(d.option.Certificate.Certificate) secretPayload.Data[secretDataKeyForKey] = []byte(d.option.Certificate.PrivateKey) // 获取 Secret 实例 - _, err = client.CoreV1().Secrets(namespace).Get(context.TODO(), secretName, k8sMeta.GetOptions{}) + _, err = d.k8sClient.CoreV1().Secrets(namespace).Get(context.TODO(), secretName, k8sMeta.GetOptions{}) if err != nil { - _, err = client.CoreV1().Secrets(namespace).Create(context.TODO(), &secretPayload, k8sMeta.CreateOptions{}) + _, err = d.k8sClient.CoreV1().Secrets(namespace).Create(context.TODO(), &secretPayload, k8sMeta.CreateOptions{}) if err != nil { - return fmt.Errorf("failed to create k8s secret: %w", err) + return xerrors.Wrap(err, "failed to create k8s secret") } else { d.infos = append(d.infos, toStr("Certificate has been created in K8s Secret", nil)) return nil @@ -108,9 +101,9 @@ func (d *K8sSecretDeployer) Deploy(ctx context.Context) error { } // 更新 Secret 实例 - _, err = client.CoreV1().Secrets(namespace).Update(context.TODO(), &secretPayload, k8sMetaV1.UpdateOptions{}) + _, err = d.k8sClient.CoreV1().Secrets(namespace).Update(context.TODO(), &secretPayload, k8sMeta.UpdateOptions{}) if err != nil { - return fmt.Errorf("failed to update k8s secret: %w", err) + return xerrors.Wrap(err, "failed to update k8s secret") } d.infos = append(d.infos, toStr("Certificate has been updated to K8s Secret", nil)) @@ -118,7 +111,7 @@ func (d *K8sSecretDeployer) Deploy(ctx context.Context) error { return nil } -func (d *K8sSecretDeployer) createClient(access *domain.KubernetesAccess) (*kubernetes.Clientset, error) { +func (d *K8sSecretDeployer) createK8sClient(access *domain.KubernetesAccess) (*kubernetes.Clientset, error) { var config *rest.Config var err error if access.KubeConfig == "" { @@ -129,7 +122,6 @@ func (d *K8sSecretDeployer) createClient(access *domain.KubernetesAccess) (*kube return nil, err } config, err = kubeConfig.ClientConfig() - } if err != nil { return nil, err @@ -139,5 +131,6 @@ func (d *K8sSecretDeployer) createClient(access *domain.KubernetesAccess) (*kube if err != nil { return nil, err } + return client, nil } diff --git a/internal/deployer/local.go b/internal/deployer/local.go index 0c839fa4..1f1ef488 100644 --- a/internal/deployer/local.go +++ b/internal/deployer/local.go @@ -3,12 +3,13 @@ package deployer import ( "bytes" "context" - "encoding/json" + "errors" "fmt" "os/exec" "runtime" - "github.com/usual2970/certimate/internal/domain" + xerrors "github.com/pkg/errors" + "github.com/usual2970/certimate/internal/pkg/utils/fs" ) @@ -45,17 +46,12 @@ func (d *LocalDeployer) GetInfo() []string { } func (d *LocalDeployer) Deploy(ctx context.Context) error { - access := &domain.LocalAccess{} - if err := json.Unmarshal([]byte(d.option.Access), access); err != nil { - return err - } - // 执行前置命令 preCommand := d.option.DeployConfig.GetConfigAsString("preCommand") if preCommand != "" { stdout, stderr, err := d.execCommand(preCommand) if err != nil { - return fmt.Errorf("failed to run pre-command: %w, stdout: %s, stderr: %s", err, stdout, stderr) + return xerrors.Wrapf(err, "failed to run pre-command, stdout: %s, stderr: %s", stdout, stderr) } d.infos = append(d.infos, toStr("执行前置命令成功", stdout)) @@ -65,13 +61,13 @@ func (d *LocalDeployer) Deploy(ctx context.Context) error { switch d.option.DeployConfig.GetConfigOrDefaultAsString("format", certFormatPEM) { case certFormatPEM: if err := fs.WriteFileString(d.option.DeployConfig.GetConfigAsString("certPath"), d.option.Certificate.Certificate); err != nil { - return fmt.Errorf("failed to save certificate file: %w", err) + return err } d.infos = append(d.infos, toStr("保存证书成功", nil)) if err := fs.WriteFileString(d.option.DeployConfig.GetConfigAsString("keyPath"), d.option.Certificate.PrivateKey); err != nil { - return fmt.Errorf("failed to save private key file: %w", err) + return err } d.infos = append(d.infos, toStr("保存私钥成功", nil)) @@ -83,11 +79,11 @@ func (d *LocalDeployer) Deploy(ctx context.Context) error { d.option.DeployConfig.GetConfigAsString("pfxPassword"), ) if err != nil { - return fmt.Errorf("failed to convert pem to pfx %w", err) + return err } if err := fs.WriteFile(d.option.DeployConfig.GetConfigAsString("certPath"), pfxData); err != nil { - return fmt.Errorf("failed to save certificate file: %w", err) + return err } d.infos = append(d.infos, toStr("保存证书成功", nil)) @@ -101,11 +97,11 @@ func (d *LocalDeployer) Deploy(ctx context.Context) error { d.option.DeployConfig.GetConfigAsString("jksStorepass"), ) if err != nil { - return fmt.Errorf("failed to convert pem to pfx %w", err) + return err } if err := fs.WriteFile(d.option.DeployConfig.GetConfigAsString("certPath"), jksData); err != nil { - return fmt.Errorf("failed to save certificate file: %w", err) + return err } d.infos = append(d.infos, toStr("保存证书成功", nil)) @@ -116,7 +112,7 @@ func (d *LocalDeployer) Deploy(ctx context.Context) error { if command != "" { stdout, stderr, err := d.execCommand(command) if err != nil { - return fmt.Errorf("failed to run command: %w, stdout: %s, stderr: %s", err, stdout, stderr) + return xerrors.Wrapf(err, "failed to run command, stdout: %s, stderr: %s", stdout, stderr) } d.infos = append(d.infos, toStr("执行命令成功", stdout)) @@ -146,7 +142,7 @@ func (d *LocalDeployer) execCommand(command string) (string, string, error) { } default: - return "", "", fmt.Errorf("unsupported shell") + return "", "", errors.New("unsupported shell") } var stdoutBuf bytes.Buffer @@ -156,7 +152,7 @@ func (d *LocalDeployer) execCommand(command string) (string, string, error) { err := cmd.Run() if err != nil { - return "", "", fmt.Errorf("failed to execute script: %w", err) + return "", "", xerrors.Wrap(err, "failed to execute shell script") } return stdoutBuf.String(), stderrBuf.String(), err diff --git a/internal/deployer/qiniu_cdn.go b/internal/deployer/qiniu_cdn.go index c17c5241..797e3427 100644 --- a/internal/deployer/qiniu_cdn.go +++ b/internal/deployer/qiniu_cdn.go @@ -24,7 +24,9 @@ type QiniuCDNDeployer struct { func NewQiniuCDNDeployer(option *DeployerOption) (*QiniuCDNDeployer, error) { access := &domain.QiniuAccess{} - json.Unmarshal([]byte(option.Access), access) + if err := json.Unmarshal([]byte(option.Access), access); err != nil { + return nil, fmt.Errorf("failed to get access: %w", err) + } return &QiniuCDNDeployer{ option: option, diff --git a/internal/pkg/core/uploader/uploader_aliyun_cas.go b/internal/pkg/core/uploader/uploader_aliyun_cas.go index 6a90331d..a6e23c40 100644 --- a/internal/pkg/core/uploader/uploader_aliyun_cas.go +++ b/internal/pkg/core/uploader/uploader_aliyun_cas.go @@ -9,6 +9,7 @@ import ( aliyunCas "github.com/alibabacloud-go/cas-20200407/v3/client" aliyunOpen "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/utils/x509" ) @@ -31,7 +32,7 @@ func NewAliyunCASUploader(config *AliyunCASUploaderConfig) (Uploader, error) { config.Region, ) if err != nil { - return nil, fmt.Errorf("failed to create sdk client: %w", err) + return nil, xerrors.Wrap(err, "failed to create sdk client") } return &AliyunCASUploader{ @@ -60,7 +61,7 @@ func (u *AliyunCASUploader) Upload(ctx context.Context, certPem string, privkeyP } listUserCertificateOrderResp, err := u.sdkClient.ListUserCertificateOrder(listUserCertificateOrderReq) if err != nil { - return nil, fmt.Errorf("failed to execute sdk request 'cas.ListUserCertificateOrder': %w", err) + return nil, xerrors.Wrap(err, "failed to execute sdk request 'cas.ListUserCertificateOrder'") } if listUserCertificateOrderResp.Body.CertificateOrderList != nil { @@ -71,7 +72,7 @@ func (u *AliyunCASUploader) Upload(ctx context.Context, certPem string, privkeyP } getUserCertificateDetailResp, err := u.sdkClient.GetUserCertificateDetail(getUserCertificateDetailReq) if err != nil { - return nil, fmt.Errorf("failed to execute sdk request 'cas.GetUserCertificateDetail': %w", err) + return nil, xerrors.Wrap(err, "failed to execute sdk request 'cas.GetUserCertificateDetail'") } var isSameCert bool @@ -120,7 +121,7 @@ func (u *AliyunCASUploader) Upload(ctx context.Context, certPem string, privkeyP } uploadUserCertificateResp, err := u.sdkClient.UploadUserCertificate(uploadUserCertificateReq) if err != nil { - return nil, fmt.Errorf("failed to execute sdk request 'cas.UploadUserCertificate': %w", err) + return nil, xerrors.Wrap(err, "failed to execute sdk request 'cas.UploadUserCertificate'") } certId = fmt.Sprintf("%d", tea.Int64Value(uploadUserCertificateResp.Body.CertId)) diff --git a/internal/pkg/core/uploader/uploader_aliyun_slb.go b/internal/pkg/core/uploader/uploader_aliyun_slb.go index 2028a04b..6f25d128 100644 --- a/internal/pkg/core/uploader/uploader_aliyun_slb.go +++ b/internal/pkg/core/uploader/uploader_aliyun_slb.go @@ -11,6 +11,7 @@ import ( aliyunOpen "github.com/alibabacloud-go/darabonba-openapi/v2/client" aliyunSlb "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/utils/x509" ) @@ -33,7 +34,7 @@ func NewAliyunSLBUploader(config *AliyunSLBUploaderConfig) (Uploader, error) { config.Region, ) if err != nil { - return nil, fmt.Errorf("failed to create sdk client: %w", err) + return nil, xerrors.Wrap(err, "failed to create sdk client") } return &AliyunSLBUploader{ @@ -56,7 +57,7 @@ func (u *AliyunSLBUploader) Upload(ctx context.Context, certPem string, privkeyP } describeServerCertificatesResp, err := u.sdkClient.DescribeServerCertificates(describeServerCertificatesReq) if err != nil { - return nil, fmt.Errorf("failed to execute sdk request 'slb.DescribeServerCertificates': %w", err) + return nil, xerrors.Wrap(err, "failed to execute sdk request 'slb.DescribeServerCertificates'") } if describeServerCertificatesResp.Body.ServerCertificates != nil && describeServerCertificatesResp.Body.ServerCertificates.ServerCertificate != nil { @@ -90,7 +91,7 @@ func (u *AliyunSLBUploader) Upload(ctx context.Context, certPem string, privkeyP } uploadServerCertificateResp, err := u.sdkClient.UploadServerCertificate(uploadServerCertificateReq) if err != nil { - return nil, fmt.Errorf("failed to execute sdk request 'slb.UploadServerCertificate': %w", err) + return nil, xerrors.Wrap(err, "failed to execute sdk request 'slb.UploadServerCertificate'") } certId = *uploadServerCertificateResp.Body.ServerCertificateId diff --git a/internal/pkg/core/uploader/uploader_huaweicloud_elb.go b/internal/pkg/core/uploader/uploader_huaweicloud_elb.go index 090362af..840db8cf 100644 --- a/internal/pkg/core/uploader/uploader_huaweicloud_elb.go +++ b/internal/pkg/core/uploader/uploader_huaweicloud_elb.go @@ -2,6 +2,7 @@ import ( "context" + "errors" "fmt" "time" @@ -13,6 +14,7 @@ import ( 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/utils/cast" "github.com/usual2970/certimate/internal/pkg/utils/x509" @@ -36,7 +38,7 @@ func NewHuaweiCloudELBUploader(config *HuaweiCloudELBUploaderConfig) (Uploader, config.Region, ) if err != nil { - return nil, fmt.Errorf("failed to create sdk client: %w", err) + return nil, xerrors.Wrap(err, "failed to create sdk client: %w") } return &HuaweiCloudELBUploader{ @@ -65,7 +67,7 @@ func (u *HuaweiCloudELBUploader) Upload(ctx context.Context, certPem string, pri } listCertificatesResp, err := u.sdkClient.ListCertificates(listCertificatesReq) if err != nil { - return nil, fmt.Errorf("failed to execute sdk request 'elb.ListCertificates': %w", err) + return nil, xerrors.Wrap(err, "failed to execute sdk request 'elb.ListCertificates'") } if listCertificatesResp.Certificates != nil { @@ -107,7 +109,7 @@ func (u *HuaweiCloudELBUploader) Upload(ctx context.Context, certPem string, pri // REF: https://support.huaweicloud.com/api-iam/iam_06_0001.html projectId, err := u.getSdkProjectId(u.config.Region, u.config.AccessKeyId, u.config.SecretAccessKey) if err != nil { - return nil, fmt.Errorf("failed to get SDK project id: %w", err) + return nil, xerrors.Wrap(err, "failed to get SDK project id") } // 生成新证书名(需符合华为云命名规则) @@ -128,7 +130,7 @@ func (u *HuaweiCloudELBUploader) Upload(ctx context.Context, certPem string, pri } createCertificateResp, err := u.sdkClient.CreateCertificate(createCertificateReq) if err != nil { - return nil, fmt.Errorf("failed to execute sdk request 'elb.CreateCertificate': %w", err) + return nil, xerrors.Wrap(err, "failed to execute sdk request 'elb.CreateCertificate'") } certId = createCertificateResp.Certificate.Id @@ -207,7 +209,7 @@ func (u *HuaweiCloudELBUploader) getSdkProjectId(accessKeyId, secretAccessKey, r if err != nil { return "", err } else if response.Projects == nil || len(*response.Projects) == 0 { - return "", fmt.Errorf("no project found") + return "", errors.New("no project found") } return (*response.Projects)[0].Id, nil diff --git a/internal/pkg/core/uploader/uploader_huaweicloud_scm.go b/internal/pkg/core/uploader/uploader_huaweicloud_scm.go index 2b09ca19..5cc0d153 100644 --- a/internal/pkg/core/uploader/uploader_huaweicloud_scm.go +++ b/internal/pkg/core/uploader/uploader_huaweicloud_scm.go @@ -9,6 +9,7 @@ import ( 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/utils/cast" "github.com/usual2970/certimate/internal/pkg/utils/x509" @@ -32,7 +33,7 @@ func NewHuaweiCloudSCMUploader(config *HuaweiCloudSCMUploaderConfig) (Uploader, config.Region, ) if err != nil { - return nil, fmt.Errorf("failed to create sdk client: %w", err) + return nil, xerrors.Wrap(err, "failed to create sdk client") } return &HuaweiCloudSCMUploader{ @@ -63,7 +64,7 @@ func (u *HuaweiCloudSCMUploader) Upload(ctx context.Context, certPem string, pri } listCertificatesResp, err := u.sdkClient.ListCertificates(listCertificatesReq) if err != nil { - return nil, fmt.Errorf("failed to execute sdk request 'scm.ListCertificates': %w", err) + return nil, xerrors.Wrap(err, "failed to execute sdk request 'scm.ListCertificates'") } if listCertificatesResp.Certificates != nil { @@ -76,7 +77,7 @@ func (u *HuaweiCloudSCMUploader) Upload(ctx context.Context, certPem string, pri if exportCertificateResp != nil && exportCertificateResp.HttpStatusCode == 404 { continue } - return nil, fmt.Errorf("failed to execute sdk request 'scm.ExportCertificate': %w", err) + return nil, xerrors.Wrap(err, "failed to execute sdk request 'scm.ExportCertificate'") } var isSameCert bool @@ -127,7 +128,7 @@ func (u *HuaweiCloudSCMUploader) Upload(ctx context.Context, certPem string, pri } importCertificateResp, err := u.sdkClient.ImportCertificate(importCertificateReq) if err != nil { - return nil, fmt.Errorf("failed to execute sdk request 'scm.ImportCertificate': %w", err) + return nil, xerrors.Wrap(err, "failed to execute sdk request 'scm.ImportCertificate'") } certId = *importCertificateResp.CertificateId diff --git a/internal/pkg/core/uploader/uploader_tencentcloud_ssl.go b/internal/pkg/core/uploader/uploader_tencentcloud_ssl.go index 2a34e5e6..28837371 100644 --- a/internal/pkg/core/uploader/uploader_tencentcloud_ssl.go +++ b/internal/pkg/core/uploader/uploader_tencentcloud_ssl.go @@ -5,15 +5,13 @@ import ( "fmt" "time" + 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" - - "github.com/usual2970/certimate/internal/pkg/utils/cast" ) type TencentCloudSSLUploaderConfig struct { - Region string `json:"region"` SecretId string `json:"secretId"` SecretKey string `json:"secretKey"` } @@ -25,12 +23,11 @@ type TencentCloudSSLUploader struct { func NewTencentCloudSSLUploader(config *TencentCloudSSLUploaderConfig) (Uploader, error) { client, err := (&TencentCloudSSLUploader{}).createSdkClient( - config.Region, config.SecretId, config.SecretKey, ) if err != nil { - return nil, fmt.Errorf("failed to create sdk client: %w", err) + return nil, xerrors.Wrap(err, "failed to create sdk client") } return &TencentCloudSSLUploader{ @@ -40,33 +37,38 @@ func NewTencentCloudSSLUploader(config *TencentCloudSSLUploaderConfig) (Uploader } func (u *TencentCloudSSLUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *UploadResult, err error) { + defer func() { + if r := recover(); r != nil { + fmt.Printf("Recovered from panic: %+v", r) + fmt.Println() + } + }() + // 生成新证书名(需符合腾讯云命名规则) var certId, certName string certName = fmt.Sprintf("certimate-%d", time.Now().UnixMilli()) // 上传新证书 // REF: https://cloud.tencent.com/document/product/400/41665 - uploadCertificateReq := &tcSsl.UploadCertificateRequest{ - Alias: cast.StringPtr(certName), - CertificatePublicKey: cast.StringPtr(certPem), - CertificatePrivateKey: cast.StringPtr(privkeyPem), - Repeatable: cast.BoolPtr(false), - } + uploadCertificateReq := tcSsl.NewUploadCertificateRequest() + uploadCertificateReq.Alias = common.StringPtr(certName) + uploadCertificateReq.CertificatePublicKey = common.StringPtr(certPem) + uploadCertificateReq.CertificatePrivateKey = common.StringPtr(privkeyPem) + uploadCertificateReq.Repeatable = common.BoolPtr(false) uploadCertificateResp, err := u.sdkClient.UploadCertificate(uploadCertificateReq) if err != nil { - return nil, fmt.Errorf("failed to execute sdk request 'ssl.UploadCertificate': %w", err) + return nil, xerrors.Wrap(err, "failed to execute sdk request 'ssl.UploadCertificate'") } // 获取证书详情 // REF: https://cloud.tencent.com/document/api/400/41673 // // P.S. 上传重复证书会返回上一次的证书 ID,这里需要重新获取一遍证书名(https://github.com/usual2970/certimate/pull/227) - describeCertificateDetailReq := &tcSsl.DescribeCertificateDetailRequest{ - CertificateId: uploadCertificateResp.Response.CertificateId, - } + describeCertificateDetailReq := tcSsl.NewDescribeCertificateDetailRequest() + describeCertificateDetailReq.CertificateId = uploadCertificateResp.Response.CertificateId describeCertificateDetailResp, err := u.sdkClient.DescribeCertificateDetail(describeCertificateDetailReq) if err != nil { - return nil, fmt.Errorf("failed to execute sdk request 'ssl.DescribeCertificateDetail': %w", err) + return nil, xerrors.Wrap(err, "failed to execute sdk request 'ssl.DescribeCertificateDetail'") } certId = *describeCertificateDetailResp.Response.CertificateId @@ -77,13 +79,9 @@ func (u *TencentCloudSSLUploader) Upload(ctx context.Context, certPem string, pr }, nil } -func (u *TencentCloudSSLUploader) createSdkClient(region, secretId, secretKey string) (*tcSsl.Client, error) { - if region == "" { - region = "ap-guangzhou" // SSL 服务默认区域:广州 - } - +func (u *TencentCloudSSLUploader) createSdkClient(secretId, secretKey string) (*tcSsl.Client, error) { credential := common.NewCredential(secretId, secretKey) - client, err := tcSsl.NewClient(credential, region, profile.NewClientProfile()) + client, err := tcSsl.NewClient(credential, "", profile.NewClientProfile()) if err != nil { return nil, err } diff --git a/internal/pkg/utils/fs/fs.go b/internal/pkg/utils/fs/fs.go index 3ae82060..47b0cafb 100644 --- a/internal/pkg/utils/fs/fs.go +++ b/internal/pkg/utils/fs/fs.go @@ -1,9 +1,10 @@ package fs import ( - "fmt" "os" "path/filepath" + + xerrors "github.com/pkg/errors" ) // 与 [WriteFile] 类似,但写入的是字符串内容。 @@ -33,18 +34,18 @@ func WriteFile(path string, data []byte) error { err := os.MkdirAll(dir, os.ModePerm) if err != nil { - return fmt.Errorf("failed to create directory: %w", err) + return xerrors.Wrap(err, "failed to create directory") } file, err := os.Create(path) if err != nil { - return fmt.Errorf("failed to create file: %w", err) + return xerrors.Wrap(err, "failed to create file") } defer file.Close() _, err = file.Write(data) if err != nil { - return fmt.Errorf("failed to write file: %w", err) + return xerrors.Wrap(err, "failed to write file") } return nil diff --git a/internal/pkg/utils/x509/x509.go b/internal/pkg/utils/x509/x509.go index 40cc39d6..2a70a083 100644 --- a/internal/pkg/utils/x509/x509.go +++ b/internal/pkg/utils/x509/x509.go @@ -5,7 +5,9 @@ import ( "crypto/rsa" "crypto/x509" "encoding/pem" - "fmt" + "errors" + + xerrors "github.com/pkg/errors" ) // 比较两个 x509.Certificate 对象,判断它们是否是同一张证书。 @@ -38,12 +40,12 @@ func ParseCertificateFromPEM(certPem string) (cert *x509.Certificate, err error) block, _ := pem.Decode(pemData) if block == nil { - return nil, fmt.Errorf("failed to decode PEM block") + return nil, errors.New("failed to decode PEM block") } cert, err = x509.ParseCertificate(block.Bytes) if err != nil { - return nil, fmt.Errorf("failed to parse certificate: %w", err) + return nil, xerrors.Wrap(err, "failed to parse certificate") } return cert, nil @@ -62,12 +64,12 @@ func ParseECPrivateKeyFromPEM(privkeyPem string) (privkey *ecdsa.PrivateKey, err block, _ := pem.Decode(pemData) if block == nil { - return nil, fmt.Errorf("failed to decode PEM block") + return nil, errors.New("failed to decode PEM block") } privkey, err = x509.ParseECPrivateKey(block.Bytes) if err != nil { - return nil, fmt.Errorf("failed to parse private key: %w", err) + return nil, xerrors.Wrap(err, "failed to parse private key") } return privkey, nil @@ -86,12 +88,12 @@ func ParsePKCS1PrivateKeyFromPEM(privkeyPem string) (privkey *rsa.PrivateKey, er block, _ := pem.Decode(pemData) if block == nil { - return nil, fmt.Errorf("failed to decode PEM block") + return nil, errors.New("failed to decode PEM block") } privkey, err = x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { - return nil, fmt.Errorf("failed to parse private key: %w", err) + return nil, xerrors.Wrap(err, "failed to parse private key") } return privkey, nil @@ -108,7 +110,7 @@ func ParsePKCS1PrivateKeyFromPEM(privkeyPem string) (privkey *rsa.PrivateKey, er func ConvertECPrivateKeyToPEM(privkey *ecdsa.PrivateKey) (privkeyPem string, err error) { data, err := x509.MarshalECPrivateKey(privkey) if err != nil { - return "", fmt.Errorf("failed to marshal EC private key: %w", err) + return "", xerrors.Wrap(err, "failed to marshal EC private key") } block := &pem.Block{ From 59af2464791971749ad8c22f7d6fb10eedc03781 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Wed, 30 Oct 2024 19:37:44 +0800 Subject: [PATCH 03/18] refactor: clean code --- internal/deployer/local.go | 2 +- internal/deployer/ssh.go | 33 ++-- internal/deployer/tencent_cdn.go | 241 +++++++++++++++--------------- internal/deployer/tencent_clb.go | 141 +++++++++-------- internal/deployer/tencent_cos.go | 115 +++++++------- internal/deployer/tencent_ecdn.go | 177 +++++++++++----------- internal/deployer/tencent_teo.go | 123 ++++++++------- internal/deployer/webhook.go | 10 +- 8 files changed, 439 insertions(+), 403 deletions(-) diff --git a/internal/deployer/local.go b/internal/deployer/local.go index 1f1ef488..ccda2306 100644 --- a/internal/deployer/local.go +++ b/internal/deployer/local.go @@ -155,5 +155,5 @@ func (d *LocalDeployer) execCommand(command string) (string, string, error) { return "", "", xerrors.Wrap(err, "failed to execute shell script") } - return stdoutBuf.String(), stderrBuf.String(), err + return stdoutBuf.String(), stderrBuf.String(), nil } diff --git a/internal/deployer/ssh.go b/internal/deployer/ssh.go index 98c4de48..a94c9782 100644 --- a/internal/deployer/ssh.go +++ b/internal/deployer/ssh.go @@ -8,6 +8,7 @@ import ( "os" "path/filepath" + xerrors "github.com/pkg/errors" "github.com/pkg/sftp" "golang.org/x/crypto/ssh" @@ -55,7 +56,7 @@ func (d *SSHDeployer) Deploy(ctx context.Context) error { if preCommand != "" { stdout, stderr, err := d.sshExecCommand(client, preCommand) if err != nil { - return fmt.Errorf("failed to run pre-command: %w, stdout: %s, stderr: %s", err, stdout, stderr) + return xerrors.Wrapf(err, "failed to run pre-command: stdout: %s, stderr: %s", stdout, stderr) } d.infos = append(d.infos, toStr("SSH 执行前置命令成功", stdout)) @@ -65,13 +66,13 @@ func (d *SSHDeployer) Deploy(ctx context.Context) error { switch d.option.DeployConfig.GetConfigOrDefaultAsString("format", certFormatPEM) { case certFormatPEM: if err := d.writeSftpFileString(client, d.option.DeployConfig.GetConfigAsString("certPath"), d.option.Certificate.Certificate); err != nil { - return fmt.Errorf("failed to upload certificate file: %w", err) + return err } d.infos = append(d.infos, toStr("SSH 上传证书成功", nil)) if err := d.writeSftpFileString(client, d.option.DeployConfig.GetConfigAsString("keyPath"), d.option.Certificate.PrivateKey); err != nil { - return fmt.Errorf("failed to upload private key file: %w", err) + return err } d.infos = append(d.infos, toStr("SSH 上传私钥成功", nil)) @@ -83,11 +84,11 @@ func (d *SSHDeployer) Deploy(ctx context.Context) error { d.option.DeployConfig.GetConfigAsString("pfxPassword"), ) if err != nil { - return fmt.Errorf("failed to convert pem to pfx %w", err) + return err } if err := d.writeSftpFile(client, d.option.DeployConfig.GetConfigAsString("certPath"), pfxData); err != nil { - return fmt.Errorf("failed to upload certificate file: %w", err) + return err } d.infos = append(d.infos, toStr("SSH 上传证书成功", nil)) @@ -101,11 +102,11 @@ func (d *SSHDeployer) Deploy(ctx context.Context) error { d.option.DeployConfig.GetConfigAsString("jksStorepass"), ) if err != nil { - return fmt.Errorf("failed to convert pem to pfx %w", err) + return err } if err := fs.WriteFile(d.option.DeployConfig.GetConfigAsString("certPath"), jksData); err != nil { - return fmt.Errorf("failed to save certificate file: %w", err) + return err } d.infos = append(d.infos, toStr("保存证书成功", nil)) @@ -116,7 +117,7 @@ func (d *SSHDeployer) Deploy(ctx context.Context) error { if command != "" { stdout, stderr, err := d.sshExecCommand(client, command) if err != nil { - return fmt.Errorf("failed to run command: %w, stdout: %s, stderr: %s", err, stdout, stderr) + return xerrors.Wrapf(err, "failed to run command, stdout: %s, stderr: %s", stdout, stderr) } d.infos = append(d.infos, toStr("SSH 执行命令成功", stdout)) @@ -158,7 +159,7 @@ func (d *SSHDeployer) createSshClient(access *domain.SSHAccess) (*ssh.Client, er func (d *SSHDeployer) sshExecCommand(client *ssh.Client, command string) (string, string, error) { session, err := client.NewSession() if err != nil { - return "", "", fmt.Errorf("failed to create ssh session: %w", err) + return "", "", xerrors.Wrap(err, "failed to create ssh session") } defer session.Close() @@ -167,7 +168,11 @@ func (d *SSHDeployer) sshExecCommand(client *ssh.Client, command string) (string var stderrBuf bytes.Buffer session.Stderr = &stderrBuf err = session.Run(command) - return stdoutBuf.String(), stderrBuf.String(), err + if err != nil { + return "", "", xerrors.Wrap(err, "failed to execute ssh script") + } + + return stdoutBuf.String(), stderrBuf.String(), nil } func (d *SSHDeployer) writeSftpFileString(client *ssh.Client, path string, content string) error { @@ -177,23 +182,23 @@ func (d *SSHDeployer) writeSftpFileString(client *ssh.Client, path string, conte func (d *SSHDeployer) writeSftpFile(client *ssh.Client, path string, data []byte) error { sftpCli, err := sftp.NewClient(client) if err != nil { - return fmt.Errorf("failed to create sftp client: %w", err) + return xerrors.Wrap(err, "failed to create sftp client") } defer sftpCli.Close() if err := sftpCli.MkdirAll(filepath.Dir(path)); err != nil { - return fmt.Errorf("failed to create remote directory: %w", err) + return xerrors.Wrap(err, "failed to create remote directory") } file, err := sftpCli.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC) if err != nil { - return fmt.Errorf("failed to open remote file: %w", err) + return xerrors.Wrap(err, "failed to open remote file") } defer file.Close() _, err = file.Write(data) if err != nil { - return fmt.Errorf("failed to write to remote file: %w", err) + return xerrors.Wrap(err, "failed to write to remote file") } return nil diff --git a/internal/deployer/tencent_cdn.go b/internal/deployer/tencent_cdn.go index 26c9c252..d89cb819 100644 --- a/internal/deployer/tencent_cdn.go +++ b/internal/deployer/tencent_cdn.go @@ -5,38 +5,58 @@ import ( "encoding/json" "fmt" "strings" - "golang.org/x/exp/slices" - cdn "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn/v20180606" + xerrors "github.com/pkg/errors" + tcCdn "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn/v20180606" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile" - ssl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205" + tcSsl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205" + "golang.org/x/exp/slices" "github.com/usual2970/certimate/internal/domain" - "github.com/usual2970/certimate/internal/utils/rand" + "github.com/usual2970/certimate/internal/pkg/core/uploader" ) type TencentCDNDeployer struct { - option *DeployerOption - credential *common.Credential - infos []string + option *DeployerOption + infos []string + + sdkClients *tencentCDNDeployerSdkClients + sslUploader uploader.Uploader +} + +type tencentCDNDeployerSdkClients struct { + ssl *tcSsl.Client + cdn *tcCdn.Client } func NewTencentCDNDeployer(option *DeployerOption) (Deployer, error) { access := &domain.TencentAccess{} if err := json.Unmarshal([]byte(option.Access), access); err != nil { - return nil, fmt.Errorf("failed to unmarshal tencent access: %w", err) + return nil, xerrors.Wrap(err, "failed to get access") } - credential := common.NewCredential( + clients, err := (&TencentCDNDeployer{}).createSdkClients( access.SecretId, access.SecretKey, ) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk clients") + } + + uploader, err := uploader.NewTencentCloudSSLUploader(&uploader.TencentCloudSSLUploaderConfig{ + SecretId: access.SecretId, + SecretKey: access.SecretKey, + }) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create ssl uploader") + } return &TencentCDNDeployer{ - option: option, - credential: credential, - infos: make([]string, 0), + option: option, + infos: make([]string, 0), + sdkClients: clients, + sslUploader: uploader, }, nil } @@ -49,141 +69,124 @@ func (d *TencentCDNDeployer) GetInfo() []string { } func (d *TencentCDNDeployer) Deploy(ctx context.Context) error { - // 上传证书 - certId, err := d.uploadCert() + // 上传证书到 SSL + upres, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey) if err != nil { - return fmt.Errorf("failed to upload certificate: %w", err) + return err } - d.infos = append(d.infos, toStr("上传证书", certId)) - if err := d.deploy(certId); err != nil { - return fmt.Errorf("failed to deploy: %w", err) + d.infos = append(d.infos, toStr("已上传证书", upres)) + + // 获取待部署的 CDN 实例 + // 如果是泛域名,根据证书匹配 CDN 实例 + aliInstanceIds := make([]string, 0) + domain := d.option.DeployConfig.GetConfigAsString("domain") + if strings.HasPrefix(domain, "*") { + domains, err := d.getDomainsByCertificateId(upres.CertId) + if err != nil { + return err + } + + aliInstanceIds = domains + } else { + aliInstanceIds = append(aliInstanceIds, domain) } + // 跳过已部署的 CDN 实例 + if len(aliInstanceIds) > 0 { + deployedDomains, err := d.getDeployedDomainsByCertificateId(upres.CertId) + if err != nil { + return err + } + + temp := make([]string, 0) + for _, aliInstanceId := range aliInstanceIds { + if !slices.Contains(deployedDomains, aliInstanceId) { + temp = append(temp, aliInstanceId) + } + } + aliInstanceIds = temp + } + if len(aliInstanceIds) == 0 { + d.infos = append(d.infos, "已部署过或没有要部署的 CDN 实例") + return nil + } + + // 证书部署到 CDN 实例 + // REF: https://cloud.tencent.com/document/product/400/91667 + deployCertificateInstanceReq := tcSsl.NewDeployCertificateInstanceRequest() + deployCertificateInstanceReq.CertificateId = common.StringPtr(upres.CertId) + deployCertificateInstanceReq.ResourceType = common.StringPtr("cdn") + deployCertificateInstanceReq.Status = common.Int64Ptr(1) + deployCertificateInstanceReq.InstanceIdList = common.StringPtrs(aliInstanceIds) + deployCertificateInstanceResp, err := d.sdkClients.ssl.DeployCertificateInstance(deployCertificateInstanceReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'ssl.DeployCertificateInstance'") + } + + d.infos = append(d.infos, toStr("已部署证书到云资源实例", deployCertificateInstanceResp.Response)) + return nil } -func (d *TencentCDNDeployer) uploadCert() (string, error) { - cpf := profile.NewClientProfile() - cpf.HttpProfile.Endpoint = "ssl.tencentcloudapi.com" +func (d *TencentCDNDeployer) createSdkClients(secretId, secretKey string) (*tencentCDNDeployerSdkClients, error) { + credential := common.NewCredential(secretId, secretKey) - client, _ := ssl.NewClient(d.credential, "", cpf) - - request := ssl.NewUploadCertificateRequest() - - request.CertificatePublicKey = common.StringPtr(d.option.Certificate.Certificate) - request.CertificatePrivateKey = common.StringPtr(d.option.Certificate.PrivateKey) - request.Alias = common.StringPtr(d.option.Domain + "_" + rand.RandStr(6)) - request.Repeatable = common.BoolPtr(false) - - response, err := client.UploadCertificate(request) + sslClient, err := tcSsl.NewClient(credential, "", profile.NewClientProfile()) if err != nil { - return "", fmt.Errorf("failed to upload certificate: %w", err) + return nil, err } - return *response.Response.CertificateId, nil + cdnClient, err := tcCdn.NewClient(credential, "", profile.NewClientProfile()) + if err != nil { + return nil, err + } + + return &tencentCDNDeployerSdkClients{ + ssl: sslClient, + cdn: cdnClient, + }, nil } -func (d *TencentCDNDeployer) deploy(certId string) error { - cpf := profile.NewClientProfile() - cpf.HttpProfile.Endpoint = "ssl.tencentcloudapi.com" - // 实例化要请求产品的client对象,clientProfile是可选的 - client, _ := ssl.NewClient(d.credential, "", cpf) - - // 实例化一个请求对象,每个接口都会对应一个request对象 - request := ssl.NewDeployCertificateInstanceRequest() - - request.CertificateId = common.StringPtr(certId) - request.ResourceType = common.StringPtr("cdn") - request.Status = common.Int64Ptr(1) - - // 如果是泛域名就从cdn列表下获取SSL证书中的可用域名 - domain := getDeployString(d.option.DeployConfig, "domain") - if strings.Contains(domain, "*") { - list, errGetList := d.getDomainList(certId) - if errGetList != nil { - return fmt.Errorf("failed to get certificate domain list: %w", errGetList) - } - if len(list) == 0 { - d.infos = append(d.infos, "没有需要部署的实例") - return nil - } - request.InstanceIdList = common.StringPtrs(list) - } else { // 否则直接使用传入的域名 - deployed, _ := d.isDomainDeployed(certId, domain) - if(deployed){ - d.infos = append(d.infos, "域名已部署") - return nil - }else{ - request.InstanceIdList = common.StringPtrs([]string{domain}) - } - } - - // 返回的resp是一个DeployCertificateInstanceResponse的实例,与请求对象对应 - resp, err := client.DeployCertificateInstance(request) +func (d *TencentCDNDeployer) getDomainsByCertificateId(tcCertId string) ([]string, error) { + // 获取证书中的可用域名 + // REF: https://cloud.tencent.com/document/product/228/42491 + describeCertDomainsReq := tcCdn.NewDescribeCertDomainsRequest() + describeCertDomainsReq.CertId = common.StringPtr(tcCertId) + describeCertDomainsReq.Product = common.StringPtr("cdn") + describeCertDomainsResp, err := d.sdkClients.cdn.DescribeCertDomains(describeCertDomainsReq) if err != nil { - return fmt.Errorf("failed to deploy certificate: %w", err) - } - d.infos = append(d.infos, toStr("部署证书", resp.Response)) - return nil -} - -func (d *TencentCDNDeployer) getDomainList(certId string) ([]string, error) { - cpf := profile.NewClientProfile() - cpf.HttpProfile.Endpoint = "cdn.tencentcloudapi.com" - client, _ := cdn.NewClient(d.credential, "", cpf) - - request := cdn.NewDescribeCertDomainsRequest() - - request.CertId = common.StringPtr(certId) - - response, err := client.DescribeCertDomains(request) - if err != nil { - return nil, fmt.Errorf("failed to get domain list: %w", err) - } - - deployedDomains, err := d.getDeployedDomainList(certId) - if err != nil { - return nil, fmt.Errorf("failed to get deployed domain list: %w", err) + return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.DescribeCertDomains'") } domains := make([]string, 0) - for _, domain := range response.Response.Domains { - domainStr := *domain - if(slices.Contains(deployedDomains, domainStr)){ - domains = append(domains, domainStr) + if describeCertDomainsResp.Response.Domains == nil { + for _, domain := range describeCertDomainsResp.Response.Domains { + domains = append(domains, *domain) } } return domains, nil } -func (d *TencentCDNDeployer) isDomainDeployed(certId, domain string) (bool, error) { - deployedDomains, err := d.getDeployedDomainList(certId) - if(err != nil){ - return false, err - } - - return slices.Contains(deployedDomains, domain), nil -} - -func (d *TencentCDNDeployer) getDeployedDomainList(certId string) ([]string, error) { - cpf := profile.NewClientProfile() - cpf.HttpProfile.Endpoint = "ssl.tencentcloudapi.com" - client, _ := ssl.NewClient(d.credential, "", cpf) - - request := ssl.NewDescribeDeployedResourcesRequest() - request.CertificateIds = common.StringPtrs([]string{certId}) - request.ResourceType = common.StringPtr("cdn") - - response, err := client.DescribeDeployedResources(request) +func (d *TencentCDNDeployer) getDeployedDomainsByCertificateId(tcCertId string) ([]string, error) { + // 根据证书查询关联 CDN 域名 + // REF: https://cloud.tencent.com/document/product/400/62674 + describeDeployedResourcesReq := tcSsl.NewDescribeDeployedResourcesRequest() + describeDeployedResourcesReq.CertificateIds = common.StringPtrs([]string{tcCertId}) + describeDeployedResourcesReq.ResourceType = common.StringPtr("cdn") + describeDeployedResourcesResp, err := d.sdkClients.ssl.DescribeDeployedResources(describeDeployedResourcesReq) if err != nil { - return nil, fmt.Errorf("failed to get deployed domain list: %w", err) + return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.DescribeDeployedResources'") } domains := make([]string, 0) - for _, domain := range response.Response.DeployedResources[0].Resources { - domains = append(domains, *domain) + if describeDeployedResourcesResp.Response.DeployedResources != nil { + for _, deployedResource := range describeDeployedResourcesResp.Response.DeployedResources { + for _, resource := range deployedResource.Resources { + domains = append(domains, *resource) + } + } } return domains, nil diff --git a/internal/deployer/tencent_clb.go b/internal/deployer/tencent_clb.go index ba97e840..45ccb993 100644 --- a/internal/deployer/tencent_clb.go +++ b/internal/deployer/tencent_clb.go @@ -3,37 +3,58 @@ package deployer import ( "context" "encoding/json" + "errors" "fmt" + xerrors "github.com/pkg/errors" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile" - ssl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205" + tcSsl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205" "github.com/usual2970/certimate/internal/domain" - "github.com/usual2970/certimate/internal/utils/rand" + "github.com/usual2970/certimate/internal/pkg/core/uploader" ) type TencentCLBDeployer struct { - option *DeployerOption - credential *common.Credential - infos []string + option *DeployerOption + infos []string + + sdkClients *tencentCLBDeployerSdkClients + sslUploader uploader.Uploader +} + +type tencentCLBDeployerSdkClients struct { + ssl *tcSsl.Client } func NewTencentCLBDeployer(option *DeployerOption) (Deployer, error) { access := &domain.TencentAccess{} if err := json.Unmarshal([]byte(option.Access), access); err != nil { - return nil, fmt.Errorf("failed to unmarshal tencent access: %w", err) + return nil, xerrors.Wrap(err, "failed to get access") } - credential := common.NewCredential( + clients, err := (&TencentCLBDeployer{}).createSdkClients( access.SecretId, access.SecretKey, + option.DeployConfig.GetConfigAsString("region"), ) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk clients") + } + + uploader, err := uploader.NewTencentCloudSSLUploader(&uploader.TencentCloudSSLUploaderConfig{ + SecretId: access.SecretId, + SecretKey: access.SecretKey, + }) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create ssl uploader") + } return &TencentCLBDeployer{ - option: option, - credential: credential, - infos: make([]string, 0), + option: option, + infos: make([]string, 0), + sdkClients: clients, + sslUploader: uploader, }, nil } @@ -46,72 +67,68 @@ func (d *TencentCLBDeployer) GetInfo() []string { } func (d *TencentCLBDeployer) Deploy(ctx context.Context) error { - // 上传证书 - certId, err := d.uploadCert() - if err != nil { - return fmt.Errorf("failed to upload certificate: %w", err) - } - d.infos = append(d.infos, toStr("上传证书", certId)) + // TODO: 直接部署方式 - if err := d.deploy(certId); err != nil { - return fmt.Errorf("failed to deploy: %w", err) + // 通过 SSL 服务部署到云资源实例 + err := d.deployToInstanceUseSsl(ctx) + if err != nil { + return err } return nil } -func (d *TencentCLBDeployer) uploadCert() (string, error) { - cpf := profile.NewClientProfile() - cpf.HttpProfile.Endpoint = "ssl.tencentcloudapi.com" +func (d *TencentCLBDeployer) createSdkClients(secretId, secretKey, region string) (*tencentCLBDeployerSdkClients, error) { + credential := common.NewCredential(secretId, secretKey) - client, _ := ssl.NewClient(d.credential, "", cpf) - - request := ssl.NewUploadCertificateRequest() - - request.CertificatePublicKey = common.StringPtr(d.option.Certificate.Certificate) - request.CertificatePrivateKey = common.StringPtr(d.option.Certificate.PrivateKey) - request.Alias = common.StringPtr(d.option.Domain + "_" + rand.RandStr(6)) - request.Repeatable = common.BoolPtr(false) - - response, err := client.UploadCertificate(request) + sslClient, err := tcSsl.NewClient(credential, "", profile.NewClientProfile()) if err != nil { - return "", fmt.Errorf("failed to upload certificate: %w", err) + return nil, err } - return *response.Response.CertificateId, nil + return &tencentCLBDeployerSdkClients{ + ssl: sslClient, + }, nil } -func (d *TencentCLBDeployer) deploy(certId string) error { - cpf := profile.NewClientProfile() - cpf.HttpProfile.Endpoint = "ssl.tencentcloudapi.com" - // 实例化要请求产品的client对象,clientProfile是可选的 - client, _ := ssl.NewClient(d.credential, getDeployString(d.option.DeployConfig, "region"), cpf) - - // 实例化一个请求对象,每个接口都会对应一个request对象 - request := ssl.NewDeployCertificateInstanceRequest() - - request.CertificateId = common.StringPtr(certId) - request.ResourceType = common.StringPtr("clb") - request.Status = common.Int64Ptr(1) - - clbId := getDeployString(d.option.DeployConfig, "clbId") - lsnId := getDeployString(d.option.DeployConfig, "lsnId") - domain := getDeployString(d.option.DeployConfig, "domain") - - if(domain == ""){ - // 未开启SNI,只需要精确到监听器 - request.InstanceIdList = common.StringPtrs([]string{fmt.Sprintf("%s|%s", clbId, lsnId)}) - }else{ - // 开启SNI,需要精确到域名,支持泛域名 - request.InstanceIdList = common.StringPtrs([]string{fmt.Sprintf("%s|%s|%s", clbId, lsnId, domain)}) +func (d *TencentCLBDeployer) deployToInstanceUseSsl(ctx context.Context) error { + tcLoadbalancerId := d.option.DeployConfig.GetConfigAsString("clbId") + tcListenerId := d.option.DeployConfig.GetConfigAsString("lsnId") + tcDomain := d.option.DeployConfig.GetConfigAsString("domain") + if tcLoadbalancerId == "" { + return errors.New("`loadbalancerId` is required") + } + if tcListenerId == "" { + return errors.New("`listenerId` is required") } - - // 返回的resp是一个DeployCertificateInstanceResponse的实例,与请求对象对应 - resp, err := client.DeployCertificateInstance(request) + // 上传证书到 SSL + upres, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey) if err != nil { - return fmt.Errorf("failed to deploy certificate: %w", err) + return err } - d.infos = append(d.infos, toStr("部署证书", resp.Response)) + + d.infos = append(d.infos, toStr("已上传证书", upres)) + + // 证书部署到 CLB 实例 + // REF: https://cloud.tencent.com/document/product/400/91667 + deployCertificateInstanceReq := tcSsl.NewDeployCertificateInstanceRequest() + deployCertificateInstanceReq.CertificateId = common.StringPtr(upres.CertId) + deployCertificateInstanceReq.ResourceType = common.StringPtr("clb") + deployCertificateInstanceReq.Status = common.Int64Ptr(1) + if tcDomain == "" { + // 未开启 SNI,只需指定到监听器 + deployCertificateInstanceReq.InstanceIdList = common.StringPtrs([]string{fmt.Sprintf("%s|%s", tcLoadbalancerId, tcListenerId)}) + } else { + // 开启 SNI,需指定到域名(支持泛域名) + deployCertificateInstanceReq.InstanceIdList = common.StringPtrs([]string{fmt.Sprintf("%s|%s|%s", tcLoadbalancerId, tcListenerId, tcDomain)}) + } + deployCertificateInstanceResp, err := d.sdkClients.ssl.DeployCertificateInstance(deployCertificateInstanceReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'ssl.DeployCertificateInstance'") + } + + d.infos = append(d.infos, toStr("已部署证书到云资源实例", deployCertificateInstanceResp.Response)) + return nil -} \ No newline at end of file +} diff --git a/internal/deployer/tencent_cos.go b/internal/deployer/tencent_cos.go index 2ea8c7d6..749f5249 100644 --- a/internal/deployer/tencent_cos.go +++ b/internal/deployer/tencent_cos.go @@ -3,37 +3,53 @@ package deployer import ( "context" "encoding/json" + "errors" "fmt" + xerrors "github.com/pkg/errors" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile" - ssl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205" + tcSsl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205" "github.com/usual2970/certimate/internal/domain" - "github.com/usual2970/certimate/internal/utils/rand" + "github.com/usual2970/certimate/internal/pkg/core/uploader" ) type TencentCOSDeployer struct { - option *DeployerOption - credential *common.Credential - infos []string + option *DeployerOption + infos []string + + sdkClient *tcSsl.Client + sslUploader uploader.Uploader } func NewTencentCOSDeployer(option *DeployerOption) (Deployer, error) { access := &domain.TencentAccess{} if err := json.Unmarshal([]byte(option.Access), access); err != nil { - return nil, fmt.Errorf("failed to unmarshal tencent access: %w", err) + return nil, xerrors.Wrap(err, "failed to get access") } - credential := common.NewCredential( + client, err := (&TencentCOSDeployer{}).createSdkClient( access.SecretId, access.SecretKey, ) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk clients") + } + + uploader, err := uploader.NewTencentCloudSSLUploader(&uploader.TencentCloudSSLUploaderConfig{ + SecretId: access.SecretId, + SecretKey: access.SecretKey, + }) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create ssl uploader") + } return &TencentCOSDeployer{ - option: option, - credential: credential, - infos: make([]string, 0), + option: option, + infos: make([]string, 0), + sdkClient: client, + sslUploader: uploader, }, nil } @@ -46,63 +62,44 @@ func (d *TencentCOSDeployer) GetInfo() []string { } func (d *TencentCOSDeployer) Deploy(ctx context.Context) error { - // 上传证书 - certId, err := d.uploadCert() - if err != nil { - return fmt.Errorf("failed to upload certificate: %w", err) + tcRegion := d.option.DeployConfig.GetConfigAsString("region") + tcBucket := d.option.DeployConfig.GetConfigAsString("bucket") + tcDomain := d.option.DeployConfig.GetConfigAsString("domain") + if tcBucket == "" { + return errors.New("`bucket` is required") } - d.infos = append(d.infos, toStr("上传证书", certId)) - if err := d.deploy(certId); err != nil { - return fmt.Errorf("failed to deploy: %w", err) + // 上传证书到 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)) + + // 证书部署到 CLB 实例 + // REF: https://cloud.tencent.com/document/product/400/91667 + deployCertificateInstanceReq := tcSsl.NewDeployCertificateInstanceRequest() + deployCertificateInstanceReq.CertificateId = common.StringPtr(upres.CertId) + deployCertificateInstanceReq.ResourceType = common.StringPtr("cos") + deployCertificateInstanceReq.Status = common.Int64Ptr(1) + deployCertificateInstanceReq.InstanceIdList = common.StringPtrs([]string{fmt.Sprintf("%s#%s#%s", tcRegion, tcBucket, tcDomain)}) + deployCertificateInstanceResp, err := d.sdkClient.DeployCertificateInstance(deployCertificateInstanceReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'ssl.DeployCertificateInstance'") + } + + d.infos = append(d.infos, toStr("已部署证书到云资源实例", deployCertificateInstanceResp.Response)) + return nil } -// 上传证书,与CDN部署的上传方法一致。 -func (d *TencentCOSDeployer) uploadCert() (string, error) { - cpf := profile.NewClientProfile() - cpf.HttpProfile.Endpoint = "ssl.tencentcloudapi.com" - - client, _ := ssl.NewClient(d.credential, "", cpf) - - request := ssl.NewUploadCertificateRequest() - - request.CertificatePublicKey = common.StringPtr(d.option.Certificate.Certificate) - request.CertificatePrivateKey = common.StringPtr(d.option.Certificate.PrivateKey) - request.Alias = common.StringPtr(d.option.Domain + "_" + rand.RandStr(6)) - request.Repeatable = common.BoolPtr(false) - - response, err := client.UploadCertificate(request) +func (d *TencentCOSDeployer) createSdkClient(secretId, secretKey string) (*tcSsl.Client, error) { + credential := common.NewCredential(secretId, secretKey) + client, err := tcSsl.NewClient(credential, "", profile.NewClientProfile()) if err != nil { - return "", fmt.Errorf("failed to upload certificate: %w", err) + return nil, err } - return *response.Response.CertificateId, nil + return client, nil } - -func (d *TencentCOSDeployer) deploy(certId string) error { - cpf := profile.NewClientProfile() - cpf.HttpProfile.Endpoint = "ssl.tencentcloudapi.com" - // 实例化要请求产品的client对象,clientProfile是可选的 - client, _ := ssl.NewClient(d.credential, getDeployString(d.option.DeployConfig, "region"), cpf) - - // 实例化一个请求对象,每个接口都会对应一个request对象 - request := ssl.NewDeployCertificateInstanceRequest() - - request.CertificateId = common.StringPtr(certId) - request.ResourceType = common.StringPtr("cos") - request.Status = common.Int64Ptr(1) - - domain := getDeployString(d.option.DeployConfig, "domain") - request.InstanceIdList = common.StringPtrs([]string{fmt.Sprintf("%s#%s#%s", getDeployString(d.option.DeployConfig, "region"), getDeployString(d.option.DeployConfig, "bucket"), domain)}) - - // 返回的resp是一个DeployCertificateInstanceResponse的实例,与请求对象对应 - resp, err := client.DeployCertificateInstance(request) - if err != nil { - return fmt.Errorf("failed to deploy certificate: %w", err) - } - d.infos = append(d.infos, toStr("部署证书", resp.Response)) - return nil -} \ No newline at end of file diff --git a/internal/deployer/tencent_ecdn.go b/internal/deployer/tencent_ecdn.go index ea52794e..0458c74d 100644 --- a/internal/deployer/tencent_ecdn.go +++ b/internal/deployer/tencent_ecdn.go @@ -2,41 +2,60 @@ package deployer import ( "context" - "encoding/base64" "encoding/json" "fmt" "strings" - cdn "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn/v20180606" + xerrors "github.com/pkg/errors" + tcCdn "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn/v20180606" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile" - ssl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205" + tcSsl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205" "github.com/usual2970/certimate/internal/domain" - "github.com/usual2970/certimate/internal/utils/rand" + "github.com/usual2970/certimate/internal/pkg/core/uploader" ) type TencentECDNDeployer struct { - option *DeployerOption - credential *common.Credential - infos []string + option *DeployerOption + infos []string + + sdkClients *tencentECDNDeployerSdkClients + sslUploader uploader.Uploader +} + +type tencentECDNDeployerSdkClients struct { + ssl *tcSsl.Client + cdn *tcCdn.Client } func NewTencentECDNDeployer(option *DeployerOption) (Deployer, error) { access := &domain.TencentAccess{} if err := json.Unmarshal([]byte(option.Access), access); err != nil { - return nil, fmt.Errorf("failed to unmarshal tencent access: %w", err) + return nil, xerrors.Wrap(err, "failed to get access") } - credential := common.NewCredential( + clients, err := (&TencentECDNDeployer{}).createSdkClients( access.SecretId, access.SecretKey, ) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk clients") + } + + uploader, err := uploader.NewTencentCloudSSLUploader(&uploader.TencentCloudSSLUploaderConfig{ + SecretId: access.SecretId, + SecretKey: access.SecretKey, + }) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create ssl uploader") + } return &TencentECDNDeployer{ - option: option, - credential: credential, - infos: make([]string, 0), + option: option, + infos: make([]string, 0), + sdkClients: clients, + sslUploader: uploader, }, nil } @@ -49,97 +68,85 @@ func (d *TencentECDNDeployer) GetInfo() []string { } func (d *TencentECDNDeployer) Deploy(ctx context.Context) error { - // 上传证书 - certId, err := d.uploadCert() + // 上传证书到 SSL + upres, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey) if err != nil { - return fmt.Errorf("failed to upload certificate: %w", err) + return err } - d.infos = append(d.infos, toStr("上传证书", certId)) - if err := d.deploy(certId); err != nil { - return fmt.Errorf("failed to deploy: %w", err) + d.infos = append(d.infos, toStr("已上传证书", upres)) + + // 获取待部署的 ECDN 实例 + // 如果是泛域名,根据证书匹配 ECDN 实例 + aliInstanceIds := make([]string, 0) + domain := d.option.DeployConfig.GetConfigAsString("domain") + if strings.HasPrefix(domain, "*") { + domains, err := d.getDomainsByCertificateId(upres.CertId) + if err != nil { + return err + } + + aliInstanceIds = domains + } else { + aliInstanceIds = append(aliInstanceIds, domain) } + if len(aliInstanceIds) == 0 { + d.infos = append(d.infos, "没有要部署的 ECDN 实例") + return nil + } + + // 证书部署到 ECDN 实例 + // REF: https://cloud.tencent.com/document/product/400/91667 + deployCertificateInstanceReq := tcSsl.NewDeployCertificateInstanceRequest() + deployCertificateInstanceReq.CertificateId = common.StringPtr(upres.CertId) + deployCertificateInstanceReq.ResourceType = common.StringPtr("ecdn") + deployCertificateInstanceReq.Status = common.Int64Ptr(1) + deployCertificateInstanceReq.InstanceIdList = common.StringPtrs(aliInstanceIds) + deployCertificateInstanceResp, err := d.sdkClients.ssl.DeployCertificateInstance(deployCertificateInstanceReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'ssl.DeployCertificateInstance'") + } + + d.infos = append(d.infos, toStr("已部署证书到云资源实例", deployCertificateInstanceResp.Response)) return nil } -func (d *TencentECDNDeployer) uploadCert() (string, error) { - cpf := profile.NewClientProfile() - cpf.HttpProfile.Endpoint = "ssl.tencentcloudapi.com" +func (d *TencentECDNDeployer) createSdkClients(secretId, secretKey string) (*tencentECDNDeployerSdkClients, error) { + credential := common.NewCredential(secretId, secretKey) - client, _ := ssl.NewClient(d.credential, "", cpf) - - request := ssl.NewUploadCertificateRequest() - - request.CertificatePublicKey = common.StringPtr(d.option.Certificate.Certificate) - request.CertificatePrivateKey = common.StringPtr(d.option.Certificate.PrivateKey) - request.Alias = common.StringPtr(d.option.Domain + "_" + rand.RandStr(6)) - request.Repeatable = common.BoolPtr(false) - - response, err := client.UploadCertificate(request) + sslClient, err := tcSsl.NewClient(credential, "", profile.NewClientProfile()) if err != nil { - return "", fmt.Errorf("failed to upload certificate: %w", err) + return nil, err } - return *response.Response.CertificateId, nil + cdnClient, err := tcCdn.NewClient(credential, "", profile.NewClientProfile()) + if err != nil { + return nil, err + } + + return &tencentECDNDeployerSdkClients{ + ssl: sslClient, + cdn: cdnClient, + }, nil } -func (d *TencentECDNDeployer) deploy(certId string) error { - cpf := profile.NewClientProfile() - cpf.HttpProfile.Endpoint = "ssl.tencentcloudapi.com" - // 实例化要请求产品的client对象,clientProfile是可选的 - client, _ := ssl.NewClient(d.credential, "", cpf) - - // 实例化一个请求对象,每个接口都会对应一个request对象 - request := ssl.NewDeployCertificateInstanceRequest() - - request.CertificateId = common.StringPtr(certId) - request.ResourceType = common.StringPtr("ecdn") - request.Status = common.Int64Ptr(1) - - // 如果是泛域名就从cdn列表下获取SSL证书中的可用域名 - domain := getDeployString(d.option.DeployConfig, "domain") - if strings.Contains(domain, "*") { - list, errGetList := d.getDomainList() - if errGetList != nil { - return fmt.Errorf("failed to get certificate domain list: %w", errGetList) - } - if list == nil || len(list) == 0 { - return fmt.Errorf("failed to get certificate domain list: empty list.") - } - request.InstanceIdList = common.StringPtrs(list) - } else { // 否则直接使用传入的域名 - request.InstanceIdList = common.StringPtrs([]string{domain}) - } - - // 返回的resp是一个DeployCertificateInstanceResponse的实例,与请求对象对应 - resp, err := client.DeployCertificateInstance(request) +func (d *TencentECDNDeployer) getDomainsByCertificateId(tcCertId string) ([]string, error) { + // 获取证书中的可用域名 + // REF: https://cloud.tencent.com/document/product/228/42491 + describeCertDomainsReq := tcCdn.NewDescribeCertDomainsRequest() + describeCertDomainsReq.CertId = common.StringPtr(tcCertId) + describeCertDomainsReq.Product = common.StringPtr("ecdn") + describeCertDomainsResp, err := d.sdkClients.cdn.DescribeCertDomains(describeCertDomainsReq) if err != nil { - return fmt.Errorf("failed to deploy certificate: %w", err) - } - d.infos = append(d.infos, toStr("部署证书", resp.Response)) - return nil -} - -func (d *TencentECDNDeployer) getDomainList() ([]string, error) { - cpf := profile.NewClientProfile() - cpf.HttpProfile.Endpoint = "cdn.tencentcloudapi.com" - client, _ := cdn.NewClient(d.credential, "", cpf) - - request := cdn.NewDescribeCertDomainsRequest() - - cert := base64.StdEncoding.EncodeToString([]byte(d.option.Certificate.Certificate)) - request.Cert = &cert - request.Product = common.StringPtr("ecdn") - - response, err := client.DescribeCertDomains(request) - if err != nil { - return nil, fmt.Errorf("failed to get domain list: %w", err) + return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.DescribeCertDomains'") } domains := make([]string, 0) - for _, domain := range response.Response.Domains { - domains = append(domains, *domain) + if describeCertDomainsResp.Response.Domains == nil { + for _, domain := range describeCertDomainsResp.Response.Domains { + domains = append(domains, *domain) + } } return domains, nil diff --git a/internal/deployer/tencent_teo.go b/internal/deployer/tencent_teo.go index f31aee8d..83eca55e 100644 --- a/internal/deployer/tencent_teo.go +++ b/internal/deployer/tencent_teo.go @@ -6,36 +6,56 @@ import ( "fmt" "strings" - teo "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo/v20220901" + xerrors "github.com/pkg/errors" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile" - ssl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205" + tcSsl "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl/v20191205" + tcTeo "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo/v20220901" "github.com/usual2970/certimate/internal/domain" - "github.com/usual2970/certimate/internal/utils/rand" + "github.com/usual2970/certimate/internal/pkg/core/uploader" ) type TencentTEODeployer struct { - option *DeployerOption - credential *common.Credential - infos []string + option *DeployerOption + infos []string + + sdkClients *tencentTEODeployerSdkClients + sslUploader uploader.Uploader +} + +type tencentTEODeployerSdkClients struct { + ssl *tcSsl.Client + teo *tcTeo.Client } func NewTencentTEODeployer(option *DeployerOption) (Deployer, error) { access := &domain.TencentAccess{} if err := json.Unmarshal([]byte(option.Access), access); err != nil { - return nil, fmt.Errorf("failed to unmarshal tencent access: %w", err) + return nil, xerrors.Wrap(err, "failed to get access") } - credential := common.NewCredential( + clients, err := (&TencentTEODeployer{}).createSdkClients( access.SecretId, access.SecretKey, ) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk clients") + } + + uploader, err := uploader.NewTencentCloudSSLUploader(&uploader.TencentCloudSSLUploaderConfig{ + SecretId: access.SecretId, + SecretKey: access.SecretKey, + }) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create ssl uploader") + } return &TencentTEODeployer{ - option: option, - credential: credential, - infos: make([]string, 0), + option: option, + infos: make([]string, 0), + sdkClients: clients, + sslUploader: uploader, }, nil } @@ -48,64 +68,51 @@ func (d *TencentTEODeployer) GetInfo() []string { } func (d *TencentTEODeployer) Deploy(ctx context.Context) error { - // 上传证书 - certId, err := d.uploadCert() - if err != nil { - return fmt.Errorf("failed to upload certificate: %w", err) + tcZoneId := d.option.DeployConfig.GetConfigAsString("zoneId") + if tcZoneId == "" { + return xerrors.New("`zoneId` is required") } - d.infos = append(d.infos, toStr("上传证书", certId)) - if err := d.deploy(certId); err != nil { - return fmt.Errorf("failed to deploy: %w", err) + // 上传证书到 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/product/1552/80764 + modifyHostsCertificateReq := tcTeo.NewModifyHostsCertificateRequest() + modifyHostsCertificateReq.ZoneId = common.StringPtr(tcZoneId) + modifyHostsCertificateReq.Mode = common.StringPtr("sslcert") + modifyHostsCertificateReq.Hosts = common.StringPtrs(strings.Split(strings.ReplaceAll(d.option.Domain, "\r\n", "\n"), "\n")) + modifyHostsCertificateReq.ServerCertInfo = []*tcTeo.ServerCertInfo{{CertId: common.StringPtr(upres.CertId)}} + modifyHostsCertificateResp, err := d.sdkClients.teo.ModifyHostsCertificate(modifyHostsCertificateReq) + if err != nil { + return xerrors.Wrap(err, "failed to execute sdk request 'teo.ModifyHostsCertificate'") + } + + d.infos = append(d.infos, toStr("已配置域名证书", modifyHostsCertificateResp.Response)) + return nil } -func (d *TencentTEODeployer) uploadCert() (string, error) { - cpf := profile.NewClientProfile() - cpf.HttpProfile.Endpoint = "ssl.tencentcloudapi.com" +func (d *TencentTEODeployer) createSdkClients(secretId, secretKey string) (*tencentTEODeployerSdkClients, error) { + credential := common.NewCredential(secretId, secretKey) - client, _ := ssl.NewClient(d.credential, "", cpf) - - request := ssl.NewUploadCertificateRequest() - - request.CertificatePublicKey = common.StringPtr(d.option.Certificate.Certificate) - request.CertificatePrivateKey = common.StringPtr(d.option.Certificate.PrivateKey) - request.Alias = common.StringPtr(d.option.Domain + "_" + rand.RandStr(6)) - request.Repeatable = common.BoolPtr(false) - - response, err := client.UploadCertificate(request) + sslClient, err := tcSsl.NewClient(credential, "", profile.NewClientProfile()) if err != nil { - return "", fmt.Errorf("failed to upload certificate: %w", err) + return nil, err } - return *response.Response.CertificateId, nil -} - -func (d *TencentTEODeployer) deploy(certId string) error { - cpf := profile.NewClientProfile() - cpf.HttpProfile.Endpoint = "teo.tencentcloudapi.com" - // 实例化要请求产品的client对象,clientProfile是可选的 - client, _ := teo.NewClient(d.credential, "", cpf) - - // 实例化一个请求对象,每个接口都会对应一个request对象 - request := teo.NewModifyHostsCertificateRequest() - - request.ZoneId = common.StringPtr(getDeployString(d.option.DeployConfig, "zoneId")) - request.Mode = common.StringPtr("sslcert") - request.ServerCertInfo = []*teo.ServerCertInfo{{ - CertId: common.StringPtr(certId), - }} - - domains := strings.Split(strings.ReplaceAll(d.option.Domain, "\r\n", "\n"),"\n") - request.Hosts = common.StringPtrs(domains) - - // 返回的resp是一个DeployCertificateInstanceResponse的实例,与请求对象对应 - resp, err := client.ModifyHostsCertificate(request) + teoClient, err := tcTeo.NewClient(credential, "", profile.NewClientProfile()) if err != nil { - return fmt.Errorf("failed to deploy certificate: %w", err) + return nil, err } - d.infos = append(d.infos, toStr("部署证书", resp.Response)) - return nil + + return &tencentTEODeployerSdkClients{ + ssl: sslClient, + teo: teoClient, + }, nil } diff --git a/internal/deployer/webhook.go b/internal/deployer/webhook.go index 522705d4..bc227f0d 100644 --- a/internal/deployer/webhook.go +++ b/internal/deployer/webhook.go @@ -7,6 +7,8 @@ import ( "fmt" "net/http" + xerrors "github.com/pkg/errors" + "github.com/usual2970/certimate/internal/domain" xhttp "github.com/usual2970/certimate/internal/utils/http" ) @@ -41,7 +43,7 @@ type webhookData struct { func (d *WebhookDeployer) Deploy(ctx context.Context) error { access := &domain.WebhookAccess{} if err := json.Unmarshal([]byte(d.option.Access), access); err != nil { - return fmt.Errorf("failed to parse hook access config: %w", err) + return xerrors.Wrap(err, "failed to get access") } data := &webhookData{ @@ -50,17 +52,15 @@ func (d *WebhookDeployer) Deploy(ctx context.Context) error { PrivateKey: d.option.Certificate.PrivateKey, Variables: getDeployVariables(d.option.DeployConfig), } - body, _ := json.Marshal(data) - resp, err := xhttp.Req(access.Url, http.MethodPost, bytes.NewReader(body), map[string]string{ "Content-Type": "application/json", }) if err != nil { - return fmt.Errorf("failed to send hook request: %w", err) + return xerrors.Wrap(err, "failed to send webhook request") } - d.infos = append(d.infos, toStr("webhook response", string(resp))) + d.infos = append(d.infos, toStr("Webhook Response", string(resp))) return nil } From ce553652925f5a126f85a1d5c0e61cbcc11b8f83 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Thu, 31 Oct 2024 10:14:27 +0800 Subject: [PATCH 04/18] refactor: extend huaweicloud cdn sdk --- internal/deployer/huaweicloud_cdn.go | 82 ++----------------- internal/pkg/utils/x509/common.go | 22 +++++ internal/pkg/utils/x509/converter.go | 31 +++++++ .../pkg/utils/x509/{x509.go => parser.go} | 39 --------- .../pkg/vendors/huaweicloud-cdn-sdk/client.go | 26 ++++++ .../pkg/vendors/huaweicloud-cdn-sdk/models.go | 62 ++++++++++++++ 6 files changed, 150 insertions(+), 112 deletions(-) create mode 100644 internal/pkg/utils/x509/common.go create mode 100644 internal/pkg/utils/x509/converter.go rename internal/pkg/utils/x509/{x509.go => parser.go} (60%) create mode 100644 internal/pkg/vendors/huaweicloud-cdn-sdk/client.go create mode 100644 internal/pkg/vendors/huaweicloud-cdn-sdk/models.go diff --git a/internal/deployer/huaweicloud_cdn.go b/internal/deployer/huaweicloud_cdn.go index e8f35171..dfbe131e 100644 --- a/internal/deployer/huaweicloud_cdn.go +++ b/internal/deployer/huaweicloud_cdn.go @@ -15,13 +15,14 @@ import ( "github.com/usual2970/certimate/internal/domain" "github.com/usual2970/certimate/internal/pkg/core/uploader" "github.com/usual2970/certimate/internal/pkg/utils/cast" + hcCdnEx "github.com/usual2970/certimate/internal/pkg/vendors/huaweicloud-cdn-sdk" ) type HuaweiCloudCDNDeployer struct { option *DeployerOption infos []string - sdkClient *hcCdn.CdnClient + sdkClient *hcCdnEx.Client sslUploader uploader.Uploader } @@ -40,7 +41,6 @@ func NewHuaweiCloudCDNDeployer(option *DeployerOption) (Deployer, error) { return nil, xerrors.Wrap(err, "failed to create sdk client") } - // TODO: SCM 服务与 DNS 服务所支持的区域可能不一致,这里暂时不传而是使用默认值,仅支持华为云国内版 uploader, err := uploader.NewHuaweiCloudSCMUploader(&uploader.HuaweiCloudSCMUploaderConfig{ AccessKeyId: access.AccessKeyId, SecretAccessKey: access.SecretAccessKey, @@ -82,10 +82,9 @@ func (d *HuaweiCloudCDNDeployer) Deploy(ctx context.Context) error { // 更新加速域名配置 // REF: https://support.huaweicloud.com/api-cdn/UpdateDomainMultiCertificates.html // REF: https://support.huaweicloud.com/usermanual-cdn/cdn_01_0306.html - updateDomainMultiCertificatesReqBodyContent := &huaweicloudCDNUpdateDomainMultiCertificatesRequestBodyContent{} + updateDomainMultiCertificatesReqBodyContent := &hcCdnEx.UpdateDomainMultiCertificatesExRequestBodyContent{} updateDomainMultiCertificatesReqBodyContent.DomainName = d.option.DeployConfig.GetConfigAsString("domain") updateDomainMultiCertificatesReqBodyContent.HttpsSwitch = 1 - var updateDomainMultiCertificatesResp *hcCdnModel.UpdateDomainMultiCertificatesResponse if d.option.DeployConfig.GetConfigAsBool("useSCM") { // 上传证书到 SCM upres, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey) @@ -104,13 +103,13 @@ func (d *HuaweiCloudCDNDeployer) Deploy(ctx context.Context) error { updateDomainMultiCertificatesReqBodyContent.Certificate = cast.StringPtr(d.option.Certificate.Certificate) updateDomainMultiCertificatesReqBodyContent.PrivateKey = cast.StringPtr(d.option.Certificate.PrivateKey) } - updateDomainMultiCertificatesReqBodyContent = mergeHuaweiCloudCDNConfig(showDomainFullConfigResp.Configs, updateDomainMultiCertificatesReqBodyContent) - updateDomainMultiCertificatesReq := &huaweicloudCDNUpdateDomainMultiCertificatesRequest{ - Body: &huaweicloudCDNUpdateDomainMultiCertificatesRequestBody{ + updateDomainMultiCertificatesReqBodyContent = updateDomainMultiCertificatesReqBodyContent.MergeConfig(showDomainFullConfigResp.Configs) + updateDomainMultiCertificatesReq := &hcCdnEx.UpdateDomainMultiCertificatesExRequest{ + Body: &hcCdnEx.UpdateDomainMultiCertificatesExRequestBody{ Https: updateDomainMultiCertificatesReqBodyContent, }, } - updateDomainMultiCertificatesResp, err = executeHuaweiCloudCDNUploadDomainMultiCertificates(d.sdkClient, updateDomainMultiCertificatesReq) + updateDomainMultiCertificatesResp, err := d.sdkClient.UploadDomainMultiCertificatesEx(updateDomainMultiCertificatesReq) if err != nil { return err } @@ -120,7 +119,7 @@ func (d *HuaweiCloudCDNDeployer) Deploy(ctx context.Context) error { return nil } -func (d *HuaweiCloudCDNDeployer) createSdkClient(accessKeyId, secretAccessKey, region string) (*hcCdn.CdnClient, error) { +func (d *HuaweiCloudCDNDeployer) createSdkClient(accessKeyId, secretAccessKey, region string) (*hcCdnEx.Client, error) { if region == "" { region = "cn-north-1" // CDN 服务默认区域:华北一北京 } @@ -146,69 +145,6 @@ func (d *HuaweiCloudCDNDeployer) createSdkClient(accessKeyId, secretAccessKey, r return nil, err } - client := hcCdn.NewCdnClient(hcClient) + client := hcCdnEx.NewClient(hcClient) return client, nil } - -type huaweicloudCDNUpdateDomainMultiCertificatesRequestBodyContent struct { - hcCdnModel.UpdateDomainMultiCertificatesRequestBodyContent `json:",inline"` - - SCMCertificateId *string `json:"scm_certificate_id,omitempty"` -} - -type huaweicloudCDNUpdateDomainMultiCertificatesRequestBody struct { - Https *huaweicloudCDNUpdateDomainMultiCertificatesRequestBodyContent `json:"https,omitempty"` -} - -type huaweicloudCDNUpdateDomainMultiCertificatesRequest struct { - Body *huaweicloudCDNUpdateDomainMultiCertificatesRequestBody `json:"body,omitempty"` -} - -func executeHuaweiCloudCDNUploadDomainMultiCertificates(client *hcCdn.CdnClient, request *huaweicloudCDNUpdateDomainMultiCertificatesRequest) (*hcCdnModel.UpdateDomainMultiCertificatesResponse, error) { - // 华为云官方 SDK 中目前提供的字段缺失,这里暂时先需自定义请求 - // 可能需要等之后 SDK 更新 - - requestDef := hcCdn.GenReqDefForUpdateDomainMultiCertificates() - - if resp, err := client.HcClient.Sync(request, requestDef); err != nil { - return nil, err - } else { - return resp.(*hcCdnModel.UpdateDomainMultiCertificatesResponse), nil - } -} - -func mergeHuaweiCloudCDNConfig(src *hcCdnModel.ConfigsGetBody, dest *huaweicloudCDNUpdateDomainMultiCertificatesRequestBodyContent) *huaweicloudCDNUpdateDomainMultiCertificatesRequestBodyContent { - if src == nil { - return dest - } - - // 华为云 API 中不传的字段表示使用默认值、而非保留原值,因此这里需要把原配置中的参数重新赋值回去 - // 而且蛋疼的是查询接口返回的数据结构和更新接口传入的参数结构不一致,需要做很多转化 - - if *src.OriginProtocol == "follow" { - dest.AccessOriginWay = cast.Int32Ptr(1) - } else if *src.OriginProtocol == "http" { - dest.AccessOriginWay = cast.Int32Ptr(2) - } else if *src.OriginProtocol == "https" { - dest.AccessOriginWay = cast.Int32Ptr(3) - } - - if src.ForceRedirect != nil { - dest.ForceRedirectConfig = &hcCdnModel.ForceRedirect{} - - if src.ForceRedirect.Status == "on" { - dest.ForceRedirectConfig.Switch = 1 - dest.ForceRedirectConfig.RedirectType = src.ForceRedirect.Type - } else { - dest.ForceRedirectConfig.Switch = 0 - } - } - - if src.Https != nil { - if *src.Https.Http2Status == "on" { - dest.Http2 = cast.Int32Ptr(1) - } - } - - return dest -} diff --git a/internal/pkg/utils/x509/common.go b/internal/pkg/utils/x509/common.go new file mode 100644 index 00000000..f5557962 --- /dev/null +++ b/internal/pkg/utils/x509/common.go @@ -0,0 +1,22 @@ +package x509 + +import ( + "crypto/x509" +) + +// 比较两个 x509.Certificate 对象,判断它们是否是同一张证书。 +// 注意,这不是精确比较,而只是基于证书序列号和数字签名的快速判断,但对于权威 CA 签发的证书来说不会存在误判。 +// +// 入参: +// - a: 待比较的第一个 x509.Certificate 对象。 +// - b: 待比较的第二个 x509.Certificate 对象。 +// +// 出参: +// - 是否相同。 +func EqualCertificate(a, b *x509.Certificate) bool { + return string(a.Signature) == string(b.Signature) && + a.SignatureAlgorithm == b.SignatureAlgorithm && + a.SerialNumber.String() == b.SerialNumber.String() && + a.Issuer.SerialNumber == b.Issuer.SerialNumber && + a.Subject.SerialNumber == b.Subject.SerialNumber +} diff --git a/internal/pkg/utils/x509/converter.go b/internal/pkg/utils/x509/converter.go new file mode 100644 index 00000000..c5522f27 --- /dev/null +++ b/internal/pkg/utils/x509/converter.go @@ -0,0 +1,31 @@ +package x509 + +import ( + "crypto/ecdsa" + "crypto/x509" + "encoding/pem" + + xerrors "github.com/pkg/errors" +) + +// 将 ecdsa.PrivateKey 对象转换为 PEM 编码的字符串。 +// +// 入参: +// - privkey: ecdsa.PrivateKey 对象。 +// +// 出参: +// - privkeyPem: 私钥 PEM 内容。 +// - err: 错误。 +func ConvertECPrivateKeyToPEM(privkey *ecdsa.PrivateKey) (privkeyPem string, err error) { + data, err := x509.MarshalECPrivateKey(privkey) + if err != nil { + return "", xerrors.Wrap(err, "failed to marshal EC private key") + } + + block := &pem.Block{ + Type: "EC PRIVATE KEY", + Bytes: data, + } + + return string(pem.EncodeToMemory(block)), nil +} diff --git a/internal/pkg/utils/x509/x509.go b/internal/pkg/utils/x509/parser.go similarity index 60% rename from internal/pkg/utils/x509/x509.go rename to internal/pkg/utils/x509/parser.go index 2a70a083..d9604526 100644 --- a/internal/pkg/utils/x509/x509.go +++ b/internal/pkg/utils/x509/parser.go @@ -10,23 +10,6 @@ import ( xerrors "github.com/pkg/errors" ) -// 比较两个 x509.Certificate 对象,判断它们是否是同一张证书。 -// 注意,这不是精确比较,而只是基于证书序列号和数字签名的快速判断,但对于权威 CA 签发的证书来说不会存在误判。 -// -// 入参: -// - a: 待比较的第一个 x509.Certificate 对象。 -// - b: 待比较的第二个 x509.Certificate 对象。 -// -// 出参: -// - 是否相同。 -func EqualCertificate(a, b *x509.Certificate) bool { - return string(a.Signature) == string(b.Signature) && - a.SignatureAlgorithm == b.SignatureAlgorithm && - a.SerialNumber.String() == b.SerialNumber.String() && - a.Issuer.SerialNumber == b.Issuer.SerialNumber && - a.Subject.SerialNumber == b.Subject.SerialNumber -} - // 从 PEM 编码的证书字符串解析并返回一个 x509.Certificate 对象。 // // 入参: @@ -98,25 +81,3 @@ func ParsePKCS1PrivateKeyFromPEM(privkeyPem string) (privkey *rsa.PrivateKey, er return privkey, nil } - -// 将 ecdsa.PrivateKey 对象转换为 PEM 编码的字符串。 -// -// 入参: -// - privkey: ecdsa.PrivateKey 对象。 -// -// 出参: -// - privkeyPem: 私钥 PEM 内容。 -// - err: 错误。 -func ConvertECPrivateKeyToPEM(privkey *ecdsa.PrivateKey) (privkeyPem string, err error) { - data, err := x509.MarshalECPrivateKey(privkey) - if err != nil { - return "", xerrors.Wrap(err, "failed to marshal EC private key") - } - - block := &pem.Block{ - Type: "EC PRIVATE KEY", - Bytes: data, - } - - return string(pem.EncodeToMemory(block)), nil -} diff --git a/internal/pkg/vendors/huaweicloud-cdn-sdk/client.go b/internal/pkg/vendors/huaweicloud-cdn-sdk/client.go new file mode 100644 index 00000000..8befeb5f --- /dev/null +++ b/internal/pkg/vendors/huaweicloud-cdn-sdk/client.go @@ -0,0 +1,26 @@ +package huaweicloudcdnsdk + +import ( + "github.com/huaweicloud/huaweicloud-sdk-go-v3/core" + hcCdn "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/cdn/v2" +) + +type Client struct { + hcCdn.CdnClient +} + +func NewClient(hcClient *core.HcHttpClient) *Client { + return &Client{ + CdnClient: *hcCdn.NewCdnClient(hcClient), + } +} + +func (c *Client) UploadDomainMultiCertificatesEx(request *UpdateDomainMultiCertificatesExRequest) (*UpdateDomainMultiCertificatesExResponse, error) { + requestDef := hcCdn.GenReqDefForUpdateDomainMultiCertificates() + + if resp, err := c.HcClient.Sync(request, requestDef); err != nil { + return nil, err + } else { + return resp.(*UpdateDomainMultiCertificatesExResponse), nil + } +} diff --git a/internal/pkg/vendors/huaweicloud-cdn-sdk/models.go b/internal/pkg/vendors/huaweicloud-cdn-sdk/models.go new file mode 100644 index 00000000..cca42058 --- /dev/null +++ b/internal/pkg/vendors/huaweicloud-cdn-sdk/models.go @@ -0,0 +1,62 @@ +package huaweicloudcdnsdk + +import ( + hcCdnModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/cdn/v2/model" + + "github.com/usual2970/certimate/internal/pkg/utils/cast" +) + +type UpdateDomainMultiCertificatesExRequestBodyContent struct { + hcCdnModel.UpdateDomainMultiCertificatesRequestBodyContent `json:",inline"` + + // 华为云官方 SDK 中目前提供的字段缺失,这里暂时先需自定义请求,可能需要等之后 SDK 更新。 + SCMCertificateId *string `json:"scm_certificate_id,omitempty"` +} + +type UpdateDomainMultiCertificatesExRequestBody struct { + Https *UpdateDomainMultiCertificatesExRequestBodyContent `json:"https,omitempty"` +} + +type UpdateDomainMultiCertificatesExRequest struct { + Body *UpdateDomainMultiCertificatesExRequestBody `json:"body,omitempty"` +} + +type UpdateDomainMultiCertificatesExResponse struct { + hcCdnModel.UpdateDomainMultiCertificatesResponse +} + +func (m *UpdateDomainMultiCertificatesExRequestBodyContent) MergeConfig(src *hcCdnModel.ConfigsGetBody) *UpdateDomainMultiCertificatesExRequestBodyContent { + if src == nil { + return m + } + + // 华为云 API 中不传的字段表示使用默认值、而非保留原值,因此这里需要把原配置中的参数重新赋值回去。 + // 而且蛋疼的是查询接口返回的数据结构和更新接口传入的参数结构不一致,需要做很多转化。 + + if *src.OriginProtocol == "follow" { + m.AccessOriginWay = cast.Int32Ptr(1) + } else if *src.OriginProtocol == "http" { + m.AccessOriginWay = cast.Int32Ptr(2) + } else if *src.OriginProtocol == "https" { + m.AccessOriginWay = cast.Int32Ptr(3) + } + + if src.ForceRedirect != nil { + m.ForceRedirectConfig = &hcCdnModel.ForceRedirect{} + + if src.ForceRedirect.Status == "on" { + m.ForceRedirectConfig.Switch = 1 + m.ForceRedirectConfig.RedirectType = src.ForceRedirect.Type + } else { + m.ForceRedirectConfig.Switch = 0 + } + } + + if src.Https != nil { + if *src.Https.Http2Status == "on" { + m.Http2 = cast.Int32Ptr(1) + } + } + + return m +} From 3c3d4e91094bace5b93c71ed66aa8f1251d83bfa Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Thu, 31 Oct 2024 11:37:03 +0800 Subject: [PATCH 05/18] refactor: extend qiniu sdk --- internal/deployer/qiniu_cdn.go | 222 +++++------------- internal/deployer/qiniu_cdn_test.go | 85 ------- .../core/uploader/uploader_qiniu_sslcert.go | 69 ++++++ internal/pkg/vendors/qiniu-sdk/client.go | 160 +++++++++++++ internal/pkg/vendors/qiniu-sdk/models.go | 53 +++++ 5 files changed, 338 insertions(+), 251 deletions(-) delete mode 100644 internal/deployer/qiniu_cdn_test.go create mode 100644 internal/pkg/core/uploader/uploader_qiniu_sslcert.go create mode 100644 internal/pkg/vendors/qiniu-sdk/client.go create mode 100644 internal/pkg/vendors/qiniu-sdk/models.go diff --git a/internal/deployer/qiniu_cdn.go b/internal/deployer/qiniu_cdn.go index 797e3427..73e82ae0 100644 --- a/internal/deployer/qiniu_cdn.go +++ b/internal/deployer/qiniu_cdn.go @@ -1,38 +1,53 @@ package deployer import ( - "bytes" "context" "encoding/json" "fmt" - "io" - "net/http" + xerrors "github.com/pkg/errors" "github.com/qiniu/go-sdk/v7/auth" "github.com/usual2970/certimate/internal/domain" - xhttp "github.com/usual2970/certimate/internal/utils/http" + "github.com/usual2970/certimate/internal/pkg/core/uploader" + qiniuEx "github.com/usual2970/certimate/internal/pkg/vendors/qiniu-sdk" ) -const qiniuGateway = "http://api.qiniu.com" - type QiniuCDNDeployer struct { - option *DeployerOption - info []string - credentials *auth.Credentials + option *DeployerOption + infos []string + + sdkClient *qiniuEx.Client + sslUploader uploader.Uploader } -func NewQiniuCDNDeployer(option *DeployerOption) (*QiniuCDNDeployer, error) { +func NewQiniuCDNDeployer(option *DeployerOption) (Deployer, error) { access := &domain.QiniuAccess{} if err := json.Unmarshal([]byte(option.Access), access); err != nil { - return nil, fmt.Errorf("failed to get access: %w", err) + return nil, xerrors.Wrap(err, "failed to get access") + } + + client, err := (&QiniuCDNDeployer{}).createSdkClient( + access.AccessKey, + access.SecretKey, + ) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + uploader, err := uploader.NewQiniuSSLCertUploader(&uploader.QiniuSSLCertUploaderConfig{ + AccessKey: access.AccessKey, + SecretKey: access.SecretKey, + }) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create ssl uploader") } return &QiniuCDNDeployer{ - option: option, - info: make([]string, 0), - - credentials: auth.New(access.AccessKey, access.SecretKey), + option: option, + infos: make([]string, 0), + sdkClient: client, + sslUploader: uploader, }, nil } @@ -41,176 +56,51 @@ func (d *QiniuCDNDeployer) GetID() string { } func (d *QiniuCDNDeployer) GetInfo() []string { - return d.info + return d.infos } func (d *QiniuCDNDeployer) Deploy(ctx context.Context) error { // 上传证书 - certId, err := d.uploadCert() + upres, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey) if err != nil { - return fmt.Errorf("uploadCert failed: %w", err) + return err } + d.infos = append(d.infos, toStr("已上传证书", upres)) + // 获取域名信息 - domainInfo, err := d.getDomainInfo() + // REF: https://developer.qiniu.com/fusion/4246/the-domain-name + domain := d.option.DeployConfig.GetConfigAsString("domain") + getDomainInfoResp, err := d.sdkClient.GetDomainInfo(domain) if err != nil { - return fmt.Errorf("getDomainInfo failed: %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'cdn.GetDomainInfo'") } - // 判断域名是否启用 https - if domainInfo.Https != nil && domainInfo.Https.CertID != "" { - // 启用了 https - // 修改域名证书 - err = d.modifyDomainCert(certId, domainInfo.Https.ForceHttps, domainInfo.Https.Http2Enable) + d.infos = append(d.infos, toStr("已获取域名信息", 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(domain, upres.CertId, getDomainInfoResp.Https.ForceHttps, getDomainInfoResp.Https.Http2Enable) if err != nil { - return fmt.Errorf("modifyDomainCert failed: %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'cdn.ModifyDomainHttpsConf'") } + + d.infos = append(d.infos, toStr("已修改域名证书", modifyDomainHttpsConfResp)) } else { - // 没启用 https - // 启用 https - err = d.enableHttps(certId) + enableDomainHttpsResp, err := d.sdkClient.EnableDomainHttps(domain, upres.CertId, true, true) if err != nil { - return fmt.Errorf("enableHttps failed: %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'cdn.EnableDomainHttps'") } + + d.infos = append(d.infos, toStr("已将域名升级为 HTTPS", enableDomainHttpsResp)) } return nil } -func (d *QiniuCDNDeployer) enableHttps(certId string) error { - domain := d.option.DeployConfig.GetDomain() - path := fmt.Sprintf("/domain/%s/sslize", domain) - - body := &qiniuModifyDomainCertReq{ - CertID: certId, - ForceHttps: true, - Http2Enable: true, - } - - bodyBytes, err := json.Marshal(body) - if err != nil { - return fmt.Errorf("enable https failed: %w", err) - } - - _, err = d.req(qiniuGateway+path, http.MethodPut, bytes.NewReader(bodyBytes)) - if err != nil { - return fmt.Errorf("enable https failed: %w", err) - } - - return nil -} - -type qiniuDomainInfo struct { - Https *qiniuModifyDomainCertReq `json:"https"` -} - -func (d *QiniuCDNDeployer) getDomainInfo() (*qiniuDomainInfo, error) { - domain := d.option.DeployConfig.GetDomain() - - path := fmt.Sprintf("/domain/%s", domain) - - res, err := d.req(qiniuGateway+path, http.MethodGet, nil) - if err != nil { - return nil, fmt.Errorf("req failed: %w", err) - } - - resp := &qiniuDomainInfo{} - err = json.Unmarshal(res, resp) - if err != nil { - return nil, fmt.Errorf("json.Unmarshal failed: %w", err) - } - - return resp, nil -} - -type qiniuUploadCertReq struct { - Name string `json:"name"` - CommonName string `json:"common_name"` - Pri string `json:"pri"` - Ca string `json:"ca"` -} - -type qiniuUploadCertResp struct { - CertID string `json:"certID"` -} - -func (d *QiniuCDNDeployer) uploadCert() (string, error) { - path := "/sslcert" - - body := &qiniuUploadCertReq{ - Name: getDeployString(d.option.DeployConfig, "domain"), - CommonName: getDeployString(d.option.DeployConfig, "domain"), - Pri: d.option.Certificate.PrivateKey, - Ca: d.option.Certificate.Certificate, - } - - bodyBytes, err := json.Marshal(body) - if err != nil { - return "", fmt.Errorf("json.Marshal failed: %w", err) - } - - res, err := d.req(qiniuGateway+path, http.MethodPost, bytes.NewReader(bodyBytes)) - if err != nil { - return "", fmt.Errorf("req failed: %w", err) - } - resp := &qiniuUploadCertResp{} - err = json.Unmarshal(res, resp) - if err != nil { - return "", fmt.Errorf("json.Unmarshal failed: %w", err) - } - - return resp.CertID, nil -} - -type qiniuModifyDomainCertReq struct { - CertID string `json:"certId"` - ForceHttps bool `json:"forceHttps"` - Http2Enable bool `json:"http2Enable"` -} - -func (d *QiniuCDNDeployer) modifyDomainCert(certId string, forceHttps, http2Enable bool) error { - domain := d.option.DeployConfig.GetDomain() - path := fmt.Sprintf("/domain/%s/httpsconf", domain) - - body := &qiniuModifyDomainCertReq{ - CertID: certId, - ForceHttps: forceHttps, - Http2Enable: http2Enable, - } - - bodyBytes, err := json.Marshal(body) - if err != nil { - return fmt.Errorf("json.Marshal failed: %w", err) - } - - _, err = d.req(qiniuGateway+path, http.MethodPut, bytes.NewReader(bodyBytes)) - if err != nil { - return fmt.Errorf("req failed: %w", err) - } - - return nil -} - -func (d *QiniuCDNDeployer) req(url, method string, body io.Reader) ([]byte, error) { - req := xhttp.BuildReq(url, method, body, map[string]string{ - "Content-Type": "application/json", - }) - - if err := d.credentials.AddToken(auth.TokenQBox, req); err != nil { - return nil, fmt.Errorf("credentials.AddToken failed: %w", err) - } - - respBody, err := xhttp.ToRequest(req) - if err != nil { - return nil, fmt.Errorf("ToRequest failed: %w", err) - } - - defer respBody.Close() - - res, err := io.ReadAll(respBody) - if err != nil { - return nil, fmt.Errorf("io.ReadAll failed: %w", err) - } - - return res, nil +func (u *QiniuCDNDeployer) createSdkClient(accessKey, secretKey string) (*qiniuEx.Client, error) { + credential := auth.New(accessKey, secretKey) + client := qiniuEx.NewClient(credential) + return client, nil } diff --git a/internal/deployer/qiniu_cdn_test.go b/internal/deployer/qiniu_cdn_test.go deleted file mode 100644 index 67012bfc..00000000 --- a/internal/deployer/qiniu_cdn_test.go +++ /dev/null @@ -1,85 +0,0 @@ -package deployer - -import ( - "testing" - - "github.com/qiniu/go-sdk/v7/auth" - - "github.com/usual2970/certimate/internal/applicant" -) - -func Test_qiuniu_uploadCert(t *testing.T) { - type fields struct { - option *DeployerOption - } - tests := []struct { - name string - fields fields - want string - wantErr bool - }{ - { - name: "test", - fields: fields{ - option: &DeployerOption{ - DomainId: "1", - Domain: "example.com", - Access: `{"bucket":"test","accessKey":"","secretKey":""}`, - Certificate: applicant.Certificate{ - Certificate: "", - PrivateKey: "", - }, - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - q, _ := NewQiniuCDNDeployer(tt.fields.option) - got, err := q.uploadCert() - if (err != nil) != tt.wantErr { - t.Errorf("qiuniu.uploadCert() error = %v, wantErr %v", err, tt.wantErr) - return - } - if got != tt.want { - t.Errorf("qiuniu.uploadCert() = %v, want %v", got, tt.want) - } - }) - } -} - -func Test_qiuniu_modifyDomainCert(t *testing.T) { - type fields struct { - option *DeployerOption - info []string - credentials *auth.Credentials - } - type args struct { - certId string - } - tests := []struct { - name string - fields fields - args args - wantErr bool - }{ - { - name: "test", - fields: fields{ - option: &DeployerOption{ - DomainId: "1", - Domain: "jt1.ikit.fun", - Access: `{"bucket":"test","accessKey":"","secretKey":""}`, - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - q, _ := NewQiniuCDNDeployer(tt.fields.option) - if err := q.modifyDomainCert(tt.args.certId, true, true); (err != nil) != tt.wantErr { - t.Errorf("qiuniu.modifyDomainCert() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} diff --git a/internal/pkg/core/uploader/uploader_qiniu_sslcert.go b/internal/pkg/core/uploader/uploader_qiniu_sslcert.go new file mode 100644 index 00000000..edf72ac2 --- /dev/null +++ b/internal/pkg/core/uploader/uploader_qiniu_sslcert.go @@ -0,0 +1,69 @@ +package uploader + +import ( + "context" + "fmt" + "time" + + xerrors "github.com/pkg/errors" + "github.com/qiniu/go-sdk/v7/auth" + + "github.com/usual2970/certimate/internal/pkg/utils/x509" + qiniuEx "github.com/usual2970/certimate/internal/pkg/vendors/qiniu-sdk" +) + +type QiniuSSLCertUploaderConfig struct { + AccessKey string `json:"accessKey"` + SecretKey string `json:"secretKey"` +} + +type QiniuSSLCertUploader struct { + config *QiniuSSLCertUploaderConfig + sdkClient *qiniuEx.Client +} + +func NewQiniuSSLCertUploader(config *QiniuSSLCertUploaderConfig) (Uploader, error) { + client, err := (&QiniuSSLCertUploader{}).createSdkClient( + config.AccessKey, + config.SecretKey, + ) + if err != nil { + return nil, xerrors.Wrap(err, "failed to create sdk client") + } + + return &QiniuSSLCertUploader{ + config: config, + sdkClient: client, + }, nil +} + +func (u *QiniuSSLCertUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *UploadResult, err error) { + // 解析证书内容 + certX509, err := x509.ParseCertificateFromPEM(certPem) + if err != nil { + return nil, err + } + + // 生成新证书名(需符合七牛云命名规则) + var certId, certName string + certName = fmt.Sprintf("certimate-%d", time.Now().UnixMilli()) + + // 上传新证书 + // REF: https://developer.qiniu.com/fusion/8593/interface-related-certificate + uploadSslCertResp, err := u.sdkClient.UploadSslCert(certName, certX509.Subject.CommonName, privkeyPem, certPem) + if err != nil { + return nil, xerrors.Wrap(err, "failed to execute sdk request 'cdn.UploadSslCert'") + } + + certId = uploadSslCertResp.CertID + return &UploadResult{ + CertId: certId, + CertName: certName, + }, nil +} + +func (u *QiniuSSLCertUploader) createSdkClient(accessKey, secretKey string) (*qiniuEx.Client, error) { + credential := auth.New(accessKey, secretKey) + client := qiniuEx.NewClient(credential) + return client, nil +} diff --git a/internal/pkg/vendors/qiniu-sdk/client.go b/internal/pkg/vendors/qiniu-sdk/client.go new file mode 100644 index 00000000..eceff741 --- /dev/null +++ b/internal/pkg/vendors/qiniu-sdk/client.go @@ -0,0 +1,160 @@ +package qiniusdk + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + + "github.com/qiniu/go-sdk/v7/auth" + + xhttp "github.com/usual2970/certimate/internal/utils/http" +) + +const qiniuHost = "http://api.qiniu.com" + +type Client struct { + mac *auth.Credentials +} + +func NewClient(mac *auth.Credentials) *Client { + if mac == nil { + mac = auth.Default() + } + return &Client{mac: mac} +} + +func (c *Client) GetDomainInfo(domain string) (*GetDomainInfoResponse, error) { + respBytes, err := c.sendReq(http.MethodGet, fmt.Sprintf("domain/%s", domain), nil) + if err != nil { + return nil, err + } + + resp := &GetDomainInfoResponse{} + err = json.Unmarshal(respBytes, resp) + if err != nil { + return nil, err + } + if resp.Code != nil && *resp.Code != 0 && *resp.Code != 200 { + return nil, fmt.Errorf("code: %d, error: %s", *resp.Code, *resp.Error) + } + + return resp, nil +} + +func (c *Client) ModifyDomainHttpsConf(domain, certId string, forceHttps, http2Enable bool) (*ModifyDomainHttpsConfResponse, error) { + req := &ModifyDomainHttpsConfRequest{ + DomainInfoHttpsData: DomainInfoHttpsData{ + CertID: certId, + ForceHttps: forceHttps, + Http2Enable: http2Enable, + }, + } + + reqBytes, err := json.Marshal(req) + if err != nil { + return nil, err + } + + respBytes, err := c.sendReq(http.MethodPut, fmt.Sprintf("domain/%s/httpsconf", domain), bytes.NewReader(reqBytes)) + if err != nil { + return nil, err + } + + resp := &ModifyDomainHttpsConfResponse{} + err = json.Unmarshal(respBytes, resp) + if err != nil { + return nil, err + } + if resp.Code != nil && *resp.Code != 0 && *resp.Code != 200 { + return nil, fmt.Errorf("code: %d, error: %s", *resp.Code, *resp.Error) + } + + return resp, nil +} + +func (c *Client) EnableDomainHttps(domain, certId string, forceHttps, http2Enable bool) (*EnableDomainHttpsResponse, error) { + req := &EnableDomainHttpsRequest{ + DomainInfoHttpsData: DomainInfoHttpsData{ + CertID: certId, + ForceHttps: forceHttps, + Http2Enable: http2Enable, + }, + } + + reqBytes, err := json.Marshal(req) + if err != nil { + return nil, err + } + + respBytes, err := c.sendReq(http.MethodPut, fmt.Sprintf("domain/%s/sslize", domain), bytes.NewReader(reqBytes)) + if err != nil { + return nil, err + } + + resp := &EnableDomainHttpsResponse{} + err = json.Unmarshal(respBytes, resp) + if err != nil { + return nil, err + } + if resp.Code != nil && *resp.Code != 0 && *resp.Code != 200 { + return nil, fmt.Errorf("code: %d, error: %s", *resp.Code, *resp.Error) + } + + return resp, nil +} + +func (c *Client) UploadSslCert(name, commonName, pri, ca string) (*UploadSslCertResponse, error) { + req := &UploadSslCertRequest{ + Name: name, + CommonName: commonName, + Pri: pri, + Ca: ca, + } + + reqBytes, err := json.Marshal(req) + if err != nil { + return nil, err + } + + respBytes, err := c.sendReq(http.MethodPost, "sslcert", bytes.NewReader(reqBytes)) + if err != nil { + return nil, err + } + + resp := &UploadSslCertResponse{} + err = json.Unmarshal(respBytes, resp) + if err != nil { + return nil, err + } + if resp.Code != nil && *resp.Code != 0 && *resp.Code != 200 { + return nil, fmt.Errorf("code: %d, error: %s", *resp.Code, *resp.Error) + } + + return resp, nil +} + +func (c *Client) sendReq(method string, path string, body io.Reader) ([]byte, error) { + req := xhttp.BuildReq(fmt.Sprintf("%s/%s", qiniuHost, path), method, body, map[string]string{ + "Content-Type": "application/json", + }) + + if err := c.mac.AddToken(auth.TokenQBox, req); err != nil { + return nil, err + } + + respBody, err := xhttp.ToRequest(req) + if err != nil { + return nil, err + } + + defer respBody.Close() + + res, err := io.ReadAll(respBody) + if err != nil { + return nil, err + } + + return res, nil +} diff --git a/internal/pkg/vendors/qiniu-sdk/models.go b/internal/pkg/vendors/qiniu-sdk/models.go new file mode 100644 index 00000000..433909e1 --- /dev/null +++ b/internal/pkg/vendors/qiniu-sdk/models.go @@ -0,0 +1,53 @@ +package qiniusdk + +type UploadSslCertRequest struct { + Name string `json:"name"` + CommonName string `json:"common_name"` + Pri string `json:"pri"` + Ca string `json:"ca"` +} + +type UploadSslCertResponse struct { + Code *int `json:"code,omitempty"` + Error *string `json:"error,omitempty"` + CertID string `json:"certID"` +} + +type DomainInfoHttpsData struct { + CertID string `json:"certId"` + ForceHttps bool `json:"forceHttps"` + Http2Enable bool `json:"http2Enable"` +} + +type GetDomainInfoResponse struct { + Code *int `json:"code,omitempty"` + Error *string `json:"error,omitempty"` + Name string `json:"name"` + Type string `json:"type"` + CName string `json:"cname"` + Https *DomainInfoHttpsData `json:"https"` + PareDomain string `json:"pareDomain"` + OperationType string `json:"operationType"` + OperatingState string `json:"operatingState"` + OperatingStateDesc string `json:"operatingStateDesc"` + CreateAt string `json:"createAt"` + ModifyAt string `json:"modifyAt"` +} + +type ModifyDomainHttpsConfRequest struct { + DomainInfoHttpsData +} + +type ModifyDomainHttpsConfResponse struct { + Code *int `json:"code,omitempty"` + Error *string `json:"error,omitempty"` +} + +type EnableDomainHttpsRequest struct { + DomainInfoHttpsData +} + +type EnableDomainHttpsResponse struct { + Code *int `json:"code,omitempty"` + Error *string `json:"error,omitempty"` +} From 83264a69462f94b530d5c6e7a884f6cdd193ebaa Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Thu, 31 Oct 2024 11:37:16 +0800 Subject: [PATCH 06/18] refactor: clean code --- internal/deployer/aliyun_alb.go | 2 +- internal/deployer/aliyun_cdn.go | 2 +- internal/deployer/aliyun_clb.go | 2 +- internal/deployer/aliyun_dcdn.go | 2 +- internal/deployer/aliyun_nlb.go | 2 +- internal/deployer/aliyun_oss.go | 2 +- internal/deployer/deployer.go | 15 +-------------- internal/deployer/huaweicloud_cdn.go | 6 +++--- internal/deployer/huaweicloud_elb.go | 18 +++++++++--------- internal/deployer/k8s_secret.go | 2 +- internal/deployer/local.go | 2 +- internal/deployer/qiniu_cdn.go | 2 +- internal/deployer/ssh.go | 2 +- internal/deployer/tencent_cdn.go | 2 +- internal/deployer/tencent_clb.go | 2 +- internal/deployer/tencent_cos.go | 2 +- internal/deployer/tencent_ecdn.go | 2 +- internal/deployer/tencent_teo.go | 2 +- internal/deployer/webhook.go | 2 +- internal/domains/deploy.go | 4 ++-- .../core/uploader/uploader_tencentcloud_ssl.go | 7 ------- 21 files changed, 31 insertions(+), 51 deletions(-) diff --git a/internal/deployer/aliyun_alb.go b/internal/deployer/aliyun_alb.go index 91f6f0c7..cd6bddb9 100644 --- a/internal/deployer/aliyun_alb.go +++ b/internal/deployer/aliyun_alb.go @@ -59,7 +59,7 @@ func (d *AliyunALBDeployer) GetID() string { return fmt.Sprintf("%s-%s", d.option.AccessRecord.GetString("name"), d.option.AccessRecord.Id) } -func (d *AliyunALBDeployer) GetInfo() []string { +func (d *AliyunALBDeployer) GetInfos() []string { return d.infos } diff --git a/internal/deployer/aliyun_cdn.go b/internal/deployer/aliyun_cdn.go index 29e9bf15..71a96d6d 100644 --- a/internal/deployer/aliyun_cdn.go +++ b/internal/deployer/aliyun_cdn.go @@ -46,7 +46,7 @@ func (d *AliyunCDNDeployer) GetID() string { return fmt.Sprintf("%s-%s", d.option.AccessRecord.GetString("name"), d.option.AccessRecord.Id) } -func (d *AliyunCDNDeployer) GetInfo() []string { +func (d *AliyunCDNDeployer) GetInfos() []string { return d.infos } diff --git a/internal/deployer/aliyun_clb.go b/internal/deployer/aliyun_clb.go index 8af40687..3344b501 100644 --- a/internal/deployer/aliyun_clb.go +++ b/internal/deployer/aliyun_clb.go @@ -59,7 +59,7 @@ func (d *AliyunCLBDeployer) GetID() string { return fmt.Sprintf("%s-%s", d.option.AccessRecord.GetString("name"), d.option.AccessRecord.Id) } -func (d *AliyunCLBDeployer) GetInfo() []string { +func (d *AliyunCLBDeployer) GetInfos() []string { return d.infos } diff --git a/internal/deployer/aliyun_dcdn.go b/internal/deployer/aliyun_dcdn.go index 37641016..75b03cbc 100644 --- a/internal/deployer/aliyun_dcdn.go +++ b/internal/deployer/aliyun_dcdn.go @@ -47,7 +47,7 @@ func (d *AliyunDCDNDeployer) GetID() string { return fmt.Sprintf("%s-%s", d.option.AccessRecord.GetString("name"), d.option.AccessRecord.Id) } -func (d *AliyunDCDNDeployer) GetInfo() []string { +func (d *AliyunDCDNDeployer) GetInfos() []string { return d.infos } diff --git a/internal/deployer/aliyun_nlb.go b/internal/deployer/aliyun_nlb.go index 36034036..1e771744 100644 --- a/internal/deployer/aliyun_nlb.go +++ b/internal/deployer/aliyun_nlb.go @@ -59,7 +59,7 @@ func (d *AliyunNLBDeployer) GetID() string { return fmt.Sprintf("%s-%s", d.option.AccessRecord.GetString("name"), d.option.AccessRecord.Id) } -func (d *AliyunNLBDeployer) GetInfo() []string { +func (d *AliyunNLBDeployer) GetInfos() []string { return d.infos } diff --git a/internal/deployer/aliyun_oss.go b/internal/deployer/aliyun_oss.go index f0ee5f56..d0045d89 100644 --- a/internal/deployer/aliyun_oss.go +++ b/internal/deployer/aliyun_oss.go @@ -45,7 +45,7 @@ func (d *AliyunOSSDeployer) GetID() string { return fmt.Sprintf("%s-%s", d.option.AccessRecord.GetString("name"), d.option.AccessRecord.Id) } -func (d *AliyunOSSDeployer) GetInfo() []string { +func (d *AliyunOSSDeployer) GetInfos() []string { return d.infos } diff --git a/internal/deployer/deployer.go b/internal/deployer/deployer.go index 57ae4568..7be7b8ed 100644 --- a/internal/deployer/deployer.go +++ b/internal/deployer/deployer.go @@ -52,7 +52,7 @@ type DeployerOption struct { type Deployer interface { Deploy(ctx context.Context) error - GetInfo() []string + GetInfos() []string GetID() string } @@ -156,19 +156,6 @@ func toStr(tag string, data any) string { return tag + ":" + string(byts) } -func getDeployString(conf domain.DeployConfig, key string) string { - if _, ok := conf.Config[key]; !ok { - return "" - } - - val, ok := conf.Config[key].(string) - if !ok { - return "" - } - - return val -} - func getDeployVariables(conf domain.DeployConfig) map[string]string { rs := make(map[string]string) data, ok := conf.Config["variables"] diff --git a/internal/deployer/huaweicloud_cdn.go b/internal/deployer/huaweicloud_cdn.go index dfbe131e..ff7b4328 100644 --- a/internal/deployer/huaweicloud_cdn.go +++ b/internal/deployer/huaweicloud_cdn.go @@ -62,7 +62,7 @@ func (d *HuaweiCloudCDNDeployer) GetID() string { return fmt.Sprintf("%s-%s", d.option.AccessRecord.GetString("name"), d.option.AccessRecord.Id) } -func (d *HuaweiCloudCDNDeployer) GetInfo() []string { +func (d *HuaweiCloudCDNDeployer) GetInfos() []string { return d.infos } @@ -74,7 +74,7 @@ func (d *HuaweiCloudCDNDeployer) Deploy(ctx context.Context) error { } showDomainFullConfigResp, err := d.sdkClient.ShowDomainFullConfig(showDomainFullConfigReq) if err != nil { - return err + return xerrors.Wrap(err, "failed to execute sdk request 'cdn.ShowDomainFullConfig'") } d.infos = append(d.infos, toStr("已查询到加速域名配置", showDomainFullConfigResp)) @@ -111,7 +111,7 @@ func (d *HuaweiCloudCDNDeployer) Deploy(ctx context.Context) error { } updateDomainMultiCertificatesResp, err := d.sdkClient.UploadDomainMultiCertificatesEx(updateDomainMultiCertificatesReq) if err != nil { - return err + return xerrors.Wrap(err, "failed to execute sdk request 'cdn.UploadDomainMultiCertificatesEx'") } d.infos = append(d.infos, toStr("已更新加速域名配置", updateDomainMultiCertificatesResp)) diff --git a/internal/deployer/huaweicloud_elb.go b/internal/deployer/huaweicloud_elb.go index 9bf9f40e..05b94956 100644 --- a/internal/deployer/huaweicloud_elb.go +++ b/internal/deployer/huaweicloud_elb.go @@ -67,7 +67,7 @@ func (d *HuaweiCloudELBDeployer) GetID() string { return fmt.Sprintf("%s-%s", d.option.AccessRecord.GetString("name"), d.option.AccessRecord.Id) } -func (d *HuaweiCloudELBDeployer) GetInfo() []string { +func (d *HuaweiCloudELBDeployer) GetInfos() []string { return d.infos } @@ -173,7 +173,7 @@ func (u *HuaweiCloudELBDeployer) getSdkProjectId(accessKeyId, secretAccessKey, r if err != nil { return "", err } else if response.Projects == nil || len(*response.Projects) == 0 { - return "", fmt.Errorf("no project found") + return "", errors.New("no project found") } return (*response.Projects)[0].Id, nil @@ -198,7 +198,7 @@ func (d *HuaweiCloudELBDeployer) deployToCertificate(ctx context.Context) error } updateCertificateResp, err := d.sdkClient.UpdateCertificate(updateCertificateReq) if err != nil { - return fmt.Errorf("failed to execute sdk request 'elb.UpdateCertificate': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'elb.UpdateCertificate'") } d.infos = append(d.infos, toStr("已更新 ELB 证书", updateCertificateResp)) @@ -221,7 +221,7 @@ func (d *HuaweiCloudELBDeployer) deployToLoadbalancer(ctx context.Context) error } showLoadBalancerResp, err := d.sdkClient.ShowLoadBalancer(showLoadBalancerReq) if err != nil { - return fmt.Errorf("failed to execute sdk request 'elb.ShowLoadBalancer': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'elb.ShowLoadBalancer'") } d.infos = append(d.infos, toStr("已查询到 ELB 负载均衡器", showLoadBalancerResp)) @@ -239,7 +239,7 @@ func (d *HuaweiCloudELBDeployer) deployToLoadbalancer(ctx context.Context) error } listListenersResp, err := d.sdkClient.ListListeners(listListenersReq) if err != nil { - return fmt.Errorf("failed to execute sdk request 'elb.ListListeners': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'elb.ListListeners'") } if listListenersResp.Listeners != nil { @@ -309,7 +309,7 @@ func (d *HuaweiCloudELBDeployer) updateListenerCertificate(ctx context.Context, } showListenerResp, err := d.sdkClient.ShowListener(showListenerReq) if err != nil { - return fmt.Errorf("failed to execute sdk request 'elb.ShowListener': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'elb.ShowListener'") } d.infos = append(d.infos, toStr("已查询到 ELB 监听器", showListenerResp)) @@ -335,7 +335,7 @@ func (d *HuaweiCloudELBDeployer) updateListenerCertificate(ctx context.Context, } listOldCertificateResp, err := d.sdkClient.ListCertificates(listOldCertificateReq) if err != nil { - return fmt.Errorf("failed to execute sdk request 'elb.ListCertificates': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'elb.ListCertificates'") } showNewCertificateReq := &hcElbModel.ShowCertificateRequest{ @@ -343,7 +343,7 @@ func (d *HuaweiCloudELBDeployer) updateListenerCertificate(ctx context.Context, } showNewCertificateResp, err := d.sdkClient.ShowCertificate(showNewCertificateReq) if err != nil { - return fmt.Errorf("failed to execute sdk request 'elb.ShowCertificate': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'elb.ShowCertificate'") } for _, certificate := range *listOldCertificateResp.Certificates { @@ -376,7 +376,7 @@ func (d *HuaweiCloudELBDeployer) updateListenerCertificate(ctx context.Context, } updateListenerResp, err := d.sdkClient.UpdateListener(updateListenerReq) if err != nil { - return fmt.Errorf("failed to execute sdk request 'elb.UpdateListener': %w", err) + return xerrors.Wrap(err, "failed to execute sdk request 'elb.UpdateListener'") } d.infos = append(d.infos, toStr("已更新 ELB 监听器", updateListenerResp)) diff --git a/internal/deployer/k8s_secret.go b/internal/deployer/k8s_secret.go index 0b5945b9..8a1c30ff 100644 --- a/internal/deployer/k8s_secret.go +++ b/internal/deployer/k8s_secret.go @@ -47,7 +47,7 @@ func (d *K8sSecretDeployer) GetID() string { return fmt.Sprintf("%s-%s", d.option.AccessRecord.GetString("name"), d.option.AccessRecord.Id) } -func (d *K8sSecretDeployer) GetInfo() []string { +func (d *K8sSecretDeployer) GetInfos() []string { return d.infos } diff --git a/internal/deployer/local.go b/internal/deployer/local.go index ccda2306..eedec98b 100644 --- a/internal/deployer/local.go +++ b/internal/deployer/local.go @@ -41,7 +41,7 @@ func (d *LocalDeployer) GetID() string { return fmt.Sprintf("%s-%s", d.option.AccessRecord.GetString("name"), d.option.AccessRecord.Id) } -func (d *LocalDeployer) GetInfo() []string { +func (d *LocalDeployer) GetInfos() []string { return []string{} } diff --git a/internal/deployer/qiniu_cdn.go b/internal/deployer/qiniu_cdn.go index 73e82ae0..d782a3e0 100644 --- a/internal/deployer/qiniu_cdn.go +++ b/internal/deployer/qiniu_cdn.go @@ -55,7 +55,7 @@ func (d *QiniuCDNDeployer) GetID() string { return fmt.Sprintf("%s-%s", d.option.AccessRecord.GetString("name"), d.option.AccessRecord.Id) } -func (d *QiniuCDNDeployer) GetInfo() []string { +func (d *QiniuCDNDeployer) GetInfos() []string { return d.infos } diff --git a/internal/deployer/ssh.go b/internal/deployer/ssh.go index a94c9782..a50fcab6 100644 --- a/internal/deployer/ssh.go +++ b/internal/deployer/ssh.go @@ -32,7 +32,7 @@ func (d *SSHDeployer) GetID() string { return fmt.Sprintf("%s-%s", d.option.AccessRecord.GetString("name"), d.option.AccessRecord.Id) } -func (d *SSHDeployer) GetInfo() []string { +func (d *SSHDeployer) GetInfos() []string { return d.infos } diff --git a/internal/deployer/tencent_cdn.go b/internal/deployer/tencent_cdn.go index d89cb819..ba03dc73 100644 --- a/internal/deployer/tencent_cdn.go +++ b/internal/deployer/tencent_cdn.go @@ -64,7 +64,7 @@ func (d *TencentCDNDeployer) GetID() string { return fmt.Sprintf("%s-%s", d.option.AccessRecord.GetString("name"), d.option.AccessRecord.Id) } -func (d *TencentCDNDeployer) GetInfo() []string { +func (d *TencentCDNDeployer) GetInfos() []string { return d.infos } diff --git a/internal/deployer/tencent_clb.go b/internal/deployer/tencent_clb.go index 45ccb993..e773a346 100644 --- a/internal/deployer/tencent_clb.go +++ b/internal/deployer/tencent_clb.go @@ -62,7 +62,7 @@ func (d *TencentCLBDeployer) GetID() string { return fmt.Sprintf("%s-%s", d.option.AccessRecord.GetString("name"), d.option.AccessRecord.Id) } -func (d *TencentCLBDeployer) GetInfo() []string { +func (d *TencentCLBDeployer) GetInfos() []string { return d.infos } diff --git a/internal/deployer/tencent_cos.go b/internal/deployer/tencent_cos.go index 749f5249..dfd1d850 100644 --- a/internal/deployer/tencent_cos.go +++ b/internal/deployer/tencent_cos.go @@ -57,7 +57,7 @@ func (d *TencentCOSDeployer) GetID() string { return fmt.Sprintf("%s-%s", d.option.AccessRecord.GetString("name"), d.option.AccessRecord.Id) } -func (d *TencentCOSDeployer) GetInfo() []string { +func (d *TencentCOSDeployer) GetInfos() []string { return d.infos } diff --git a/internal/deployer/tencent_ecdn.go b/internal/deployer/tencent_ecdn.go index 0458c74d..6d526a3d 100644 --- a/internal/deployer/tencent_ecdn.go +++ b/internal/deployer/tencent_ecdn.go @@ -63,7 +63,7 @@ func (d *TencentECDNDeployer) GetID() string { return fmt.Sprintf("%s-%s", d.option.AccessRecord.GetString("name"), d.option.AccessRecord.Id) } -func (d *TencentECDNDeployer) GetInfo() []string { +func (d *TencentECDNDeployer) GetInfos() []string { return d.infos } diff --git a/internal/deployer/tencent_teo.go b/internal/deployer/tencent_teo.go index 83eca55e..d9d8e433 100644 --- a/internal/deployer/tencent_teo.go +++ b/internal/deployer/tencent_teo.go @@ -63,7 +63,7 @@ func (d *TencentTEODeployer) GetID() string { return fmt.Sprintf("%s-%s", d.option.AccessRecord.GetString("name"), d.option.AccessRecord.Id) } -func (d *TencentTEODeployer) GetInfo() []string { +func (d *TencentTEODeployer) GetInfos() []string { return d.infos } diff --git a/internal/deployer/webhook.go b/internal/deployer/webhook.go index bc227f0d..33b73f43 100644 --- a/internal/deployer/webhook.go +++ b/internal/deployer/webhook.go @@ -29,7 +29,7 @@ func (d *WebhookDeployer) GetID() string { return fmt.Sprintf("%s-%s", d.option.AccessRecord.GetString("name"), d.option.AccessRecord.Id) } -func (d *WebhookDeployer) GetInfo() []string { +func (d *WebhookDeployer) GetInfos() []string { return d.infos } diff --git a/internal/domains/deploy.go b/internal/domains/deploy.go index 23b3a1dd..c9df14d3 100644 --- a/internal/domains/deploy.go +++ b/internal/domains/deploy.go @@ -105,11 +105,11 @@ func deploy(ctx context.Context, record *models.Record) error { if err = deployer.Deploy(ctx); err != nil { app.GetApp().Logger().Error("部署失败", "err", err) - history.record(deployPhase, "部署失败", &RecordInfo{Err: err, Info: deployer.GetInfo()}) + history.record(deployPhase, "部署失败", &RecordInfo{Err: err, Info: deployer.GetInfos()}) return err } history.record(deployPhase, fmt.Sprintf("[%s]-部署成功", deployer.GetID()), &RecordInfo{ - Info: deployer.GetInfo(), + Info: deployer.GetInfos(), }, false) } diff --git a/internal/pkg/core/uploader/uploader_tencentcloud_ssl.go b/internal/pkg/core/uploader/uploader_tencentcloud_ssl.go index 28837371..553e411c 100644 --- a/internal/pkg/core/uploader/uploader_tencentcloud_ssl.go +++ b/internal/pkg/core/uploader/uploader_tencentcloud_ssl.go @@ -37,13 +37,6 @@ func NewTencentCloudSSLUploader(config *TencentCloudSSLUploaderConfig) (Uploader } func (u *TencentCloudSSLUploader) Upload(ctx context.Context, certPem string, privkeyPem string) (res *UploadResult, err error) { - defer func() { - if r := recover(); r != nil { - fmt.Printf("Recovered from panic: %+v", r) - fmt.Println() - } - }() - // 生成新证书名(需符合腾讯云命名规则) var certId, certName string certName = fmt.Sprintf("certimate-%d", time.Now().UnixMilli()) From 369c146ecad2182f2371498c0455509a8768e320 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Thu, 31 Oct 2024 13:24:43 +0800 Subject: [PATCH 07/18] 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", From f71a5196749e15b8568e30e8b5e30bb698730118 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Thu, 31 Oct 2024 13:41:21 +0800 Subject: [PATCH 08/18] refactor: clean code --- .../certimate/DeployToAliyunALB.tsx | 24 +-- .../certimate/DeployToAliyunCDN.tsx | 50 ++---- .../certimate/DeployToAliyunCLB.tsx | 24 +-- .../certimate/DeployToAliyunNLB.tsx | 24 +-- .../certimate/DeployToAliyunOSS.tsx | 106 ++++--------- .../certimate/DeployToHuaweiCloudCDN.tsx | 37 +++-- .../certimate/DeployToHuaweiCloudELB.tsx | 31 ++-- .../certimate/DeployToKubernetesSecret.tsx | 37 ++++- ui/src/components/certimate/DeployToLocal.tsx | 42 ++--- .../components/certimate/DeployToQiniuCDN.tsx | 50 ++---- ui/src/components/certimate/DeployToSSH.tsx | 39 ++--- .../certimate/DeployToTencentCDN.tsx | 59 +++---- .../certimate/DeployToTencentCOS.tsx | 144 ++++-------------- .../certimate/DeployToTencentTEO.tsx | 99 ++++-------- .../components/certimate/DeployToWebhook.tsx | 15 +- ui/src/i18n/locales/en/nls.common.json | 1 - ui/src/i18n/locales/en/nls.domain.json | 2 + ui/src/i18n/locales/zh/nls.common.json | 1 - ui/src/i18n/locales/zh/nls.domain.json | 2 + 19 files changed, 253 insertions(+), 534 deletions(-) diff --git a/ui/src/components/certimate/DeployToAliyunALB.tsx b/ui/src/components/certimate/DeployToAliyunALB.tsx index cf7feba9..94172fd4 100644 --- a/ui/src/components/certimate/DeployToAliyunALB.tsx +++ b/ui/src/components/certimate/DeployToAliyunALB.tsx @@ -51,23 +51,13 @@ const DeployToAliyunALB = () => { useEffect(() => { const res = formSchema.safeParse(data.config); - if (!res.success) { - 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, - }); - } else { - setError({ - ...error, - region: undefined, - resourceType: undefined, - loadbalancerId: undefined, - listenerId: undefined, - }); - } + 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, + }); }, [data]); return ( diff --git a/ui/src/components/certimate/DeployToAliyunCDN.tsx b/ui/src/components/certimate/DeployToAliyunCDN.tsx index 074f27a0..32eb5a41 100644 --- a/ui/src/components/certimate/DeployToAliyunCDN.tsx +++ b/ui/src/components/certimate/DeployToAliyunCDN.tsx @@ -27,25 +27,20 @@ const DeployToAliyunCDN = () => { 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]); - - const domainSchema = z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, { - message: t("common.errmsg.domain_invalid"), + const formSchema = z.object({ + domain: z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, { + message: t("common.errmsg.domain_invalid"), + }), }); + useEffect(() => { + const res = formSchema.safeParse(data.config); + setError({ + ...error, + domain: res.error?.errors?.find((e) => e.path[0] === "domain")?.message, + }); + }, [data]); + return (
@@ -55,26 +50,9 @@ const DeployToAliyunCDN = () => { className="w-full mt-1" value={data?.config?.domain} onChange={(e) => { - const temp = e.target.value; - - const resp = domainSchema.safeParse(temp); - if (!resp.success) { - setError({ - ...error, - domain: JSON.parse(resp.error.message)[0].message, - }); - } else { - setError({ - ...error, - domain: "", - }); - } - const newData = produce(data, (draft) => { - if (!draft.config) { - draft.config = {}; - } - draft.config.domain = temp; + draft.config ??= {}; + draft.config.domain = e.target.value?.trim(); }); setDeploy(newData); }} diff --git a/ui/src/components/certimate/DeployToAliyunCLB.tsx b/ui/src/components/certimate/DeployToAliyunCLB.tsx index eb41c0ac..d90574b3 100644 --- a/ui/src/components/certimate/DeployToAliyunCLB.tsx +++ b/ui/src/components/certimate/DeployToAliyunCLB.tsx @@ -51,23 +51,13 @@ const DeployToAliyunCLB = () => { useEffect(() => { const res = formSchema.safeParse(data.config); - if (!res.success) { - 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, - listenerPort: res.error.errors.find((e) => e.path[0] === "listenerPort")?.message, - }); - } else { - setError({ - ...error, - region: undefined, - resourceType: undefined, - loadbalancerId: undefined, - listenerPort: undefined, - }); - } + 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, + listenerPort: res.error?.errors?.find((e) => e.path[0] === "listenerPort")?.message, + }); }, [data]); return ( diff --git a/ui/src/components/certimate/DeployToAliyunNLB.tsx b/ui/src/components/certimate/DeployToAliyunNLB.tsx index 38d6b1f7..0e4ea03e 100644 --- a/ui/src/components/certimate/DeployToAliyunNLB.tsx +++ b/ui/src/components/certimate/DeployToAliyunNLB.tsx @@ -51,23 +51,13 @@ const DeployToAliyunNLB = () => { useEffect(() => { const res = formSchema.safeParse(data.config); - if (!res.success) { - 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, - }); - } else { - setError({ - ...error, - region: undefined, - resourceType: undefined, - loadbalancerId: undefined, - listenerId: undefined, - }); - } + 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, + }); }, [data]); return ( diff --git a/ui/src/components/certimate/DeployToAliyunOSS.tsx b/ui/src/components/certimate/DeployToAliyunOSS.tsx index ccfcc870..7037175c 100644 --- a/ui/src/components/certimate/DeployToAliyunOSS.tsx +++ b/ui/src/components/certimate/DeployToAliyunOSS.tsx @@ -17,7 +17,7 @@ const DeployToAliyunOSS = () => { setDeploy({ ...data, config: { - endpoint: "oss-cn-hangzhou.aliyuncs.com", + endpoint: "oss.aliyuncs.com", bucket: "", domain: "", }, @@ -29,43 +29,27 @@ const DeployToAliyunOSS = () => { 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 resp = bucketSchema.safeParse(data.config?.bucket); - if (!resp.success) { - setError({ - ...error, - bucket: JSON.parse(resp.error.message)[0].message, - }); - } else { - setError({ - ...error, - bucket: "", - }); - } - }, [data]); - - const domainSchema = z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, { - message: t("common.errmsg.domain_invalid"), + const formSchema = z.object({ + endpoint: z.string().min(1, { + message: t("domain.deployment.form.aliyun_oss_endpoint.placeholder"), + }), + bucket: z.string().min(1, { + message: t("domain.deployment.form.aliyun_oss_bucket.placeholder"), + }), + domain: z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, { + message: t("common.errmsg.domain_invalid"), + }), }); - const bucketSchema = z.string().min(1, { - message: t("domain.deployment.form.aliyun_oss_bucket.placeholder"), - }); + useEffect(() => { + const res = formSchema.safeParse(data.config); + setError({ + ...error, + endpoint: res.error?.errors?.find((e) => e.path[0] === "endpoint")?.message, + bucket: res.error?.errors?.find((e) => e.path[0] === "bucket")?.message, + domain: res.error?.errors?.find((e) => e.path[0] === "domain")?.message, + }); + }, [data]); return (
@@ -76,13 +60,9 @@ const DeployToAliyunOSS = () => { className="w-full mt-1" value={data?.config?.endpoint} onChange={(e) => { - const temp = e.target.value; - const newData = produce(data, (draft) => { - if (!draft.config) { - draft.config = {}; - } - draft.config.endpoint = temp; + draft.config ??= {}; + draft.config.endpoint = e.target.value?.trim(); }); setDeploy(newData); }} @@ -97,26 +77,9 @@ const DeployToAliyunOSS = () => { className="w-full mt-1" value={data?.config?.bucket} onChange={(e) => { - const temp = e.target.value; - - const resp = bucketSchema.safeParse(temp); - if (!resp.success) { - setError({ - ...error, - bucket: JSON.parse(resp.error.message)[0].message, - }); - } else { - setError({ - ...error, - bucket: "", - }); - } - const newData = produce(data, (draft) => { - if (!draft.config) { - draft.config = {}; - } - draft.config.bucket = temp; + draft.config ??= {}; + draft.config.bucket = e.target.value?.trim(); }); setDeploy(newData); }} @@ -131,26 +94,9 @@ const DeployToAliyunOSS = () => { className="w-full mt-1" value={data?.config?.domain} onChange={(e) => { - const temp = e.target.value; - - const resp = domainSchema.safeParse(temp); - if (!resp.success) { - setError({ - ...error, - domain: JSON.parse(resp.error.message)[0].message, - }); - } else { - setError({ - ...error, - domain: "", - }); - } - const newData = produce(data, (draft) => { - if (!draft.config) { - draft.config = {}; - } - draft.config.domain = temp; + draft.config ??= {}; + draft.config.domain = e.target.value?.trim(); }); setDeploy(newData); }} diff --git a/ui/src/components/certimate/DeployToHuaweiCloudCDN.tsx b/ui/src/components/certimate/DeployToHuaweiCloudCDN.tsx index bdf968c4..10591530 100644 --- a/ui/src/components/certimate/DeployToHuaweiCloudCDN.tsx +++ b/ui/src/components/certimate/DeployToHuaweiCloudCDN.tsx @@ -28,31 +28,30 @@ const DeployToHuaweiCloudCDN = () => { 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]); - - 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, { + message: t("domain.deployment.form.huaweicloud_cdn_region.placeholder"), + }), + domain: z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, { + message: t("common.errmsg.domain_invalid"), + }), }); + useEffect(() => { + const res = formSchema.safeParse(data.config); + setError({ + ...error, + region: res.error?.errors?.find((e) => e.path[0] === "region")?.message, + domain: res.error?.errors?.find((e) => e.path[0] === "domain")?.message, + }); + }, [data]); + return (
- + { diff --git a/ui/src/components/certimate/DeployToHuaweiCloudELB.tsx b/ui/src/components/certimate/DeployToHuaweiCloudELB.tsx index e7a7fc4a..a3d44f3c 100644 --- a/ui/src/components/certimate/DeployToHuaweiCloudELB.tsx +++ b/ui/src/components/certimate/DeployToHuaweiCloudELB.tsx @@ -35,7 +35,9 @@ const DeployToHuaweiCloudCDN = () => { const formSchema = z .object({ region: z.string().min(1, t("domain.deployment.form.huaweicloud_elb_region.placeholder")), - resourceType: z.string().min(1, t("domain.deployment.form.huaweicloud_elb_resource_type.placeholder")), + resourceType: z.union([z.literal("certificate"), z.literal("loadbalancer"), z.literal("listener")], { + message: t("domain.deployment.form.huaweicloud_elb_resource_type.placeholder"), + }), certificateId: z.string().optional(), loadbalancerId: z.string().optional(), listenerId: z.string().optional(), @@ -55,25 +57,14 @@ const DeployToHuaweiCloudCDN = () => { useEffect(() => { const res = formSchema.safeParse(data.config); - if (!res.success) { - setError({ - ...error, - region: res.error.errors.find((e) => e.path[0] === "region")?.message, - resourceType: res.error.errors.find((e) => e.path[0] === "resourceType")?.message, - certificateId: res.error.errors.find((e) => e.path[0] === "certificateId")?.message, - loadbalancerId: res.error.errors.find((e) => e.path[0] === "loadbalancerId")?.message, - listenerId: res.error.errors.find((e) => e.path[0] === "listenerId")?.message, - }); - } else { - setError({ - ...error, - region: undefined, - resourceType: undefined, - certificateId: undefined, - loadbalancerId: undefined, - listenerId: undefined, - }); - } + setError({ + ...error, + region: res.error?.errors?.find((e) => e.path[0] === "region")?.message, + resourceType: res.error?.errors?.find((e) => e.path[0] === "resourceType")?.message, + certificateId: res.error?.errors?.find((e) => e.path[0] === "certificateId")?.message, + loadbalancerId: res.error?.errors?.find((e) => e.path[0] === "loadbalancerId")?.message, + listenerId: res.error?.errors?.find((e) => e.path[0] === "listenerId")?.message, + }); }, [data]); return ( diff --git a/ui/src/components/certimate/DeployToKubernetesSecret.tsx b/ui/src/components/certimate/DeployToKubernetesSecret.tsx index c7b8e2a8..90d6d84f 100644 --- a/ui/src/components/certimate/DeployToKubernetesSecret.tsx +++ b/ui/src/components/certimate/DeployToKubernetesSecret.tsx @@ -1,5 +1,6 @@ import { useEffect } from "react"; import { useTranslation } from "react-i18next"; +import { z } from "zod"; import { produce } from "immer"; import { Input } from "@/components/ui/input"; @@ -9,7 +10,7 @@ import { useDeployEditContext } from "./DeployEdit"; const DeployToKubernetesSecret = () => { const { t } = useTranslation(); - const { deploy: data, setDeploy, setError } = useDeployEditContext(); + const { deploy: data, setDeploy, error, setError } = useDeployEditContext(); useEffect(() => { if (!data.id) { @@ -29,6 +30,32 @@ const DeployToKubernetesSecret = () => { setError({}); }, []); + const formSchema = z.object({ + namespace: z.string().min(1, { + message: t("domain.deployment.form.k8s_namespace.placeholder"), + }), + secretName: z.string().min(1, { + message: t("domain.deployment.form.k8s_secret_name.placeholder"), + }), + secretDataKeyForCrt: z.string().min(1, { + message: t("domain.deployment.form.k8s_secret_data_key_for_crt.placeholder"), + }), + secretDataKeyForKey: z.string().min(1, { + message: t("domain.deployment.form.k8s_secret_data_key_for_key.placeholder"), + }), + }); + + useEffect(() => { + const res = formSchema.safeParse(data.config); + setError({ + ...error, + namespace: res.error?.errors?.find((e) => e.path[0] === "namespace")?.message, + secretName: res.error?.errors?.find((e) => e.path[0] === "secretName")?.message, + secretDataKeyForCrt: res.error?.errors?.find((e) => e.path[0] === "secretDataKeyForCrt")?.message, + secretDataKeyForKey: res.error?.errors?.find((e) => e.path[0] === "secretDataKeyForKey")?.message, + }); + }, [data]); + return ( <>
@@ -41,7 +68,7 @@ const DeployToKubernetesSecret = () => { onChange={(e) => { const newData = produce(data, (draft) => { draft.config ??= {}; - draft.config.namespace = e.target.value; + draft.config.namespace = e.target.value?.trim(); }); setDeploy(newData); }} @@ -57,7 +84,7 @@ const DeployToKubernetesSecret = () => { onChange={(e) => { const newData = produce(data, (draft) => { draft.config ??= {}; - draft.config.secretName = e.target.value; + draft.config.secretName = e.target.value?.trim(); }); setDeploy(newData); }} @@ -73,7 +100,7 @@ const DeployToKubernetesSecret = () => { onChange={(e) => { const newData = produce(data, (draft) => { draft.config ??= {}; - draft.config.secretDataKeyForCrt = e.target.value; + draft.config.secretDataKeyForCrt = e.target.value?.trim(); }); setDeploy(newData); }} @@ -89,7 +116,7 @@ const DeployToKubernetesSecret = () => { onChange={(e) => { const newData = produce(data, (draft) => { draft.config ??= {}; - draft.config.secretDataKeyForKey = e.target.value; + draft.config.secretDataKeyForKey = e.target.value?.trim(); }); setDeploy(newData); }} diff --git a/ui/src/components/certimate/DeployToLocal.tsx b/ui/src/components/certimate/DeployToLocal.tsx index ae60e75d..45a88888 100644 --- a/ui/src/components/certimate/DeployToLocal.tsx +++ b/ui/src/components/certimate/DeployToLocal.tsx @@ -87,35 +87,19 @@ const DeployToLocal = () => { useEffect(() => { const res = formSchema.safeParse(data.config); - if (!res.success) { - setError({ - ...error, - format: res.error.errors.find((e) => e.path[0] === "format")?.message, - certPath: res.error.errors.find((e) => e.path[0] === "certPath")?.message, - keyPath: res.error.errors.find((e) => e.path[0] === "keyPath")?.message, - pfxPassword: res.error.errors.find((e) => e.path[0] === "pfxPassword")?.message, - jksAlias: res.error.errors.find((e) => e.path[0] === "jksAlias")?.message, - jksKeypass: res.error.errors.find((e) => e.path[0] === "jksKeypass")?.message, - jksStorepass: res.error.errors.find((e) => e.path[0] === "jksStorepass")?.message, - shell: res.error.errors.find((e) => e.path[0] === "shell")?.message, - preCommand: res.error.errors.find((e) => e.path[0] === "preCommand")?.message, - command: res.error.errors.find((e) => e.path[0] === "command")?.message, - }); - } else { - setError({ - ...error, - format: undefined, - certPath: undefined, - keyPath: undefined, - pfxPassword: undefined, - jksAlias: undefined, - jksKeypass: undefined, - jksStorepass: undefined, - shell: undefined, - preCommand: undefined, - command: undefined, - }); - } + setError({ + ...error, + format: res.error?.errors?.find((e) => e.path[0] === "format")?.message, + certPath: res.error?.errors?.find((e) => e.path[0] === "certPath")?.message, + keyPath: res.error?.errors?.find((e) => e.path[0] === "keyPath")?.message, + pfxPassword: res.error?.errors?.find((e) => e.path[0] === "pfxPassword")?.message, + jksAlias: res.error?.errors?.find((e) => e.path[0] === "jksAlias")?.message, + jksKeypass: res.error?.errors?.find((e) => e.path[0] === "jksKeypass")?.message, + jksStorepass: res.error?.errors?.find((e) => e.path[0] === "jksStorepass")?.message, + shell: res.error?.errors?.find((e) => e.path[0] === "shell")?.message, + preCommand: res.error?.errors?.find((e) => e.path[0] === "preCommand")?.message, + command: res.error?.errors?.find((e) => e.path[0] === "command")?.message, + }); }, [data]); useEffect(() => { diff --git a/ui/src/components/certimate/DeployToQiniuCDN.tsx b/ui/src/components/certimate/DeployToQiniuCDN.tsx index 508939cd..d7358b09 100644 --- a/ui/src/components/certimate/DeployToQiniuCDN.tsx +++ b/ui/src/components/certimate/DeployToQiniuCDN.tsx @@ -27,25 +27,20 @@ const DeployToQiniuCDN = () => { 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]); - - const domainSchema = z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, { - message: t("common.errmsg.domain_invalid"), + const formSchema = z.object({ + domain: z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, { + message: t("common.errmsg.domain_invalid"), + }), }); + useEffect(() => { + const res = formSchema.safeParse(data.config); + setError({ + ...error, + domain: res.error?.errors?.find((e) => e.path[0] === "domain")?.message, + }); + }, [data]); + return (
@@ -55,26 +50,9 @@ const DeployToQiniuCDN = () => { className="w-full mt-1" value={data?.config?.domain} onChange={(e) => { - const temp = e.target.value; - - const resp = domainSchema.safeParse(temp); - if (!resp.success) { - setError({ - ...error, - domain: JSON.parse(resp.error.message)[0].message, - }); - } else { - setError({ - ...error, - domain: "", - }); - } - const newData = produce(data, (draft) => { - if (!draft.config) { - draft.config = {}; - } - draft.config.domain = temp; + draft.config ??= {}; + draft.config.domain = e.target.value?.trim(); }); setDeploy(newData); }} diff --git a/ui/src/components/certimate/DeployToSSH.tsx b/ui/src/components/certimate/DeployToSSH.tsx index b59eeb72..74d37e33 100644 --- a/ui/src/components/certimate/DeployToSSH.tsx +++ b/ui/src/components/certimate/DeployToSSH.tsx @@ -80,33 +80,18 @@ const DeployToSSH = () => { useEffect(() => { const res = formSchema.safeParse(data.config); - if (!res.success) { - setError({ - ...error, - format: res.error.errors.find((e) => e.path[0] === "format")?.message, - certPath: res.error.errors.find((e) => e.path[0] === "certPath")?.message, - keyPath: res.error.errors.find((e) => e.path[0] === "keyPath")?.message, - pfxPassword: res.error.errors.find((e) => e.path[0] === "pfxPassword")?.message, - jksAlias: res.error.errors.find((e) => e.path[0] === "jksAlias")?.message, - jksKeypass: res.error.errors.find((e) => e.path[0] === "jksKeypass")?.message, - jksStorepass: res.error.errors.find((e) => e.path[0] === "jksStorepass")?.message, - preCommand: res.error.errors.find((e) => e.path[0] === "preCommand")?.message, - command: res.error.errors.find((e) => e.path[0] === "command")?.message, - }); - } else { - setError({ - ...error, - format: undefined, - certPath: undefined, - keyPath: undefined, - pfxPassword: undefined, - jksAlias: undefined, - jksKeypass: undefined, - jksStorepass: undefined, - preCommand: undefined, - command: undefined, - }); - } + setError({ + ...error, + format: res.error?.errors?.find((e) => e.path[0] === "format")?.message, + certPath: res.error?.errors?.find((e) => e.path[0] === "certPath")?.message, + keyPath: res.error?.errors?.find((e) => e.path[0] === "keyPath")?.message, + pfxPassword: res.error?.errors?.find((e) => e.path[0] === "pfxPassword")?.message, + jksAlias: res.error?.errors?.find((e) => e.path[0] === "jksAlias")?.message, + jksKeypass: res.error?.errors?.find((e) => e.path[0] === "jksKeypass")?.message, + jksStorepass: res.error?.errors?.find((e) => e.path[0] === "jksStorepass")?.message, + preCommand: res.error?.errors?.find((e) => e.path[0] === "preCommand")?.message, + command: res.error?.errors?.find((e) => e.path[0] === "command")?.message, + }); }, [data]); useEffect(() => { diff --git a/ui/src/components/certimate/DeployToTencentCDN.tsx b/ui/src/components/certimate/DeployToTencentCDN.tsx index 05eaf22f..63f2c7ef 100644 --- a/ui/src/components/certimate/DeployToTencentCDN.tsx +++ b/ui/src/components/certimate/DeployToTencentCDN.tsx @@ -13,28 +13,34 @@ const DeployToTencentCDN = () => { const { deploy: data, setDeploy, error, setError } = useDeployEditContext(); useEffect(() => { - setError({}); + if (!data.id) { + setDeploy({ + ...data, + config: { + domain: "", + }, + }); + } }, []); 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]); + setError({}); + }, []); - const domainSchema = z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, { - message: t("common.errmsg.domain_invalid"), + const formSchema = z.object({ + domain: z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, { + message: t("common.errmsg.domain_invalid"), + }), }); + useEffect(() => { + const res = formSchema.safeParse(data.config); + setError({ + ...error, + domain: res.error?.errors?.find((e) => e.path[0] === "domain")?.message, + }); + }, [data]); + return (
@@ -44,26 +50,9 @@ const DeployToTencentCDN = () => { className="w-full mt-1" value={data?.config?.domain} onChange={(e) => { - const temp = e.target.value; - - const resp = domainSchema.safeParse(temp); - if (!resp.success) { - setError({ - ...error, - domain: JSON.parse(resp.error.message)[0].message, - }); - } else { - setError({ - ...error, - domain: "", - }); - } - const newData = produce(data, (draft) => { - if (!draft.config) { - draft.config = {}; - } - draft.config.domain = temp; + draft.config ??= {}; + draft.config.domain = e.target.value?.trim(); }); setDeploy(newData); }} diff --git a/ui/src/components/certimate/DeployToTencentCOS.tsx b/ui/src/components/certimate/DeployToTencentCOS.tsx index 5f0b8e8b..f95eb778 100644 --- a/ui/src/components/certimate/DeployToTencentCOS.tsx +++ b/ui/src/components/certimate/DeployToTencentCOS.tsx @@ -8,65 +8,16 @@ import { Label } from "@/components/ui/label"; import { useDeployEditContext } from "./DeployEdit"; const DeployToTencentCOS = () => { - 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 bucketResp = bucketSchema.safeParse(data.config?.bucket); - if (!bucketResp.success) { - setError({ - ...error, - bucket: JSON.parse(bucketResp.error.message)[0].message, - }); - } else { - setError({ - ...error, - bucket: "", - }); - } - }, []); - - 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: { - region: "", + region: "ap-guangzhou", bucket: "", domain: "", }, @@ -74,17 +25,27 @@ const DeployToTencentCOS = () => { } }, []); - const domainSchema = z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, { - message: t("common.errmsg.domain_invalid"), + useEffect(() => { + setError({}); + }, []); + + const formSchema = z.object({ + region: z.string().min(1, t("domain.deployment.form.tencent_cos_region.placeholder")), + bucket: z.string().min(1, t("domain.deployment.form.tencent_cos_bucket.placeholder")), + domain: z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, { + message: t("common.errmsg.domain_invalid"), + }), }); - const regionSchema = z.string().regex(/^ap-[a-z]+$/, { - message: t("domain.deployment.form.tencent_cos_region.placeholder"), - }); - - const bucketSchema = z.string().regex(/^.+-\d+$/, { - message: t("domain.deployment.form.tencent_cos_bucket.placeholder"), - }); + useEffect(() => { + const res = formSchema.safeParse(data.config); + setError({ + ...error, + region: res.error?.errors?.find((e) => e.path[0] === "region")?.message, + bucket: res.error?.errors?.find((e) => e.path[0] === "bucket")?.message, + domain: res.error?.errors?.find((e) => e.path[0] === "domain")?.message, + }); + }, [data]); return (
@@ -95,26 +56,9 @@ const DeployToTencentCOS = () => { 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); }} @@ -129,26 +73,9 @@ const DeployToTencentCOS = () => { className="w-full mt-1" value={data?.config?.bucket} onChange={(e) => { - const temp = e.target.value; - - const resp = bucketSchema.safeParse(temp); - if (!resp.success) { - setError({ - ...error, - bucket: JSON.parse(resp.error.message)[0].message, - }); - } else { - setError({ - ...error, - bucket: "", - }); - } - const newData = produce(data, (draft) => { - if (!draft.config) { - draft.config = {}; - } - draft.config.bucket = temp; + draft.config ??= {}; + draft.config.bucket = e.target.value?.trim(); }); setDeploy(newData); }} @@ -163,26 +90,9 @@ const DeployToTencentCOS = () => { className="w-full mt-1" value={data?.config?.domain} onChange={(e) => { - const temp = e.target.value; - - const resp = domainSchema.safeParse(temp); - if (!resp.success) { - setError({ - ...error, - domain: JSON.parse(resp.error.message)[0].message, - }); - } else { - setError({ - ...error, - domain: "", - }); - } - const newData = produce(data, (draft) => { - if (!draft.config) { - draft.config = {}; - } - draft.config.domain = temp; + draft.config ??= {}; + draft.config.domain = e.target.value?.trim(); }); setDeploy(newData); }} diff --git a/ui/src/components/certimate/DeployToTencentTEO.tsx b/ui/src/components/certimate/DeployToTencentTEO.tsx index 80715fd1..6b90c55c 100644 --- a/ui/src/components/certimate/DeployToTencentTEO.tsx +++ b/ui/src/components/certimate/DeployToTencentTEO.tsx @@ -14,47 +14,36 @@ const DeployToTencentTEO = () => { const { deploy: data, setDeploy, error, setError } = useDeployEditContext(); useEffect(() => { - setError({}); + if (!data.id) { + setDeploy({ + ...data, + config: { + zoneId: "", + }, + }); + } }, []); 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]); + setError({}); + }, []); + + const formSchema = z.object({ + zoneId: z.string().min(1, t("domain.deployment.form.tencent_teo_zone_id.placeholder")), + domain: z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, { + message: t("common.errmsg.domain_invalid"), + }), + }); useEffect(() => { - const resp = zoneIdSchema.safeParse(data.config?.zoneId); - if (!resp.success) { - setError({ - ...error, - zoneId: JSON.parse(resp.error.message)[0].message, - }); - } else { - setError({ - ...error, - zoneId: "", - }); - } + const res = formSchema.safeParse(data.config); + setError({ + ...error, + zoneId: res.error?.errors?.find((e) => e.path[0] === "zoneId")?.message, + domain: res.error?.errors?.find((e) => e.path[0] === "domain")?.message, + }); }, [data]); - const domainSchema = z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, { - message: t("common.errmsg.domain_invalid"), - }); - - const zoneIdSchema = z.string().regex(/^zone-[0-9a-zA-Z]{9}$/, { - message: t("common.errmsg.zoneid_invalid"), - }); - return (
@@ -64,26 +53,9 @@ const DeployToTencentTEO = () => { className="w-full mt-1" value={data?.config?.zoneId} onChange={(e) => { - const temp = e.target.value; - - const resp = zoneIdSchema.safeParse(temp); - if (!resp.success) { - setError({ - ...error, - zoneId: JSON.parse(resp.error.message)[0].message, - }); - } else { - setError({ - ...error, - zoneId: "", - }); - } - const newData = produce(data, (draft) => { - if (!draft.config) { - draft.config = {}; - } - draft.config.zoneId = temp; + draft.config ??= {}; + draft.config.zoneId = e.target.value?.trim(); }); setDeploy(newData); }} @@ -98,26 +70,9 @@ const DeployToTencentTEO = () => { className="w-full mt-1" value={data?.config?.domain} onChange={(e) => { - const temp = e.target.value; - - const resp = domainSchema.safeParse(temp); - if (!resp.success) { - setError({ - ...error, - domain: JSON.parse(resp.error.message)[0].message, - }); - } else { - setError({ - ...error, - domain: "", - }); - } - const newData = produce(data, (draft) => { - if (!draft.config) { - draft.config = {}; - } - draft.config.domain = temp; + draft.config ??= {}; + draft.config.domain = e.target.value?.trim(); }); setDeploy(newData); }} diff --git a/ui/src/components/certimate/DeployToWebhook.tsx b/ui/src/components/certimate/DeployToWebhook.tsx index 3134983a..3268c320 100644 --- a/ui/src/components/certimate/DeployToWebhook.tsx +++ b/ui/src/components/certimate/DeployToWebhook.tsx @@ -6,9 +6,16 @@ import KVList from "./KVList"; import { type KVType } from "@/domain/domain"; const DeployToWebhook = () => { - const { deploy: data, setDeploy } = useDeployEditContext(); + const { deploy: data, setDeploy, setError } = useDeployEditContext(); - const { setError } = useDeployEditContext(); + useEffect(() => { + if (!data.id) { + setDeploy({ + ...data, + config: {}, + }); + } + }, []); useEffect(() => { setError({}); @@ -20,9 +27,7 @@ const DeployToWebhook = () => { variables={data?.config?.variables} onValueChange={(variables: KVType[]) => { const newData = produce(data, (draft) => { - if (!draft.config) { - draft.config = {}; - } + draft.config ??= {}; draft.config.variables = variables; }); setDeploy(newData); diff --git a/ui/src/i18n/locales/en/nls.common.json b/ui/src/i18n/locales/en/nls.common.json index 4111fa21..98eaae87 100644 --- a/ui/src/i18n/locales/en/nls.common.json +++ b/ui/src/i18n/locales/en/nls.common.json @@ -51,7 +51,6 @@ "common.errmsg.host_invalid": "Please enter the correct domain name or IP", "common.errmsg.ip_invalid": "Please enter IP", "common.errmsg.url_invalid": "Please enter a valid URL", - "common.errmsg.zoneid_invalid": "Please enter Zone ID", "common.provider.aliyun": "Alibaba Cloud", "common.provider.aliyun.oss": "Alibaba Cloud - OSS", diff --git a/ui/src/i18n/locales/en/nls.domain.json b/ui/src/i18n/locales/en/nls.domain.json index 5e1d77e2..068aec7a 100644 --- a/ui/src/i18n/locales/en/nls.domain.json +++ b/ui/src/i18n/locales/en/nls.domain.json @@ -95,6 +95,8 @@ "domain.deployment.form.tencent_cos_region.placeholder": "Please enter region (e.g. ap-guangzhou)", "domain.deployment.form.tencent_cos_bucket.label": "Bucket", "domain.deployment.form.tencent_cos_bucket.placeholder": "Please enter bucket", + "domain.deployment.form.tencent_cdn_region.label": "Region", + "domain.deployment.form.tencent_cdn_region.placeholder": "Please enter region (e.g. ap-guangzhou)", "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_resource_type.label": "Resource Type", diff --git a/ui/src/i18n/locales/zh/nls.common.json b/ui/src/i18n/locales/zh/nls.common.json index 28777f3a..146f0683 100644 --- a/ui/src/i18n/locales/zh/nls.common.json +++ b/ui/src/i18n/locales/zh/nls.common.json @@ -51,7 +51,6 @@ "common.errmsg.host_invalid": "请输入正确的域名或 IP 地址", "common.errmsg.ip_invalid": "请输入正确的 IP 地址", "common.errmsg.url_invalid": "请输入正确的 URL", - "common.errmsg.zoneid_invalid": "请输入正确的 Zone ID", "common.provider.aliyun": "阿里云", "common.provider.aliyun.oss": "阿里云 - 对象存储 OSS", diff --git a/ui/src/i18n/locales/zh/nls.domain.json b/ui/src/i18n/locales/zh/nls.domain.json index c5ef365a..376e4d0a 100644 --- a/ui/src/i18n/locales/zh/nls.domain.json +++ b/ui/src/i18n/locales/zh/nls.domain.json @@ -115,6 +115,8 @@ "domain.deployment.form.tencent_teo_zone_id.placeholder": "请输入 Zone ID", "domain.deployment.form.tencent_teo_domain.label": "部署到域名(支持泛域名, 应与服务器上配置的域名完全一致, 每行一个域名)", "domain.deployment.form.tencent_teo_domain.placeholder": "请输入部署到的域名", + "domain.deployment.form.huaweicloud_cdn_region.label": "地域", + "domain.deployment.form.huaweicloud_cdn_region.placeholder": "请输入地域(如 cn-north-1)", "domain.deployment.form.huaweicloud_elb_region.label": "地域", "domain.deployment.form.huaweicloud_elb_region.placeholder": "请输入地域(如 cn-north-1)", "domain.deployment.form.huaweicloud_elb_resource_type.label": "替换方式", From 260cfb96ece4aa4bc3d34360840b40955dc58ec2 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Thu, 31 Oct 2024 14:27:11 +0800 Subject: [PATCH 09/18] refactor(ui): declare deploy config params --- ui/src/components/certimate/DeployEdit.tsx | 21 +- .../components/certimate/DeployEditDialog.tsx | 30 +-- .../certimate/DeployToAliyunALB.tsx | 64 +++--- .../certimate/DeployToAliyunCDN.tsx | 34 +-- .../certimate/DeployToAliyunCLB.tsx | 63 +++--- .../certimate/DeployToAliyunNLB.tsx | 66 +++--- .../certimate/DeployToAliyunOSS.tsx | 50 +++-- .../certimate/DeployToHuaweiCloudCDN.tsx | 40 ++-- .../certimate/DeployToHuaweiCloudELB.tsx | 80 +++---- .../certimate/DeployToKubernetesSecret.tsx | 50 +++-- ui/src/components/certimate/DeployToLocal.tsx | 211 ++++++++++-------- .../components/certimate/DeployToQiniuCDN.tsx | 34 +-- ui/src/components/certimate/DeployToSSH.tsx | 161 ++++++------- .../certimate/DeployToTencentCDN.tsx | 34 +-- .../certimate/DeployToTencentCLB.tsx | 84 +++---- .../certimate/DeployToTencentCOS.tsx | 50 +++-- .../certimate/DeployToTencentTEO.tsx | 43 ++-- .../components/certimate/DeployToWebhook.tsx | 6 +- ui/src/i18n/locales/zh/nls.domain.json | 2 +- 19 files changed, 598 insertions(+), 525 deletions(-) diff --git a/ui/src/components/certimate/DeployEdit.tsx b/ui/src/components/certimate/DeployEdit.tsx index 81353a29..05559360 100644 --- a/ui/src/components/certimate/DeployEdit.tsx +++ b/ui/src/components/certimate/DeployEdit.tsx @@ -1,16 +1,17 @@ -import { createContext, useContext } from "react"; +import { createContext, useContext, type Context as ReactContext } from "react"; -import { DeployConfig } from "@/domain/domain"; +import { type DeployConfig } from "@/domain/domain"; -type DeployEditContext = { - deploy: DeployConfig; - error: Record; - setDeploy: (deploy: DeployConfig) => void; - setError: (error: Record) => void; +export type DeployEditContext = { + config: Omit & { config: T }; + setConfig: (config: Omit & { config: T }) => void; + + errors: { [K in keyof T]?: string }; + setErrors: (error: { [K in keyof T]?: string }) => void; }; export const Context = createContext({} as DeployEditContext); -export const useDeployEditContext = () => { - return useContext(Context); -}; +export function useDeployEditContext() { + return useContext>(Context as unknown as ReactContext>); +} diff --git a/ui/src/components/certimate/DeployEditDialog.tsx b/ui/src/components/certimate/DeployEditDialog.tsx index 6db96012..140ca0b0 100644 --- a/ui/src/components/certimate/DeployEditDialog.tsx +++ b/ui/src/components/certimate/DeployEditDialog.tsx @@ -8,7 +8,7 @@ import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@/components/ui/select"; import { ScrollArea } from "@/components/ui/scroll-area"; import AccessEditDialog from "./AccessEditDialog"; -import { Context as DeployEditContext } from "./DeployEdit"; +import { Context as DeployEditContext, type DeployEditContext as DeployEditContextType } from "./DeployEdit"; import DeployToAliyunOSS from "./DeployToAliyunOSS"; import DeployToAliyunCDN from "./DeployToAliyunCDN"; import DeployToAliyunCLB from "./DeployToAliyunCLB"; @@ -49,7 +49,7 @@ const DeployEditDialog = ({ trigger, deployConfig, onSave }: DeployEditDialogPro type: "", }); - const [error, setError] = useState>({}); + const [errors, setErrors] = useState>({}); const [open, setOpen] = useState(false); @@ -66,10 +66,10 @@ const DeployEditDialog = ({ trigger, deployConfig, onSave }: DeployEditDialogPro useEffect(() => { setDeployType(locDeployConfig.type); - setError({}); + setErrors({}); }, [locDeployConfig.type]); - const setDeploy = useCallback( + const setConfig = useCallback( (deploy: DeployConfig) => { if (deploy.type !== locDeployConfig.type) { setLocDeployConfig({ ...deploy, access: "", config: {} }); @@ -94,10 +94,10 @@ const DeployEditDialog = ({ trigger, deployConfig, onSave }: DeployEditDialogPro const handleSaveClick = () => { // 验证数据 - const newError = { ...error }; + const newError = { ...errors }; newError.type = locDeployConfig.type === "" ? t("domain.deployment.form.access.placeholder") : ""; newError.access = locDeployConfig.access === "" ? t("domain.deployment.form.access.placeholder") : ""; - setError(newError); + setErrors(newError); if (Object.values(newError).some((e) => !!e)) return; // 保存数据 @@ -108,7 +108,7 @@ const DeployEditDialog = ({ trigger, deployConfig, onSave }: DeployEditDialogPro access: "", type: "", }); - setError({}); + setErrors({}); // 关闭弹框 setOpen(false); @@ -171,10 +171,10 @@ const DeployEditDialog = ({ trigger, deployConfig, onSave }: DeployEditDialogPro return ( @@ -199,7 +199,7 @@ const DeployEditDialog = ({ trigger, deployConfig, onSave }: DeployEditDialogPro -
{error.type}
+
{errors.type}
{/* 授权配置 */} @@ -241,7 +241,7 @@ const DeployEditDialog = ({ trigger, deployConfig, onSave }: DeployEditDialogPro -
{error.access}
+
{errors.access}
{/* 其他参数 */} diff --git a/ui/src/components/certimate/DeployToAliyunALB.tsx b/ui/src/components/certimate/DeployToAliyunALB.tsx index 94172fd4..33a7c562 100644 --- a/ui/src/components/certimate/DeployToAliyunALB.tsx +++ b/ui/src/components/certimate/DeployToAliyunALB.tsx @@ -8,27 +8,31 @@ import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { useDeployEditContext } from "./DeployEdit"; +type DeployToAliyunALBConfigParams = { + region?: string; + resourceType?: string; + loadbalancerId?: string; + listenerId?: string; +}; + const DeployToAliyunALB = () => { const { t } = useTranslation(); - const { deploy: data, setDeploy, error, setError } = useDeployEditContext(); + const { config, setConfig, errors, setErrors } = useDeployEditContext(); useEffect(() => { - if (!data.id) { - setDeploy({ - ...data, + if (!config.id) { + setConfig({ + ...config, config: { region: "cn-hangzhou", - resourceType: "", - loadbalancerId: "", - listenerId: "", }, }); } }, []); useEffect(() => { - setError({}); + setErrors({}); }, []); const formSchema = z @@ -50,15 +54,15 @@ const DeployToAliyunALB = () => { }); useEffect(() => { - const res = formSchema.safeParse(data.config); - setError({ - ...error, + const res = formSchema.safeParse(config.config); + setErrors({ + ...errors, 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, }); - }, [data]); + }, [config]); return (
@@ -67,28 +71,28 @@ const DeployToAliyunALB = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.region = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.region}
+
{errors?.region}
-
{error?.resourceType}
+
{errors?.resourceType}
- {data?.config?.resourceType === "loadbalancer" ? ( + {config?.config?.resourceType === "loadbalancer" ? (
{ - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.loadbalancerId = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.loadbalancerId}
+
{errors?.loadbalancerId}
) : ( <> )} - {data?.config?.resourceType === "listener" ? ( + {config?.config?.resourceType === "listener" ? (
{ - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.listenerId = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.listenerId}
+
{errors?.listenerId}
) : ( <> diff --git a/ui/src/components/certimate/DeployToAliyunCDN.tsx b/ui/src/components/certimate/DeployToAliyunCDN.tsx index 32eb5a41..0d073720 100644 --- a/ui/src/components/certimate/DeployToAliyunCDN.tsx +++ b/ui/src/components/certimate/DeployToAliyunCDN.tsx @@ -7,24 +7,26 @@ import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { useDeployEditContext } from "./DeployEdit"; +type DeployToAliyunCDNConfigParams = { + domain?: string; +}; + const DeployToAliyunCDN = () => { const { t } = useTranslation(); - const { deploy: data, setDeploy, error, setError } = useDeployEditContext(); + const { config, setConfig, errors, setErrors } = useDeployEditContext(); useEffect(() => { - if (!data.id) { - setDeploy({ - ...data, - config: { - domain: "", - }, + if (!config.id) { + setConfig({ + ...config, + config: {}, }); } }, []); useEffect(() => { - setError({}); + setErrors({}); }, []); const formSchema = z.object({ @@ -34,12 +36,12 @@ const DeployToAliyunCDN = () => { }); useEffect(() => { - const res = formSchema.safeParse(data.config); - setError({ - ...error, + const res = formSchema.safeParse(config.config); + setErrors({ + ...errors, domain: res.error?.errors?.find((e) => e.path[0] === "domain")?.message, }); - }, [data]); + }, [config]); return (
@@ -48,16 +50,16 @@ const DeployToAliyunCDN = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.domain = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.domain}
+
{errors?.domain}
); diff --git a/ui/src/components/certimate/DeployToAliyunCLB.tsx b/ui/src/components/certimate/DeployToAliyunCLB.tsx index d90574b3..a00c3b5b 100644 --- a/ui/src/components/certimate/DeployToAliyunCLB.tsx +++ b/ui/src/components/certimate/DeployToAliyunCLB.tsx @@ -8,19 +8,24 @@ import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { useDeployEditContext } from "./DeployEdit"; +type DeployToAliyunCLBConfigParams = { + region?: string; + resourceType?: string; + loadbalancerId?: string; + listenerPort?: string; +}; + const DeployToAliyunCLB = () => { const { t } = useTranslation(); - const { deploy: data, setDeploy, error, setError } = useDeployEditContext(); + const { config, setConfig, errors, setErrors } = useDeployEditContext(); useEffect(() => { - if (!data.id) { - setDeploy({ - ...data, + if (!config.id) { + setConfig({ + ...config, config: { region: "cn-hangzhou", - resourceType: "", - loadbalancerId: "", listenerPort: "443", }, }); @@ -28,7 +33,7 @@ const DeployToAliyunCLB = () => { }, []); useEffect(() => { - setError({}); + setErrors({}); }, []); const formSchema = z @@ -50,15 +55,15 @@ const DeployToAliyunCLB = () => { }); useEffect(() => { - const res = formSchema.safeParse(data.config); - setError({ - ...error, + const res = formSchema.safeParse(config.config); + setErrors({ + ...errors, 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, listenerPort: res.error?.errors?.find((e) => e.path[0] === "listenerPort")?.message, }); - }, [data]); + }, [config]); return (
@@ -67,28 +72,28 @@ const DeployToAliyunCLB = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.region = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.region}
+
{errors?.region}
-
{error?.resourceType}
+
{errors?.resourceType}
@@ -109,34 +114,34 @@ const DeployToAliyunCLB = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.loadbalancerId = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.loadbalancerId}
+
{errors?.loadbalancerId}
- {data?.config?.resourceType === "listener" ? ( + {config?.config?.resourceType === "listener" ? (
{ - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.listenerPort = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.listenerPort}
+
{errors?.listenerPort}
) : ( <> diff --git a/ui/src/components/certimate/DeployToAliyunNLB.tsx b/ui/src/components/certimate/DeployToAliyunNLB.tsx index 0e4ea03e..8ca68fa8 100644 --- a/ui/src/components/certimate/DeployToAliyunNLB.tsx +++ b/ui/src/components/certimate/DeployToAliyunNLB.tsx @@ -8,27 +8,31 @@ import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { useDeployEditContext } from "./DeployEdit"; +type DeployToAliyunNLBConfigParams = { + region?: string; + resourceType?: string; + loadbalancerId?: string; + listenerId?: string; +}; + const DeployToAliyunNLB = () => { const { t } = useTranslation(); - const { deploy: data, setDeploy, error, setError } = useDeployEditContext(); + const { config, setConfig, errors, setErrors } = useDeployEditContext(); useEffect(() => { - if (!data.id) { - setDeploy({ - ...data, + if (!config.id) { + setConfig({ + ...config, config: { region: "cn-hangzhou", - resourceType: "", - loadbalancerId: "", - listenerId: "", }, }); } }, []); useEffect(() => { - setError({}); + setErrors({}); }, []); const formSchema = z @@ -50,15 +54,15 @@ const DeployToAliyunNLB = () => { }); useEffect(() => { - const res = formSchema.safeParse(data.config); - setError({ - ...error, + const res = formSchema.safeParse(config.config); + setErrors({ + ...errors, 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, }); - }, [data]); + }, [config]); return (
@@ -67,28 +71,28 @@ const DeployToAliyunNLB = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.region = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.region}
+
{errors?.region}
-
{error?.resourceType}
+
{errors?.resourceType}
- {data?.config?.resourceType === "loadbalancer" ? ( + {config?.config?.resourceType === "loadbalancer" ? (
{ - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.loadbalancerId = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.loadbalancerId}
+
{errors?.loadbalancerId}
) : ( <> )} - {data?.config?.resourceType === "listener" ? ( + {config?.config?.resourceType === "listener" ? (
{ - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.listenerId = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.listenerId}
+
{errors?.listenerId}
) : ( <> diff --git a/ui/src/components/certimate/DeployToAliyunOSS.tsx b/ui/src/components/certimate/DeployToAliyunOSS.tsx index 7037175c..14249758 100644 --- a/ui/src/components/certimate/DeployToAliyunOSS.tsx +++ b/ui/src/components/certimate/DeployToAliyunOSS.tsx @@ -7,26 +7,30 @@ import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { useDeployEditContext } from "./DeployEdit"; +type DeployToAliyunOSSConfigParams = { + endpoint?: string; + bucket?: string; + domain?: string; +}; + const DeployToAliyunOSS = () => { const { t } = useTranslation(); - const { deploy: data, setDeploy, error, setError } = useDeployEditContext(); + const { config, setConfig, errors, setErrors } = useDeployEditContext(); useEffect(() => { - if (!data.id) { - setDeploy({ - ...data, + if (!config.id) { + setConfig({ + ...config, config: { endpoint: "oss.aliyuncs.com", - bucket: "", - domain: "", }, }); } }, []); useEffect(() => { - setError({}); + setErrors({}); }, []); const formSchema = z.object({ @@ -42,14 +46,14 @@ const DeployToAliyunOSS = () => { }); useEffect(() => { - const res = formSchema.safeParse(data.config); - setError({ - ...error, + const res = formSchema.safeParse(config.config); + setErrors({ + ...errors, endpoint: res.error?.errors?.find((e) => e.path[0] === "endpoint")?.message, bucket: res.error?.errors?.find((e) => e.path[0] === "bucket")?.message, domain: res.error?.errors?.find((e) => e.path[0] === "domain")?.message, }); - }, [data]); + }, [config]); return (
@@ -58,16 +62,16 @@ const DeployToAliyunOSS = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.endpoint = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.endpoint}
+
{errors?.endpoint}
@@ -75,16 +79,16 @@ const DeployToAliyunOSS = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.bucket = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.bucket}
+
{errors?.bucket}
@@ -92,16 +96,16 @@ const DeployToAliyunOSS = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.domain = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.domain}
+
{errors?.domain}
); diff --git a/ui/src/components/certimate/DeployToHuaweiCloudCDN.tsx b/ui/src/components/certimate/DeployToHuaweiCloudCDN.tsx index 10591530..eaeda1b7 100644 --- a/ui/src/components/certimate/DeployToHuaweiCloudCDN.tsx +++ b/ui/src/components/certimate/DeployToHuaweiCloudCDN.tsx @@ -7,25 +7,29 @@ import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { useDeployEditContext } from "./DeployEdit"; +type DeployToHuaweiCloudCDNConfigParams = { + region?: string; + domain?: string; +}; + const DeployToHuaweiCloudCDN = () => { const { t } = useTranslation(); - const { deploy: data, setDeploy, error, setError } = useDeployEditContext(); + const { config, setConfig, errors, setErrors } = useDeployEditContext(); useEffect(() => { - if (!data.id) { - setDeploy({ - ...data, + if (!config.id) { + setConfig({ + ...config, config: { region: "cn-north-1", - domain: "", }, }); } }, []); useEffect(() => { - setError({}); + setErrors({}); }, []); const formSchema = z.object({ @@ -38,13 +42,13 @@ const DeployToHuaweiCloudCDN = () => { }); useEffect(() => { - const res = formSchema.safeParse(data.config); - setError({ - ...error, + const res = formSchema.safeParse(config.config); + setErrors({ + ...errors, region: res.error?.errors?.find((e) => e.path[0] === "region")?.message, domain: res.error?.errors?.find((e) => e.path[0] === "domain")?.message, }); - }, [data]); + }, [config]); return (
@@ -53,16 +57,16 @@ const DeployToHuaweiCloudCDN = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.region = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.region}
+
{errors?.region}
@@ -70,16 +74,16 @@ const DeployToHuaweiCloudCDN = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.domain = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.domain}
+
{errors?.domain}
); diff --git a/ui/src/components/certimate/DeployToHuaweiCloudELB.tsx b/ui/src/components/certimate/DeployToHuaweiCloudELB.tsx index a3d44f3c..a26d33c8 100644 --- a/ui/src/components/certimate/DeployToHuaweiCloudELB.tsx +++ b/ui/src/components/certimate/DeployToHuaweiCloudELB.tsx @@ -8,28 +8,32 @@ import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { useDeployEditContext } from "./DeployEdit"; -const DeployToHuaweiCloudCDN = () => { +type DeployToHuaweiCloudELBConfigParams = { + region?: string; + resourceType?: string; + certificateId?: string; + loadbalancerId?: string; + listenerId?: string; +}; + +const DeployToHuaweiCloudELB = () => { const { t } = useTranslation(); - const { deploy: data, setDeploy, error, setError } = useDeployEditContext(); + const { config, setConfig, errors, setErrors } = useDeployEditContext(); useEffect(() => { - if (!data.id) { - setDeploy({ - ...data, + if (!config.id) { + setConfig({ + ...config, config: { region: "cn-north-1", - resourceType: "", - certificateId: "", - loadbalancerId: "", - listenerId: "", }, }); } }, []); useEffect(() => { - setError({}); + setErrors({}); }, []); const formSchema = z @@ -56,16 +60,16 @@ const DeployToHuaweiCloudCDN = () => { }); useEffect(() => { - const res = formSchema.safeParse(data.config); - setError({ - ...error, + const res = formSchema.safeParse(config.config); + setErrors({ + ...errors, region: res.error?.errors?.find((e) => e.path[0] === "region")?.message, resourceType: res.error?.errors?.find((e) => e.path[0] === "resourceType")?.message, certificateId: res.error?.errors?.find((e) => e.path[0] === "certificateId")?.message, loadbalancerId: res.error?.errors?.find((e) => e.path[0] === "loadbalancerId")?.message, listenerId: res.error?.errors?.find((e) => e.path[0] === "listenerId")?.message, }); - }, [data]); + }, [config]); return (
@@ -74,28 +78,28 @@ const DeployToHuaweiCloudCDN = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.region = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.region}
+
{errors?.region}
-
{error?.resourceType}
+
{errors?.resourceType}
- {data?.config?.resourceType === "certificate" ? ( + {config?.config?.resourceType === "certificate" ? (
{ - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.certificateId = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.certificateId}
+
{errors?.certificateId}
) : ( <> )} - {data?.config?.resourceType === "loadbalancer" ? ( + {config?.config?.resourceType === "loadbalancer" ? (
{ - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.loadbalancerId = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.loadbalancerId}
+
{errors?.loadbalancerId}
) : ( <> )} - {data?.config?.resourceType === "listener" ? ( + {config?.config?.resourceType === "listener" ? (
{ - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.listenerId = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.listenerId}
+
{errors?.listenerId}
) : ( <> @@ -178,4 +182,4 @@ const DeployToHuaweiCloudCDN = () => { ); }; -export default DeployToHuaweiCloudCDN; +export default DeployToHuaweiCloudELB; diff --git a/ui/src/components/certimate/DeployToKubernetesSecret.tsx b/ui/src/components/certimate/DeployToKubernetesSecret.tsx index 90d6d84f..119ae12f 100644 --- a/ui/src/components/certimate/DeployToKubernetesSecret.tsx +++ b/ui/src/components/certimate/DeployToKubernetesSecret.tsx @@ -7,18 +7,24 @@ import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { useDeployEditContext } from "./DeployEdit"; +type DeployToKubernetesSecretConfigParams = { + namespace?: string; + secretName?: string; + secretDataKeyForCrt?: string; + secretDataKeyForKey?: string; +}; + const DeployToKubernetesSecret = () => { const { t } = useTranslation(); - const { deploy: data, setDeploy, error, setError } = useDeployEditContext(); + const { config, setConfig, errors, setErrors } = useDeployEditContext(); useEffect(() => { - if (!data.id) { - setDeploy({ - ...data, + if (!config.id) { + setConfig({ + ...config, config: { namespace: "default", - secretName: "", secretDataKeyForCrt: "tls.crt", secretDataKeyForKey: "tls.key", }, @@ -27,7 +33,7 @@ const DeployToKubernetesSecret = () => { }, []); useEffect(() => { - setError({}); + setErrors({}); }, []); const formSchema = z.object({ @@ -46,15 +52,15 @@ const DeployToKubernetesSecret = () => { }); useEffect(() => { - const res = formSchema.safeParse(data.config); - setError({ - ...error, + const res = formSchema.safeParse(config.config); + setErrors({ + ...errors, namespace: res.error?.errors?.find((e) => e.path[0] === "namespace")?.message, secretName: res.error?.errors?.find((e) => e.path[0] === "secretName")?.message, secretDataKeyForCrt: res.error?.errors?.find((e) => e.path[0] === "secretDataKeyForCrt")?.message, secretDataKeyForKey: res.error?.errors?.find((e) => e.path[0] === "secretDataKeyForKey")?.message, }); - }, [data]); + }, [config]); return ( <> @@ -64,13 +70,13 @@ const DeployToKubernetesSecret = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.namespace = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} />
@@ -80,13 +86,13 @@ const DeployToKubernetesSecret = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.secretName = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} />
@@ -96,13 +102,13 @@ const DeployToKubernetesSecret = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.secretDataKeyForCrt = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} />
@@ -112,13 +118,13 @@ const DeployToKubernetesSecret = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.secretDataKeyForKey = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} />
diff --git a/ui/src/components/certimate/DeployToLocal.tsx b/ui/src/components/certimate/DeployToLocal.tsx index 45a88888..11a20c2a 100644 --- a/ui/src/components/certimate/DeployToLocal.tsx +++ b/ui/src/components/certimate/DeployToLocal.tsx @@ -12,33 +12,40 @@ import { Textarea } from "@/components/ui/textarea"; import { useDeployEditContext } from "./DeployEdit"; import { cn } from "@/lib/utils"; +type DeployToLocalConfigParams = { + format?: string; + certPath?: string; + keyPath?: string; + pfxPassword?: string; + jksAlias?: string; + jksKeypass?: string; + jksStorepass?: string; + shell?: string; + preCommand?: string; + command?: string; +}; + const DeployToLocal = () => { const { t } = useTranslation(); - const { deploy: data, setDeploy, error, setError } = useDeployEditContext(); + const { config, setConfig, errors, setErrors } = useDeployEditContext(); useEffect(() => { - if (!data.id) { - setDeploy({ - ...data, + if (!config.id) { + setConfig({ + ...config, config: { format: "pem", certPath: "/etc/nginx/ssl/nginx.crt", keyPath: "/etc/nginx/ssl/nginx.key", - pfxPassword: "", - jksAlias: "", - jksKeypass: "", - jksStorepass: "", shell: "sh", - preCommand: "", - command: "sudo service nginx reload", }, }); } }, []); useEffect(() => { - setError({}); + setErrors({}); }, []); const formSchema = z @@ -86,9 +93,9 @@ const DeployToLocal = () => { }); useEffect(() => { - const res = formSchema.safeParse(data.config); - setError({ - ...error, + const res = formSchema.safeParse(config.config); + setErrors({ + ...errors, format: res.error?.errors?.find((e) => e.path[0] === "format")?.message, certPath: res.error?.errors?.find((e) => e.path[0] === "certPath")?.message, keyPath: res.error?.errors?.find((e) => e.path[0] === "keyPath")?.message, @@ -100,38 +107,41 @@ const DeployToLocal = () => { preCommand: res.error?.errors?.find((e) => e.path[0] === "preCommand")?.message, command: res.error?.errors?.find((e) => e.path[0] === "command")?.message, }); - }, [data]); + }, [config]); useEffect(() => { - if (data.config?.format === "pem") { - if (/(.pfx|.jks)$/.test(data.config.certPath)) { - const newData = produce(data, (draft) => { - draft.config ??= {}; - draft.config.certPath = data.config!.certPath.replace(/(.pfx|.jks)$/, ".crt"); - }); - setDeploy(newData); + if (config.config?.format === "pem") { + if (/(.pfx|.jks)$/.test(config.config.certPath!)) { + setConfig( + produce(config, (draft) => { + draft.config ??= {}; + draft.config.certPath = config.config!.certPath!.replace(/(.pfx|.jks)$/, ".crt"); + }) + ); } - } else if (data.config?.format === "pfx") { - if (/(.crt|.jks)$/.test(data.config.certPath)) { - const newData = produce(data, (draft) => { - draft.config ??= {}; - draft.config.certPath = data.config!.certPath.replace(/(.crt|.jks)$/, ".pfx"); - }); - setDeploy(newData); + } else if (config.config?.format === "pfx") { + if (/(.crt|.jks)$/.test(config.config.certPath!)) { + setConfig( + produce(config, (draft) => { + draft.config ??= {}; + draft.config.certPath = config.config!.certPath!.replace(/(.crt|.jks)$/, ".pfx"); + }) + ); } - } else if (data.config?.format === "jks") { - if (/(.crt|.pfx)$/.test(data.config.certPath)) { - const newData = produce(data, (draft) => { - draft.config ??= {}; - draft.config.certPath = data.config!.certPath.replace(/(.crt|.pfx)$/, ".jks"); - }); - setDeploy(newData); + } else if (config.config?.format === "jks") { + if (/(.crt|.pfx)$/.test(config.config.certPath!)) { + setConfig( + produce(config, (draft) => { + draft.config ??= {}; + draft.config.certPath = config.config!.certPath!.replace(/(.crt|.pfx)$/, ".jks"); + }) + ); } } - }, [data.config?.format]); + }, [config.config?.format]); const getOptionCls = (val: string) => { - if (data.config?.shell === val) { + if (config.config?.shell === val) { return "border-primary dark:border-primary"; } @@ -142,21 +152,23 @@ const DeployToLocal = () => { switch (key) { case "reload_nginx": { - const newData = produce(data, (draft) => { - draft.config ??= {}; - draft.config.shell = "sh"; - draft.config.command = "sudo service nginx reload"; - }); - setDeploy(newData); + setConfig( + produce(config, (draft) => { + draft.config ??= {}; + draft.config.shell = "sh"; + draft.config.command = "sudo service nginx reload"; + }) + ); } break; case "binding_iis": { - const newData = produce(data, (draft) => { - draft.config ??= {}; - draft.config.shell = "powershell"; - draft.config.command = ` + setConfig( + produce(config, (draft) => { + draft.config ??= {}; + draft.config.shell = "powershell"; + draft.config.command = ` # 请将以下变量替换为实际值 $pfxPath = "" # PFX 文件路径 $pfxPassword = "" # PFX 密码 @@ -185,17 +197,18 @@ $binding.AddSslCertificate($thumbprint, "My") # 删除目录下的证书文件 Remove-Item -Path "$pfxPath" -Force `.trim(); - }); - setDeploy(newData); + }) + ); } break; case "binding_netsh": { - const newData = produce(data, (draft) => { - draft.config ??= {}; - draft.config.shell = "powershell"; - draft.config.command = ` + setConfig( + produce(config, (draft) => { + draft.config ??= {}; + draft.config.shell = "powershell"; + draft.config.command = ` # 请将以下变量替换为实际值 $pfxPath = "" # PFX 文件路径 $pfxPassword = "" # PFX 密码 @@ -216,8 +229,8 @@ netsh http add sslcert ipport=$addr certhash=$thumbprint # 删除目录下的证书文件 Remove-Item -Path "$pfxPath" -Force `.trim(); - }); - setDeploy(newData); + }) + ); } break; } @@ -229,13 +242,13 @@ Remove-Item -Path "$pfxPath" -Force
-
{error?.format}
+
{errors?.format}
@@ -257,77 +270,77 @@ Remove-Item -Path "$pfxPath" -Force { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.certPath = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.certPath}
+
{errors?.certPath}
- {data.config?.format === "pem" ? ( + {config.config?.format === "pem" ? (
{ - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.keyPath = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.keyPath}
+
{errors?.keyPath}
) : ( <> )} - {data.config?.format === "pfx" ? ( + {config.config?.format === "pfx" ? (
{ - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.pfxPassword = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.pfxPassword}
+
{errors?.pfxPassword}
) : ( <> )} - {data.config?.format === "jks" ? ( + {config.config?.format === "jks" ? ( <>
{ - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.jksAlias = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.jksAlias}
+
{errors?.jksAlias}
@@ -335,16 +348,16 @@ Remove-Item -Path "$pfxPath" -Force { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.jksKeypass = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.jksKeypass}
+
{errors?.jksKeypass}
@@ -352,16 +365,16 @@ Remove-Item -Path "$pfxPath" -Force { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.jksStorepass = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.jksStorepass}
+
{errors?.jksStorepass}
) : ( @@ -372,13 +385,13 @@ Remove-Item -Path "$pfxPath" -Force { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.shell = val; }); - setDeploy(newData); + setConfig(nv); }} >
@@ -406,24 +419,24 @@ Remove-Item -Path "$pfxPath" -Force
-
{error?.shell}
+
{errors?.shell}
-
{error?.preCommand}
+
{errors?.preCommand}
@@ -448,17 +461,17 @@ Remove-Item -Path "$pfxPath" -Force
-
{error?.command}
+
{errors?.command}
diff --git a/ui/src/components/certimate/DeployToQiniuCDN.tsx b/ui/src/components/certimate/DeployToQiniuCDN.tsx index d7358b09..90163c12 100644 --- a/ui/src/components/certimate/DeployToQiniuCDN.tsx +++ b/ui/src/components/certimate/DeployToQiniuCDN.tsx @@ -7,24 +7,26 @@ import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { useDeployEditContext } from "./DeployEdit"; +type DeployToQiniuCDNConfigParams = { + domain?: string; +}; + const DeployToQiniuCDN = () => { const { t } = useTranslation(); - const { deploy: data, setDeploy, error, setError } = useDeployEditContext(); + const { config, setConfig, errors, setErrors } = useDeployEditContext(); useEffect(() => { - if (!data.id) { - setDeploy({ - ...data, - config: { - domain: "", - }, + if (!config.id) { + setConfig({ + ...config, + config: {}, }); } }, []); useEffect(() => { - setError({}); + setErrors({}); }, []); const formSchema = z.object({ @@ -34,12 +36,12 @@ const DeployToQiniuCDN = () => { }); useEffect(() => { - const res = formSchema.safeParse(data.config); - setError({ - ...error, + const res = formSchema.safeParse(config.config); + setErrors({ + ...errors, domain: res.error?.errors?.find((e) => e.path[0] === "domain")?.message, }); - }, [data]); + }, [config]); return (
@@ -48,16 +50,16 @@ const DeployToQiniuCDN = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.domain = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.domain}
+
{errors?.domain}
); diff --git a/ui/src/components/certimate/DeployToSSH.tsx b/ui/src/components/certimate/DeployToSSH.tsx index 74d37e33..8db0cde5 100644 --- a/ui/src/components/certimate/DeployToSSH.tsx +++ b/ui/src/components/certimate/DeployToSSH.tsx @@ -9,24 +9,32 @@ import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectVa import { Textarea } from "@/components/ui/textarea"; import { useDeployEditContext } from "./DeployEdit"; +type DeployToSSHConfigParams = { + format?: string; + certPath?: string; + keyPath?: string; + pfxPassword?: string; + jksAlias?: string; + jksKeypass?: string; + jksStorepass?: string; + shell?: string; + preCommand?: string; + command?: string; +}; + const DeployToSSH = () => { const { t } = useTranslation(); - const { deploy: data, setDeploy, error, setError } = useDeployEditContext(); + const { config, setConfig, errors, setErrors } = useDeployEditContext(); useEffect(() => { - if (!data.id) { - setDeploy({ - ...data, + if (!config.id) { + setConfig({ + ...config, config: { format: "pem", certPath: "/etc/nginx/ssl/nginx.crt", keyPath: "/etc/nginx/ssl/nginx.key", - pfxPassword: "", - jksAlias: "", - jksKeypass: "", - jksStorepass: "", - preCommand: "", command: "sudo service nginx reload", }, }); @@ -34,7 +42,7 @@ const DeployToSSH = () => { }, []); useEffect(() => { - setError({}); + setErrors({}); }, []); const formSchema = z @@ -79,9 +87,9 @@ const DeployToSSH = () => { }); useEffect(() => { - const res = formSchema.safeParse(data.config); - setError({ - ...error, + const res = formSchema.safeParse(config.config); + setErrors({ + ...errors, format: res.error?.errors?.find((e) => e.path[0] === "format")?.message, certPath: res.error?.errors?.find((e) => e.path[0] === "certPath")?.message, keyPath: res.error?.errors?.find((e) => e.path[0] === "keyPath")?.message, @@ -92,35 +100,38 @@ const DeployToSSH = () => { preCommand: res.error?.errors?.find((e) => e.path[0] === "preCommand")?.message, command: res.error?.errors?.find((e) => e.path[0] === "command")?.message, }); - }, [data]); + }, [config]); useEffect(() => { - if (data.config?.format === "pem") { - if (/(.pfx|.jks)$/.test(data.config.certPath)) { - const newData = produce(data, (draft) => { - draft.config ??= {}; - draft.config.certPath = data.config!.certPath.replace(/(.pfx|.jks)$/, ".crt"); - }); - setDeploy(newData); + if (config.config?.format === "pem") { + if (/(.pfx|.jks)$/.test(config.config.certPath!)) { + setConfig( + produce(config, (draft) => { + draft.config ??= {}; + draft.config.certPath = config.config!.certPath!.replace(/(.pfx|.jks)$/, ".crt"); + }) + ); } - } else if (data.config?.format === "pfx") { - if (/(.crt|.jks)$/.test(data.config.certPath)) { - const newData = produce(data, (draft) => { - draft.config ??= {}; - draft.config.certPath = data.config!.certPath.replace(/(.crt|.jks)$/, ".pfx"); - }); - setDeploy(newData); + } else if (config.config?.format === "pfx") { + if (/(.crt|.jks)$/.test(config.config.certPath!)) { + setConfig( + produce(config, (draft) => { + draft.config ??= {}; + draft.config.certPath = config.config!.certPath!.replace(/(.crt|.jks)$/, ".pfx"); + }) + ); } - } else if (data.config?.format === "jks") { - if (/(.crt|.pfx)$/.test(data.config.certPath)) { - const newData = produce(data, (draft) => { - draft.config ??= {}; - draft.config.certPath = data.config!.certPath.replace(/(.crt|.pfx)$/, ".jks"); - }); - setDeploy(newData); + } else if (config.config?.format === "jks") { + if (/(.crt|.pfx)$/.test(config.config.certPath!)) { + setConfig( + produce(config, (draft) => { + draft.config ??= {}; + draft.config.certPath = config.config!.certPath!.replace(/(.crt|.pfx)$/, ".jks"); + }) + ); } } - }, [data.config?.format]); + }, [config.config?.format]); return ( <> @@ -128,13 +139,13 @@ const DeployToSSH = () => {
-
{error?.format}
+
{errors?.format}
@@ -156,77 +167,77 @@ const DeployToSSH = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.certPath = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.certPath}
+
{errors?.certPath}
- {data.config?.format === "pem" ? ( + {config.config?.format === "pem" ? (
{ - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.keyPath = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.keyPath}
+
{errors?.keyPath}
) : ( <> )} - {data.config?.format === "pfx" ? ( + {config.config?.format === "pfx" ? (
{ - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.pfxPassword = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.pfxPassword}
+
{errors?.pfxPassword}
) : ( <> )} - {data.config?.format === "jks" ? ( + {config.config?.format === "jks" ? ( <>
{ - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.jksAlias = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.jksAlias}
+
{errors?.jksAlias}
@@ -234,16 +245,16 @@ const DeployToSSH = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.jksKeypass = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.jksKeypass}
+
{errors?.jksKeypass}
@@ -251,16 +262,16 @@ const DeployToSSH = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.jksStorepass = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.jksStorepass}
+
{errors?.jksStorepass}
) : ( @@ -271,34 +282,34 @@ const DeployToSSH = () => { -
{error?.preCommand}
+
{errors?.preCommand}
-
{error?.command}
+
{errors?.command}
diff --git a/ui/src/components/certimate/DeployToTencentCDN.tsx b/ui/src/components/certimate/DeployToTencentCDN.tsx index 63f2c7ef..fff3d9b5 100644 --- a/ui/src/components/certimate/DeployToTencentCDN.tsx +++ b/ui/src/components/certimate/DeployToTencentCDN.tsx @@ -7,24 +7,26 @@ import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { useDeployEditContext } from "./DeployEdit"; +type DeployToTencentCDNParams = { + domain?: string; +}; + const DeployToTencentCDN = () => { const { t } = useTranslation(); - const { deploy: data, setDeploy, error, setError } = useDeployEditContext(); + const { config, setConfig, errors, setErrors } = useDeployEditContext(); useEffect(() => { - if (!data.id) { - setDeploy({ - ...data, - config: { - domain: "", - }, + if (!config.id) { + setConfig({ + ...config, + config: {}, }); } }, []); useEffect(() => { - setError({}); + setErrors({}); }, []); const formSchema = z.object({ @@ -34,12 +36,12 @@ const DeployToTencentCDN = () => { }); useEffect(() => { - const res = formSchema.safeParse(data.config); - setError({ - ...error, + const res = formSchema.safeParse(config.config); + setErrors({ + ...errors, domain: res.error?.errors?.find((e) => e.path[0] === "domain")?.message, }); - }, [data]); + }, [config]); return (
@@ -48,16 +50,16 @@ const DeployToTencentCDN = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.domain = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.domain}
+
{errors?.domain}
); diff --git a/ui/src/components/certimate/DeployToTencentCLB.tsx b/ui/src/components/certimate/DeployToTencentCLB.tsx index a3828a78..c9ab56ff 100644 --- a/ui/src/components/certimate/DeployToTencentCLB.tsx +++ b/ui/src/components/certimate/DeployToTencentCLB.tsx @@ -8,28 +8,32 @@ import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { useDeployEditContext } from "./DeployEdit"; +type DeployToTencentCLBParams = { + region?: string; + resourceType?: string; + loadbalancerId?: string; + listenerId?: string; + domain?: string; +}; + const DeployToTencentCLB = () => { const { t } = useTranslation(); - const { deploy: data, setDeploy, error, setError } = useDeployEditContext(); + const { config, setConfig, errors, setErrors } = useDeployEditContext(); useEffect(() => { - if (!data.id) { - setDeploy({ - ...data, + if (!config.id) { + setConfig({ + ...config, config: { region: "ap-guangzhou", - resourceType: "", - loadbalancerId: "", - listenerId: "", - domain: "", }, }); } }, []); useEffect(() => { - setError({}); + setErrors({}); }, []); const formSchema = z @@ -65,16 +69,16 @@ const DeployToTencentCLB = () => { }); useEffect(() => { - const res = formSchema.safeParse(data.config); - setError({ - ...error, + const res = formSchema.safeParse(config.config); + setErrors({ + ...errors, 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]); + }, [config]); return (
@@ -83,28 +87,28 @@ const DeployToTencentCLB = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.region = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.region}
+
{errors?.region}
-
{error?.resourceType}
+
{errors?.resourceType}
@@ -127,76 +131,76 @@ const DeployToTencentCLB = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.loadbalancerId = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.loadbalancerId}
+
{errors?.loadbalancerId}
- {data?.config?.resourceType === "ssl-deploy" || data?.config?.resourceType === "listener" || data?.config?.resourceType === "ruledomain" ? ( + {config?.config?.resourceType === "ssl-deploy" || config?.config?.resourceType === "listener" || config?.config?.resourceType === "ruledomain" ? (
{ - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.listenerId = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.listenerId}
+
{errors?.listenerId}
) : ( <> )} - {data?.config?.resourceType === "ssl-deploy" ? ( + {config?.config?.resourceType === "ssl-deploy" ? (
{ - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.domain = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.domain}
+
{errors?.domain}
) : ( <> )} - {data?.config?.resourceType === "ruledomain" ? ( + {config?.config?.resourceType === "ruledomain" ? (
{ - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.domain = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.domain}
+
{errors?.domain}
) : ( <> diff --git a/ui/src/components/certimate/DeployToTencentCOS.tsx b/ui/src/components/certimate/DeployToTencentCOS.tsx index f95eb778..b045fb22 100644 --- a/ui/src/components/certimate/DeployToTencentCOS.tsx +++ b/ui/src/components/certimate/DeployToTencentCOS.tsx @@ -7,26 +7,30 @@ import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { useDeployEditContext } from "./DeployEdit"; +type DeployToTencentCOSParams = { + region?: string; + bucket?: string; + domain?: string; +}; + const DeployToTencentCOS = () => { const { t } = useTranslation(); - const { deploy: data, setDeploy, error, setError } = useDeployEditContext(); + const { config, setConfig, errors, setErrors } = useDeployEditContext(); useEffect(() => { - if (!data.id) { - setDeploy({ - ...data, + if (!config.id) { + setConfig({ + ...config, config: { region: "ap-guangzhou", - bucket: "", - domain: "", }, }); } }, []); useEffect(() => { - setError({}); + setErrors({}); }, []); const formSchema = z.object({ @@ -38,14 +42,14 @@ const DeployToTencentCOS = () => { }); useEffect(() => { - const res = formSchema.safeParse(data.config); - setError({ - ...error, + const res = formSchema.safeParse(config.config); + setErrors({ + ...errors, region: res.error?.errors?.find((e) => e.path[0] === "region")?.message, bucket: res.error?.errors?.find((e) => e.path[0] === "bucket")?.message, domain: res.error?.errors?.find((e) => e.path[0] === "domain")?.message, }); - }, [data]); + }, [config]); return (
@@ -54,16 +58,16 @@ const DeployToTencentCOS = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.region = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.region}
+
{errors?.region}
@@ -71,16 +75,16 @@ const DeployToTencentCOS = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.bucket = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.bucket}
+
{errors?.bucket}
@@ -88,16 +92,16 @@ const DeployToTencentCOS = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.domain = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.domain}
+
{errors?.domain}
); diff --git a/ui/src/components/certimate/DeployToTencentTEO.tsx b/ui/src/components/certimate/DeployToTencentTEO.tsx index 6b90c55c..56de4d68 100644 --- a/ui/src/components/certimate/DeployToTencentTEO.tsx +++ b/ui/src/components/certimate/DeployToTencentTEO.tsx @@ -8,24 +8,27 @@ import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { useDeployEditContext } from "./DeployEdit"; +type DeployToTencentTEOParams = { + zoneId?: string; + domain?: string; +}; + const DeployToTencentTEO = () => { const { t } = useTranslation(); - const { deploy: data, setDeploy, error, setError } = useDeployEditContext(); + const { config, setConfig, errors, setErrors } = useDeployEditContext(); useEffect(() => { - if (!data.id) { - setDeploy({ - ...data, - config: { - zoneId: "", - }, + if (!config.id) { + setConfig({ + ...config, + config: {}, }); } }, []); useEffect(() => { - setError({}); + setErrors({}); }, []); const formSchema = z.object({ @@ -36,13 +39,13 @@ const DeployToTencentTEO = () => { }); useEffect(() => { - const res = formSchema.safeParse(data.config); - setError({ - ...error, + const res = formSchema.safeParse(config.config); + setErrors({ + ...errors, zoneId: res.error?.errors?.find((e) => e.path[0] === "zoneId")?.message, domain: res.error?.errors?.find((e) => e.path[0] === "domain")?.message, }); - }, [data]); + }, [config]); return (
@@ -51,16 +54,16 @@ const DeployToTencentTEO = () => { { - const newData = produce(data, (draft) => { + const nv = produce(config, (draft) => { draft.config ??= {}; draft.config.zoneId = e.target.value?.trim(); }); - setDeploy(newData); + setConfig(nv); }} /> -
{error?.zoneId}
+
{errors?.zoneId}
@@ -68,16 +71,16 @@ const DeployToTencentTEO = () => {