diff --git a/go.mod b/go.mod index bca64be5..ee794b86 100644 --- a/go.mod +++ b/go.mod @@ -30,6 +30,7 @@ require ( github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible github.com/aws/aws-sdk-go-v2/service/acm v1.32.0 github.com/aws/aws-sdk-go-v2/service/cloudfront v1.46.1 + github.com/aws/aws-sdk-go-v2/service/iam v1.42.0 github.com/baidubce/bce-sdk-go v0.9.228 github.com/blinkbean/dingtalk v1.1.3 github.com/byteplus-sdk/byteplus-sdk-golang v1.0.46 @@ -51,6 +52,7 @@ require ( github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1155 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1166 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1173 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/gaap v1.0.1163 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1150 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1172 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.1169 @@ -85,7 +87,6 @@ require ( github.com/alibabacloud-go/tea-oss-utils v1.1.0 // indirect github.com/alibabacloud-go/tea-utils/v2 v2.0.7 // indirect github.com/avast/retry-go v3.0.0+incompatible // indirect - github.com/aws/aws-sdk-go-v2/service/iam v1.42.0 // indirect github.com/aws/aws-sdk-go-v2/service/route53 v1.50.0 // indirect github.com/buger/goterm v1.0.4 // indirect github.com/diskfs/go-diskfs v1.5.0 // indirect diff --git a/go.sum b/go.sum index 404e21e4..eb4dc407 100644 --- a/go.sum +++ b/go.sum @@ -836,6 +836,7 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1166/go.mod h1 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1128/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1150/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1155/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1163/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1164/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1166/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1169/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= @@ -845,6 +846,8 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1173 h1:W5b github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1173/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1128 h1:mrJ5Fbkd7sZIJ5F6oRfh5zebPQaudPH9Y0+GUmFytYU= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1128/go.mod h1:zbsYIBT+VTX4z4ocjTAdLBIWyNYj3z0BRqd0iPdnjsk= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/gaap v1.0.1163 h1:putqrH5n1SVRqFWHOylVqYI5yLQUjRTkHqZPLT2yeVY= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/gaap v1.0.1163/go.mod h1:aEWRXlAvovPUUoS3kVB/LVWEQ19WqzTj2lXGvR1YArY= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1150 h1:RQQYfZOFYlkxKR2+xp8el3+8xs9DhxBy+ajlHtapqtQ= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/live v1.0.1150/go.mod h1:zpfr6EBWy7ClASTGUgIy01Gn4R79UXf+2QGQeyR124A= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/scf v1.0.1172 h1:6SUO0hTie3zxnUEMxmhnS1iRIXpAukSZV27Nrx4NwIk= diff --git a/internal/deployer/providers.go b/internal/deployer/providers.go index 06239710..e4467a40 100644 --- a/internal/deployer/providers.go +++ b/internal/deployer/providers.go @@ -73,6 +73,7 @@ import ( pTencentCloudCSS "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-css" pTencentCloudECDN "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-ecdn" pTencentCloudEO "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-eo" + pTencentCloudGAAP "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-gaap" pTencentCloudSCF "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-scf" pTencentCloudSSL "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-ssl" pTencentCloudSSLDeploy "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-ssl-deploy" @@ -1030,7 +1031,7 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer return deployer, err } - case domain.DeploymentProviderTypeTencentCloudCDN, domain.DeploymentProviderTypeTencentCloudCLB, domain.DeploymentProviderTypeTencentCloudCOS, domain.DeploymentProviderTypeTencentCloudCSS, domain.DeploymentProviderTypeTencentCloudECDN, domain.DeploymentProviderTypeTencentCloudEO, domain.DeploymentProviderTypeTencentCloudSCF, domain.DeploymentProviderTypeTencentCloudSSL, domain.DeploymentProviderTypeTencentCloudSSLDeploy, domain.DeploymentProviderTypeTencentCloudVOD, domain.DeploymentProviderTypeTencentCloudWAF: + case domain.DeploymentProviderTypeTencentCloudCDN, domain.DeploymentProviderTypeTencentCloudCLB, domain.DeploymentProviderTypeTencentCloudCOS, domain.DeploymentProviderTypeTencentCloudCSS, domain.DeploymentProviderTypeTencentCloudECDN, domain.DeploymentProviderTypeTencentCloudEO, domain.DeploymentProviderTypeTencentCloudGAAP, domain.DeploymentProviderTypeTencentCloudSCF, domain.DeploymentProviderTypeTencentCloudSSL, domain.DeploymentProviderTypeTencentCloudSSLDeploy, domain.DeploymentProviderTypeTencentCloudVOD, domain.DeploymentProviderTypeTencentCloudWAF: { access := domain.AccessConfigForTencentCloud{} if err := maputil.Populate(options.ProviderAccessConfig, &access); err != nil { @@ -1093,6 +1094,16 @@ func createDeployerProvider(options *deployerProviderOptions) (deployer.Deployer }) return deployer, err + case domain.DeploymentProviderTypeTencentCloudGAAP: + deployer, err := pTencentCloudGAAP.NewDeployer(&pTencentCloudGAAP.DeployerConfig{ + SecretId: access.SecretId, + SecretKey: access.SecretKey, + ResourceType: pTencentCloudGAAP.ResourceType(maputil.GetString(options.ProviderServiceConfig, "resourceType")), + ProxyId: maputil.GetString(options.ProviderServiceConfig, "proxyId"), + ListenerId: maputil.GetString(options.ProviderServiceConfig, "listenerId"), + }) + return deployer, err + case domain.DeploymentProviderTypeTencentCloudSCF: deployer, err := pTencentCloudSCF.NewDeployer(&pTencentCloudSCF.DeployerConfig{ SecretId: access.SecretId, diff --git a/internal/domain/provider.go b/internal/domain/provider.go index 560b08da..e0ace3ac 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -242,6 +242,7 @@ const ( DeploymentProviderTypeTencentCloudCSS = DeploymentProviderType(AccessProviderTypeTencentCloud + "-css") DeploymentProviderTypeTencentCloudECDN = DeploymentProviderType(AccessProviderTypeTencentCloud + "-ecdn") DeploymentProviderTypeTencentCloudEO = DeploymentProviderType(AccessProviderTypeTencentCloud + "-eo") + DeploymentProviderTypeTencentCloudGAAP = DeploymentProviderType(AccessProviderTypeTencentCloud + "-gaap") DeploymentProviderTypeTencentCloudSCF = DeploymentProviderType(AccessProviderTypeTencentCloud + "-scf") DeploymentProviderTypeTencentCloudSSL = DeploymentProviderType(AccessProviderTypeTencentCloud + "-ssl") DeploymentProviderTypeTencentCloudSSLDeploy = DeploymentProviderType(AccessProviderTypeTencentCloud + "-ssldeploy") diff --git a/internal/pkg/core/deployer/providers/tencentcloud-gaap/consts.go b/internal/pkg/core/deployer/providers/tencentcloud-gaap/consts.go new file mode 100644 index 00000000..37a8a94a --- /dev/null +++ b/internal/pkg/core/deployer/providers/tencentcloud-gaap/consts.go @@ -0,0 +1,8 @@ +package tencentcloudgaap + +type ResourceType string + +const ( + // 资源类型:部署到指定监听器。 + RESOURCE_TYPE_LISTENER = ResourceType("listener") +) diff --git a/internal/pkg/core/deployer/providers/tencentcloud-gaap/tencentcloud_gaap.go b/internal/pkg/core/deployer/providers/tencentcloud-gaap/tencentcloud_gaap.go new file mode 100644 index 00000000..2cc076f0 --- /dev/null +++ b/internal/pkg/core/deployer/providers/tencentcloud-gaap/tencentcloud_gaap.go @@ -0,0 +1,154 @@ +package tencentcloudgaap + +import ( + "context" + "errors" + "fmt" + "log/slog" + + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile" + tcgaap "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/gaap/v20180529" + + "github.com/usual2970/certimate/internal/pkg/core/deployer" + "github.com/usual2970/certimate/internal/pkg/core/uploader" + uploadersp "github.com/usual2970/certimate/internal/pkg/core/uploader/providers/tencentcloud-ssl" + typeutil "github.com/usual2970/certimate/internal/pkg/utils/type" +) + +type DeployerConfig struct { + // 腾讯云 SecretId。 + SecretId string `json:"secretId"` + // 腾讯云 SecretKey。 + SecretKey string `json:"secretKey"` + // 部署资源类型。 + ResourceType ResourceType `json:"resourceType"` + // 通道 ID。 + // 选填。 + ProxyId string `json:"proxyId,omitempty"` + // 负载均衡监听 ID。 + // 部署资源类型为 [RESOURCE_TYPE_LISTENER] 时必填。 + ListenerId string `json:"listenerId,omitempty"` +} + +type DeployerProvider struct { + config *DeployerConfig + logger *slog.Logger + sdkClient *tcgaap.Client + sslUploader uploader.Uploader +} + +var _ deployer.Deployer = (*DeployerProvider)(nil) + +func NewDeployer(config *DeployerConfig) (*DeployerProvider, error) { + if config == nil { + panic("config is nil") + } + + client, err := createSdkClients(config.SecretId, config.SecretKey) + if err != nil { + return nil, fmt.Errorf("failed to create sdk client: %w", err) + } + + uploader, err := uploadersp.NewUploader(&uploadersp.UploaderConfig{ + SecretId: config.SecretId, + SecretKey: config.SecretKey, + }) + if err != nil { + return nil, fmt.Errorf("failed to create ssl uploader: %w", err) + } + + return &DeployerProvider{ + config: config, + logger: slog.Default(), + sdkClient: client, + sslUploader: uploader, + }, nil +} + +func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer { + if logger == nil { + d.logger = slog.New(slog.DiscardHandler) + } else { + d.logger = logger + } + d.sslUploader.WithLogger(logger) + return d +} + +func (d *DeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*deployer.DeployResult, error) { + // 上传证书到 SSL + upres, err := d.sslUploader.Upload(ctx, certPEM, privkeyPEM) + if err != nil { + return nil, fmt.Errorf("failed to upload certificate file: %w", err) + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) + } + + // 根据部署资源类型决定部署方式 + switch d.config.ResourceType { + case RESOURCE_TYPE_LISTENER: + if err := d.deployToListener(ctx, upres.CertId); err != nil { + return nil, err + } + + default: + return nil, fmt.Errorf("unsupported resource type '%s'", d.config.ResourceType) + } + + return &deployer.DeployResult{}, nil +} + +func (d *DeployerProvider) deployToListener(ctx context.Context, cloudCertId string) error { + if d.config.ListenerId == "" { + return errors.New("config `listenerId` is required") + } + + // 更新监听器证书 + if err := d.modifyHttpsListenerCertificate(ctx, d.config.ListenerId, cloudCertId); err != nil { + return err + } + + return nil +} + +func (d *DeployerProvider) modifyHttpsListenerCertificate(ctx context.Context, cloudListenerId, cloudCertId string) error { + // 查询 HTTPS 监听器信息 + // REF: https://cloud.tencent.com/document/product/608/37001 + describeHTTPSListenersReq := tcgaap.NewDescribeHTTPSListenersRequest() + describeHTTPSListenersReq.ListenerId = common.StringPtr(cloudListenerId) + describeHTTPSListenersReq.Offset = common.Uint64Ptr(0) + describeHTTPSListenersReq.Limit = common.Uint64Ptr(1) + describeHTTPSListenersResp, err := d.sdkClient.DescribeHTTPSListeners(describeHTTPSListenersReq) + d.logger.Debug("sdk request 'gaap.DescribeHTTPSListeners'", slog.Any("request", describeHTTPSListenersReq), slog.Any("response", describeHTTPSListenersResp)) + if err != nil { + return fmt.Errorf("failed to execute sdk request 'gaap.DescribeHTTPSListeners': %w", err) + } else if len(describeHTTPSListenersResp.Response.ListenerSet) == 0 { + return errors.New("listener not found") + } + + // 修改 HTTPS 监听器配置 + // REF: https://cloud.tencent.com/document/product/608/36996 + modifyHTTPSListenerAttributeReq := tcgaap.NewModifyHTTPSListenerAttributeRequest() + modifyHTTPSListenerAttributeReq.ProxyId = typeutil.ToPtrOrZeroNil(d.config.ProxyId) + modifyHTTPSListenerAttributeReq.ListenerId = common.StringPtr(cloudListenerId) + modifyHTTPSListenerAttributeReq.CertificateId = common.StringPtr(cloudCertId) + modifyHTTPSListenerAttributeResp, err := d.sdkClient.ModifyHTTPSListenerAttribute(modifyHTTPSListenerAttributeReq) + d.logger.Debug("sdk request 'gaap.ModifyHTTPSListenerAttribute'", slog.Any("request", modifyHTTPSListenerAttributeReq), slog.Any("response", modifyHTTPSListenerAttributeResp)) + if err != nil { + return fmt.Errorf("failed to execute sdk request 'gaap.ModifyHTTPSListenerAttribute': %w", err) + } + + return nil +} + +func createSdkClients(secretId, secretKey string) (*tcgaap.Client, error) { + credential := common.NewCredential(secretId, secretKey) + + client, err := tcgaap.NewClient(credential, "", profile.NewClientProfile()) + if err != nil { + return nil, err + } + + return client, nil +} diff --git a/internal/pkg/core/deployer/providers/tencentcloud-gaap/tencentcloud_gaap_test.go b/internal/pkg/core/deployer/providers/tencentcloud-gaap/tencentcloud_gaap_test.go new file mode 100644 index 00000000..32943362 --- /dev/null +++ b/internal/pkg/core/deployer/providers/tencentcloud-gaap/tencentcloud_gaap_test.go @@ -0,0 +1,86 @@ +package tencentcloudgaap_test + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + "testing" + + provider "github.com/usual2970/certimate/internal/pkg/core/deployer/providers/tencentcloud-gaap" +) + +var ( + fInputCertPath string + fInputKeyPath string + fSecretId string + fSecretKey string + fProxyGroupId string + fProxyId string + fListenerId string +) + +func init() { + argsPrefix := "CERTIMATE_DEPLOYER_TENCENTCLOUDCDN_" + + flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "") + flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "") + flag.StringVar(&fSecretId, argsPrefix+"SECRETID", "", "") + flag.StringVar(&fSecretKey, argsPrefix+"SECRETKEY", "", "") + flag.StringVar(&fProxyGroupId, argsPrefix+"PROXYGROUPID", "", "") + flag.StringVar(&fProxyId, argsPrefix+"PROXYID", "", "") + flag.StringVar(&fListenerId, argsPrefix+"LISTENERID", "", "") +} + +/* +Shell command to run this test: + + go test -v ./tencentcloud_gaap_test.go -args \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDGAAP_INPUTCERTPATH="/path/to/your-input-cert.pem" \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDGAAP_INPUTKEYPATH="/path/to/your-input-key.pem" \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDGAAP_SECRETID="your-secret-id" \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDGAAP_SECRETKEY="your-secret-key" \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDGAAP_PROXYGROUPID="your-gaap-group-id" \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDGAAP_PROXYID="your-gaap-group-id" \ + --CERTIMATE_DEPLOYER_TENCENTCLOUDGAAP_LISTENERID="your-clb-listener-id" +*/ +func TestDeploy(t *testing.T) { + flag.Parse() + + t.Run("Deploy_ToListener", func(t *testing.T) { + t.Log(strings.Join([]string{ + "args:", + fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath), + fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath), + fmt.Sprintf("SECRETID: %v", fSecretId), + fmt.Sprintf("SECRETKEY: %v", fSecretKey), + fmt.Sprintf("PROXYGROUPID: %v", fProxyGroupId), + fmt.Sprintf("PROXYID: %v", fProxyId), + fmt.Sprintf("LISTENERID: %v", fListenerId), + }, "\n")) + + deployer, err := provider.NewDeployer(&provider.DeployerConfig{ + SecretId: fSecretId, + SecretKey: fSecretKey, + ResourceType: provider.RESOURCE_TYPE_LISTENER, + ProxyGroupId: fProxyGroupId, + ProxyId: fProxyId, + ListenerId: fListenerId, + }) + if err != nil { + t.Errorf("err: %+v", err) + return + } + + fInputCertData, _ := os.ReadFile(fInputCertPath) + fInputKeyData, _ := os.ReadFile(fInputKeyPath) + res, err := deployer.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData)) + if err != nil { + t.Errorf("err: %+v", err) + return + } + + t.Logf("ok: %v", res) + }) +} diff --git a/internal/workflow/node-processor/monitor_node.go b/internal/workflow/node-processor/monitor_node.go index d13e4247..8e3d3f87 100644 --- a/internal/workflow/node-processor/monitor_node.go +++ b/internal/workflow/node-processor/monitor_node.go @@ -100,7 +100,13 @@ func (n *monitorNode) Process(ctx context.Context) error { if validated { n.logger.Info(fmt.Sprintf("the certificate is valid, and will expire in %d day(s)", daysLeft)) } else { - n.logger.Warn(fmt.Sprintf("the certificate is invalid", validated)) + if !isCertHostMatched { + n.logger.Warn("the certificate is invalid, because it is not matched the host") + } else if !isCertPeriodValid { + n.logger.Warn("the certificate is invalid, because it is either expired or not yet valid") + } else { + n.logger.Warn("the certificate is invalid") + } } } } diff --git a/ui/src/components/provider/DeploymentProviderPicker.tsx b/ui/src/components/provider/DeploymentProviderPicker.tsx index bb569acd..9b441189 100644 --- a/ui/src/components/provider/DeploymentProviderPicker.tsx +++ b/ui/src/components/provider/DeploymentProviderPicker.tsx @@ -72,6 +72,7 @@ const DeploymentProviderPicker = ({ className, style, autoFocus, filter, placeho DEPLOYMENT_CATEGORIES.LOADBALANCE, DEPLOYMENT_CATEGORIES.FIREWALL, DEPLOYMENT_CATEGORIES.AV, + DEPLOYMENT_CATEGORIES.ACCELERATOR, DEPLOYMENT_CATEGORIES.APIGATEWAY, DEPLOYMENT_CATEGORIES.SERVERLESS, DEPLOYMENT_CATEGORIES.WEBSITE, diff --git a/ui/src/components/workflow/node/DeployNodeConfigForm.tsx b/ui/src/components/workflow/node/DeployNodeConfigForm.tsx index 96e50911..d9a34629 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigForm.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigForm.tsx @@ -77,6 +77,7 @@ import DeployNodeConfigFormTencentCloudCOSConfig from "./DeployNodeConfigFormTen import DeployNodeConfigFormTencentCloudCSSConfig from "./DeployNodeConfigFormTencentCloudCSSConfig.tsx"; import DeployNodeConfigFormTencentCloudECDNConfig from "./DeployNodeConfigFormTencentCloudECDNConfig.tsx"; import DeployNodeConfigFormTencentCloudEOConfig from "./DeployNodeConfigFormTencentCloudEOConfig.tsx"; +import DeployNodeConfigFormTencentCloudGAAPConfig from "./DeployNodeConfigFormTencentCloudGAAPConfig.tsx"; import DeployNodeConfigFormTencentCloudSCFConfig from "./DeployNodeConfigFormTencentCloudSCFConfig"; import DeployNodeConfigFormTencentCloudSSLDeployConfig from "./DeployNodeConfigFormTencentCloudSSLDeployConfig"; import DeployNodeConfigFormTencentCloudVODConfig from "./DeployNodeConfigFormTencentCloudVODConfig"; @@ -321,6 +322,8 @@ const DeployNodeConfigForm = forwardRef; case DEPLOYMENT_PROVIDERS.TENCENTCLOUD_EO: return ; + case DEPLOYMENT_PROVIDERS.TENCENTCLOUD_GAAP: + return ; case DEPLOYMENT_PROVIDERS.TENCENTCLOUD_SCF: return ; case DEPLOYMENT_PROVIDERS.TENCENTCLOUD_SSL_DEPLOY: diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunALBConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunALBConfig.tsx index bbfca5e6..341bfe6a 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunALBConfig.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunALBConfig.tsx @@ -26,7 +26,9 @@ const RESOURCE_TYPE_LOADBALANCER = "loadbalancer" as const; const RESOURCE_TYPE_LISTENER = "listener" as const; const initFormModel = (): DeployNodeConfigFormAliyunALBConfigFieldValues => { - return {}; + return { + resourceType: RESOURCE_TYPE_LISTENER, + }; }; const DeployNodeConfigFormAliyunALBConfig = ({ diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunCLBConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunCLBConfig.tsx index e666800e..fcd59569 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunCLBConfig.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunCLBConfig.tsx @@ -27,6 +27,7 @@ const RESOURCE_TYPE_LISTENER = "listener" as const; const initFormModel = (): DeployNodeConfigFormAliyunCLBConfigFieldValues => { return { + resourceType: RESOURCE_TYPE_LISTENER, listenerPort: 443, }; }; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunGAConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunGAConfig.tsx index 20dd1ae1..f90652f9 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunGAConfig.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunGAConfig.tsx @@ -25,7 +25,9 @@ const RESOURCE_TYPE_ACCELERATOR = "accelerator" as const; const RESOURCE_TYPE_LISTENER = "listener" as const; const initFormModel = (): DeployNodeConfigFormAliyunGAConfigFieldValues => { - return {}; + return { + resourceType: RESOURCE_TYPE_LISTENER, + }; }; const DeployNodeConfigFormAliyunGAConfig = ({ form: formInst, formName, disabled, initialValues, onValuesChange }: DeployNodeConfigFormAliyunGAConfigProps) => { diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunNLBConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunNLBConfig.tsx index c37b97db..abd95843 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunNLBConfig.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunNLBConfig.tsx @@ -24,7 +24,9 @@ const RESOURCE_TYPE_LOADBALANCER = "loadbalancer" as const; const RESOURCE_TYPE_LISTENER = "listener" as const; const initFormModel = (): DeployNodeConfigFormAliyunNLBConfigFieldValues => { - return {}; + return { + resourceType: RESOURCE_TYPE_LISTENER, + }; }; const DeployNodeConfigFormAliyunNLBConfig = ({ diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormBaiduCloudAppBLBConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormBaiduCloudAppBLBConfig.tsx index 875d254b..aba8bf6b 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigFormBaiduCloudAppBLBConfig.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigFormBaiduCloudAppBLBConfig.tsx @@ -27,6 +27,7 @@ const RESOURCE_TYPE_LISTENER = "listener" as const; const initFormModel = (): DeployNodeConfigFormBaiduCloudAppBLBConfigFieldValues => { return { + resourceType: RESOURCE_TYPE_LISTENER, listenerPort: 443, }; }; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormBaiduCloudBLBConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormBaiduCloudBLBConfig.tsx index 99c0b059..fd61053c 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigFormBaiduCloudBLBConfig.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigFormBaiduCloudBLBConfig.tsx @@ -27,6 +27,7 @@ const RESOURCE_TYPE_LISTENER = "listener" as const; const initFormModel = (): DeployNodeConfigFormBaiduCloudBLBConfigFieldValues => { return { + resourceType: RESOURCE_TYPE_LISTENER, listenerPort: 443, }; }; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormHuaweiCloudELBConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormHuaweiCloudELBConfig.tsx index 259e1f44..c3f17e2a 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigFormHuaweiCloudELBConfig.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigFormHuaweiCloudELBConfig.tsx @@ -26,7 +26,9 @@ const RESOURCE_TYPE_LOADBALANCER = "loadbalancer" as const; const RESOURCE_TYPE_LISTENER = "listener" as const; const initFormModel = (): DeployNodeConfigFormHuaweiCloudELBConfigFieldValues => { - return {}; + return { + resourceType: RESOURCE_TYPE_LISTENER, + }; }; const DeployNodeConfigFormHuaweiCloudELBConfig = ({ diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormJDCloudALBConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormJDCloudALBConfig.tsx index 22c5bf08..f9cfd937 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigFormJDCloudALBConfig.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigFormJDCloudALBConfig.tsx @@ -26,7 +26,9 @@ const RESOURCE_TYPE_LOADBALANCER = "loadbalancer" as const; const RESOURCE_TYPE_LISTENER = "listener" as const; const initFormModel = (): DeployNodeConfigFormJDCloudALBConfigFieldValues => { - return {}; + return { + resourceType: RESOURCE_TYPE_LISTENER, + }; }; const DeployNodeConfigFormJDCloudALBConfig = ({ diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudCLBConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudCLBConfig.tsx index 760c6fac..cd06dbd7 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudCLBConfig.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudCLBConfig.tsx @@ -29,7 +29,7 @@ const RESOURCE_TYPE_RULEDOMAIN = "ruledomain" as const; const initFormModel = (): DeployNodeConfigFormTencentCloudCLBConfigFieldValues => { return { - resourceType: RESOURCE_TYPE_VIA_SSLDEPLOY, + resourceType: RESOURCE_TYPE_LISTENER, }; }; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudGAAPConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudGAAPConfig.tsx new file mode 100644 index 00000000..1f443cdf --- /dev/null +++ b/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudGAAPConfig.tsx @@ -0,0 +1,100 @@ +import { useTranslation } from "react-i18next"; +import { Form, type FormInstance, Input, Select } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod"; + +import Show from "@/components/Show"; + +type DeployNodeConfigFormTencentCloudGAAPConfigFieldValues = Nullish<{ + resourceType: string; + proxyId?: string; + listenerId?: string; +}>; + +export type DeployNodeConfigFormTencentCloudGAAPConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: DeployNodeConfigFormTencentCloudGAAPConfigFieldValues; + onValuesChange?: (values: DeployNodeConfigFormTencentCloudGAAPConfigFieldValues) => void; +}; + +const RESOURCE_TYPE_LISTENER = "listener" as const; + +const initFormModel = (): DeployNodeConfigFormTencentCloudGAAPConfigFieldValues => { + return { + resourceType: RESOURCE_TYPE_LISTENER, + listenerId: "", + }; +}; + +const DeployNodeConfigFormTencentCloudGAAPConfig = ({ + form: formInst, + formName, + disabled, + initialValues, + onValuesChange, +}: DeployNodeConfigFormTencentCloudGAAPConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + resourceType: z.literal(RESOURCE_TYPE_LISTENER, { message: t("workflow_node.deploy.form.tencentcloud_gaap_resource_type.placeholder") }), + proxyId: z.string().trim().nullish(), + listenerId: z + .string() + .trim() + .nullish() + .refine( + (v) => ![RESOURCE_TYPE_LISTENER].includes(fieldResourceType) || !!v?.trim(), + t("workflow_node.deploy.form.tencentcloud_gaap_listener_id.placeholder") + ), + }); + const formRule = createSchemaFieldRule(formSchema); + + const fieldResourceType = Form.useWatch("resourceType", formInst); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ + + + + } + > + + + + + } + > + + + +
+ ); +}; + +export default DeployNodeConfigFormTencentCloudGAAPConfig; diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts index c74a13ba..d57cc380 100644 --- a/ui/src/domain/provider.ts +++ b/ui/src/domain/provider.ts @@ -436,6 +436,7 @@ export const DEPLOYMENT_PROVIDERS = Object.freeze({ TENCENTCLOUD_CSS: `${ACCESS_PROVIDERS.TENCENTCLOUD}-css`, TENCENTCLOUD_ECDN: `${ACCESS_PROVIDERS.TENCENTCLOUD}-ecdn`, TENCENTCLOUD_EO: `${ACCESS_PROVIDERS.TENCENTCLOUD}-eo`, + TENCENTCLOUD_GAAP: `${ACCESS_PROVIDERS.TENCENTCLOUD}-gaap`, TENCENTCLOUD_SCF: `${ACCESS_PROVIDERS.TENCENTCLOUD}-scf`, TENCENTCLOUD_SSL: `${ACCESS_PROVIDERS.TENCENTCLOUD}-ssl`, TENCENTCLOUD_SSL_DEPLOY: `${ACCESS_PROVIDERS.TENCENTCLOUD}-ssldeploy`, @@ -469,6 +470,7 @@ export const DEPLOYMENT_CATEGORIES = Object.freeze({ LOADBALANCE: "loadbalance", FIREWALL: "firewall", AV: "av", + ACCELERATOR: "accelerator", APIGATEWAY: "apigw", SERVERLESS: "serverless", WEBSITE: "website", @@ -511,7 +513,7 @@ export const deploymentProvidersMap: Maphttps://console.tencentcloud.com/edgeone", + "workflow_node.deploy.form.tencentcloud_gaap_resource_type.label": "Resource type", + "workflow_node.deploy.form.tencentcloud_gaap_resource_type.placeholder": "Please select resource type", + "workflow_node.deploy.form.tencentcloud_gaap_resource_type.option.listener.label": "GAAP listener", + "workflow_node.deploy.form.tencentcloud_gaap_proxy_id.label": "Tencent Cloud GAAP proxy ID (Optional)", + "workflow_node.deploy.form.tencentcloud_gaap_proxy_id.placeholder": "Please enter Tencent Cloud GAAP proxy ID", + "workflow_node.deploy.form.tencentcloud_gaap_proxy_id.tooltip": "For more information, see https://console.cloud.tencent.com/gaap", + "workflow_node.deploy.form.tencentcloud_gaap_listener_id.label": "Tencent Cloud GAAP listener ID", + "workflow_node.deploy.form.tencentcloud_gaap_listener_id.placeholder": "Please enter Tencent Cloud GAAP listener ID", + "workflow_node.deploy.form.tencentcloud_gaap_listener_id.tooltip": "For more information, see https://console.cloud.tencent.com/gaap", "workflow_node.deploy.form.tencentcloud_scf_region.label": "Tencent Cloud SCF region", "workflow_node.deploy.form.tencentcloud_scf_region.placeholder": "Please enter Tencent Cloud SCF region (e.g. ap-guangzhou)", "workflow_node.deploy.form.tencentcloud_scf_region.tooltip": "For more information, see https://www.tencentcloud.com/document/product/583/17299", diff --git a/ui/src/i18n/locales/zh/nls.access.json b/ui/src/i18n/locales/zh/nls.access.json index cbf0c7db..b4cc3846 100644 --- a/ui/src/i18n/locales/zh/nls.access.json +++ b/ui/src/i18n/locales/zh/nls.access.json @@ -398,8 +398,8 @@ "access.form.sslcom_eab_kid.label": "ACME EAB KID", "access.form.sslcom_eab_kid.placeholder": "请输入 ACME EAB KID", "access.form.sslcom_eab_kid.tooltip": "这是什么?请参阅 https://www.ssl.com/how-to/generate-acme-credentials-for-reseller-customers/", - "access.form.sslcom_eab_hmac_key.label": "ACME EAB HMAC key", - "access.form.sslcom_eab_hmac_key.placeholder": "请输入 ACME EAB HMAC key", + "access.form.sslcom_eab_hmac_key.label": "ACME EAB HMAC Key", + "access.form.sslcom_eab_hmac_key.placeholder": "请输入 ACME EAB HMAC Key", "access.form.sslcom_eab_hmac_key.tooltip": "这是什么?请参阅 https://www.ssl.com/how-to/generate-acme-credentials-for-reseller-customers/", "access.form.telegrambot_token.label": "Telegram 机器人 API Token", "access.form.telegrambot_token.placeholder": "请输入 Telegram 机器人 API Token", diff --git a/ui/src/i18n/locales/zh/nls.provider.json b/ui/src/i18n/locales/zh/nls.provider.json index 79af14fc..a5ff9e05 100644 --- a/ui/src/i18n/locales/zh/nls.provider.json +++ b/ui/src/i18n/locales/zh/nls.provider.json @@ -132,6 +132,7 @@ "provider.tencentcloud.dns": "腾讯云 - 云解析 DNS", "provider.tencentcloud.ecdn": "腾讯云 - 全站加速网络 ECDN", "provider.tencentcloud.eo": "腾讯云 - 边缘安全加速平台 EdgeOne", + "provider.tencentcloud.gaap": "腾讯云 - 全球应用加速 GAAP", "provider.tencentcloud.scf": "腾讯云 - 云函数 SCF", "provider.tencentcloud.ssl_upload": "腾讯云 - 上传到 SSL 证书服务", "provider.tencentcloud.ssl_deploy": "腾讯云 - 通过 SSL 证书服务创建部署任务", @@ -172,6 +173,7 @@ "provider.category.loadbalance": "负载均衡", "provider.category.firewall": "防火墙", "provider.category.av": "音视频", + "provider.category.accelerator": "加速器", "provider.category.apigw": "API 网关", "provider.category.serverless": "Serverless", "provider.category.website": "网站托管", diff --git a/ui/src/i18n/locales/zh/nls.workflow.nodes.json b/ui/src/i18n/locales/zh/nls.workflow.nodes.json index a27ec30a..df6b0a1b 100644 --- a/ui/src/i18n/locales/zh/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/zh/nls.workflow.nodes.json @@ -669,6 +669,15 @@ "workflow_node.deploy.form.tencentcloud_eo_domain.label": "腾讯云 EdgeOne 加速域名", "workflow_node.deploy.form.tencentcloud_eo_domain.placeholder": "请输入腾讯云 EdgeOne 加速域名", "workflow_node.deploy.form.tencentcloud_eo_domain.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/edgeone", + "workflow_node.deploy.form.tencentcloud_gaap_resource_type.label": "证书部署方式", + "workflow_node.deploy.form.tencentcloud_gaap_resource_type.placeholder": "请选择证书部署方式", + "workflow_node.deploy.form.tencentcloud_gaap_resource_type.option.listener.label": "替换指定监听器的证书", + "workflow_node.deploy.form.tencentcloud_gaap_proxy_id.label": "腾讯云 GAAP 通道 ID(可选)", + "workflow_node.deploy.form.tencentcloud_gaap_proxy_id.placeholder": "请输入腾讯云 GAAP 通道 ID", + "workflow_node.deploy.form.tencentcloud_gaap_proxy_id.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/gaap", + "workflow_node.deploy.form.tencentcloud_gaap_listener_id.label": "腾讯云 GAAP 监听器 ID", + "workflow_node.deploy.form.tencentcloud_gaap_listener_id.placeholder": "请输入腾讯云 GAAP 监听器 ID", + "workflow_node.deploy.form.tencentcloud_gaap_listener_id.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/gaap", "workflow_node.deploy.form.tencentcloud_scf_region.label": "腾讯云 SCF 产品地域", "workflow_node.deploy.form.tencentcloud_scf_region.placeholder": "输入腾讯云 SCF 产品地域(例如:ap-guangzhou)", "workflow_node.deploy.form.tencentcloud_scf_region.tooltip": "这是什么?请参阅 https://cloud.tencent.com/document/product/583/17299",