From d272b64329488236597cafa017d0d1563af7afff Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Mon, 23 Jun 2025 21:25:11 +0800 Subject: [PATCH] feat: new deployment provider: tencentcloud ssludpate --- internal/deployer/providers.go | 15 +- internal/domain/provider.go | 1 + .../tencentcloud_ssl_update.go | 304 ++++++++++++++++++ .../workflow/node/DeployNodeConfigForm.tsx | 3 + ...loyNodeConfigFormAliyunCASDeployConfig.tsx | 8 +- ...eConfigFormTencentCloudSSLDeployConfig.tsx | 8 +- ...eConfigFormTencentCloudSSLUpdateConfig.tsx | 130 ++++++++ ui/src/domain/provider.ts | 2 + ui/src/i18n/locales/en/nls.provider.json | 5 +- .../i18n/locales/en/nls.workflow.nodes.json | 18 ++ ui/src/i18n/locales/zh/nls.provider.json | 5 +- .../i18n/locales/zh/nls.workflow.nodes.json | 22 +- 12 files changed, 506 insertions(+), 15 deletions(-) create mode 100644 pkg/core/ssl-deployer/providers/tencentcloud-ssl-update/tencentcloud_ssl_update.go create mode 100644 ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudSSLUpdateConfig.tsx diff --git a/internal/deployer/providers.go b/internal/deployer/providers.go index 708dc6d0..dac425f9 100644 --- a/internal/deployer/providers.go +++ b/internal/deployer/providers.go @@ -84,6 +84,7 @@ import ( pTencentCloudSCF "github.com/certimate-go/certimate/pkg/core/ssl-deployer/providers/tencentcloud-scf" pTencentCloudSSL "github.com/certimate-go/certimate/pkg/core/ssl-deployer/providers/tencentcloud-ssl" pTencentCloudSSLDeploy "github.com/certimate-go/certimate/pkg/core/ssl-deployer/providers/tencentcloud-ssl-deploy" + pTencentCloudSSLUpdate "github.com/certimate-go/certimate/pkg/core/ssl-deployer/providers/tencentcloud-ssl-update" pTencentCloudVOD "github.com/certimate-go/certimate/pkg/core/ssl-deployer/providers/tencentcloud-vod" pTencentCloudWAF "github.com/certimate-go/certimate/pkg/core/ssl-deployer/providers/tencentcloud-waf" pUCloudUCDN "github.com/certimate-go/certimate/pkg/core/ssl-deployer/providers/ucloud-ucdn" @@ -1118,7 +1119,7 @@ func createSSLDeployerProvider(options *deployerProviderOptions) (core.SSLDeploy return deployer, err } - 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: + case domain.DeploymentProviderTypeTencentCloudCDN, domain.DeploymentProviderTypeTencentCloudCLB, domain.DeploymentProviderTypeTencentCloudCOS, domain.DeploymentProviderTypeTencentCloudCSS, domain.DeploymentProviderTypeTencentCloudECDN, domain.DeploymentProviderTypeTencentCloudEO, domain.DeploymentProviderTypeTencentCloudGAAP, domain.DeploymentProviderTypeTencentCloudSCF, domain.DeploymentProviderTypeTencentCloudSSL, domain.DeploymentProviderTypeTencentCloudSSLDeploy, domain.DeploymentProviderTypeTencentCloudSSLUpdate, domain.DeploymentProviderTypeTencentCloudVOD, domain.DeploymentProviderTypeTencentCloudWAF: { access := domain.AccessConfigForTencentCloud{} if err := xmaps.Populate(options.ProviderAccessConfig, &access); err != nil { @@ -1226,6 +1227,18 @@ func createSSLDeployerProvider(options *deployerProviderOptions) (core.SSLDeploy }) return deployer, err + case domain.DeploymentProviderTypeTencentCloudSSLUpdate: + deployer, err := pTencentCloudSSLUpdate.NewSSLDeployerProvider(&pTencentCloudSSLUpdate.SSLDeployerProviderConfig{ + SecretId: access.SecretId, + SecretKey: access.SecretKey, + Endpoint: xmaps.GetString(options.ProviderServiceConfig, "endpoint"), + CertificiateId: xmaps.GetString(options.ProviderServiceConfig, "certificiateId"), + IsReplaced: xmaps.GetBool(options.ProviderServiceConfig, "isReplaced"), + ResourceRegions: xslices.Filter(strings.Split(xmaps.GetString(options.ProviderServiceConfig, "resourceRegions"), ";"), func(s string) bool { return s != "" }), + ResourceTypes: xslices.Filter(strings.Split(xmaps.GetString(options.ProviderServiceConfig, "resourceTypes"), ";"), func(s string) bool { return s != "" }), + }) + return deployer, err + case domain.DeploymentProviderTypeTencentCloudVOD: deployer, err := pTencentCloudVOD.NewSSLDeployerProvider(&pTencentCloudVOD.SSLDeployerProviderConfig{ SecretId: access.SecretId, diff --git a/internal/domain/provider.go b/internal/domain/provider.go index 47ba0e72..3688d5e3 100644 --- a/internal/domain/provider.go +++ b/internal/domain/provider.go @@ -257,6 +257,7 @@ const ( DeploymentProviderTypeTencentCloudSCF = DeploymentProviderType(AccessProviderTypeTencentCloud + "-scf") DeploymentProviderTypeTencentCloudSSL = DeploymentProviderType(AccessProviderTypeTencentCloud + "-ssl") DeploymentProviderTypeTencentCloudSSLDeploy = DeploymentProviderType(AccessProviderTypeTencentCloud + "-ssldeploy") + DeploymentProviderTypeTencentCloudSSLUpdate = DeploymentProviderType(AccessProviderTypeTencentCloud + "-sslupdate") DeploymentProviderTypeTencentCloudVOD = DeploymentProviderType(AccessProviderTypeTencentCloud + "-vod") DeploymentProviderTypeTencentCloudWAF = DeploymentProviderType(AccessProviderTypeTencentCloud + "-waf") DeploymentProviderTypeUCloudUCDN = DeploymentProviderType(AccessProviderTypeUCloud + "-ucdn") diff --git a/pkg/core/ssl-deployer/providers/tencentcloud-ssl-update/tencentcloud_ssl_update.go b/pkg/core/ssl-deployer/providers/tencentcloud-ssl-update/tencentcloud_ssl_update.go new file mode 100644 index 00000000..e12f894f --- /dev/null +++ b/pkg/core/ssl-deployer/providers/tencentcloud-ssl-update/tencentcloud_ssl_update.go @@ -0,0 +1,304 @@ +package tencentcloudsslupdate + +import ( + "context" + "errors" + "fmt" + "log/slog" + "slices" + "time" + + "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/certimate-go/certimate/pkg/core" + sslmgrsp "github.com/certimate-go/certimate/pkg/core/ssl-manager/providers/tencentcloud-ssl" +) + +type SSLDeployerProviderConfig struct { + // 腾讯云 SecretId。 + SecretId string `json:"secretId"` + // 腾讯云 SecretKey。 + SecretKey string `json:"secretKey"` + // 腾讯云接口端点。 + Endpoint string `json:"endpoint,omitempty"` + // 原证书 ID。 + CertificiateId string `json:"certificateId"` + // 是否替换原有证书(即保持原证书 ID 不变)。 + IsReplaced bool `json:"isReplaced,omitempty"` + // 云资源类型数组。 + ResourceTypes []string `json:"resourceTypes"` + // 云资源地域数组。 + ResourceRegions []string `json:"resourceRegions"` +} + +type SSLDeployerProvider struct { + config *SSLDeployerProviderConfig + logger *slog.Logger + sdkClient *tcssl.Client + sslManager core.SSLManager +} + +var _ core.SSLDeployer = (*SSLDeployerProvider)(nil) + +func NewSSLDeployerProvider(config *SSLDeployerProviderConfig) (*SSLDeployerProvider, error) { + if config == nil { + return nil, errors.New("the configuration of the ssl deployer provider is nil") + } + + client, err := createSDKClient(config.SecretId, config.SecretKey, config.Endpoint) + if err != nil { + return nil, fmt.Errorf("could not create sdk client: %w", err) + } + + sslmgr, err := sslmgrsp.NewSSLManagerProvider(&sslmgrsp.SSLManagerProviderConfig{ + SecretId: config.SecretId, + SecretKey: config.SecretKey, + Endpoint: config.Endpoint, + }) + if err != nil { + return nil, fmt.Errorf("could not create ssl manager: %w", err) + } + + return &SSLDeployerProvider{ + config: config, + logger: slog.Default(), + sdkClient: client, + sslManager: sslmgr, + }, nil +} + +func (d *SSLDeployerProvider) SetLogger(logger *slog.Logger) { + if logger == nil { + d.logger = slog.New(slog.DiscardHandler) + } else { + d.logger = logger + } + + d.sslManager.SetLogger(logger) +} + +func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privkeyPEM string) (*core.SSLDeployResult, error) { + if d.config.CertificiateId == "" { + return nil, errors.New("config `certificateId` is required") + } + if len(d.config.ResourceTypes) == 0 { + return nil, errors.New("config `resourceTypes` is required") + } + + if d.config.IsReplaced { + if err := d.executeUploadUpdateCertificateInstance(ctx, certPEM, privkeyPEM); err != nil { + return nil, err + } + } else { + if err := d.executeUpdateCertificateInstance(ctx, certPEM, privkeyPEM); err != nil { + return nil, err + } + } + + return &core.SSLDeployResult{}, nil +} + +func (d *SSLDeployerProvider) executeUpdateCertificateInstance(ctx context.Context, certPEM string, privkeyPEM string) error { + // 上传证书 + upres, err := d.sslManager.Upload(ctx, certPEM, privkeyPEM) + if err != nil { + return fmt.Errorf("failed to upload certificate file: %w", err) + } else { + d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) + } + + // 一键更新新旧证书资源 + // REF: https://cloud.tencent.com/document/product/400/91649 + var deployRecordId string + for { + select { + case <-ctx.Done(): + return ctx.Err() + default: + } + + updateCertificateInstanceReq := tcssl.NewUpdateCertificateInstanceRequest() + updateCertificateInstanceReq.OldCertificateId = common.StringPtr(d.config.CertificiateId) + updateCertificateInstanceReq.CertificateId = common.StringPtr(upres.CertId) + updateCertificateInstanceReq.ResourceTypes = common.StringPtrs(d.config.ResourceTypes) + updateCertificateInstanceReq.ResourceTypesRegions = wrapResourceTypeRegions(d.config.ResourceTypes, d.config.ResourceRegions) + updateCertificateInstanceResp, err := d.sdkClient.UpdateCertificateInstance(updateCertificateInstanceReq) + d.logger.Debug("sdk request 'ssl.UpdateCertificateInstance'", slog.Any("request", updateCertificateInstanceReq), slog.Any("response", updateCertificateInstanceResp)) + if err != nil { + return fmt.Errorf("failed to execute sdk request 'ssl.UpdateCertificateInstance': %w", err) + } + + if updateCertificateInstanceResp.Response.DeployStatus == nil { + return errors.New("unexpected deployment job status") + } else if *updateCertificateInstanceResp.Response.DeployStatus == 1 { + deployRecordId = fmt.Sprintf("%d", *updateCertificateInstanceResp.Response.DeployRecordId) + break + } + + time.Sleep(time.Second * 5) + } + + // 循环查询证书云资源更新记录详情,等待任务状态变更 + // REF: https://cloud.tencent.com/document/api/400/91652 + for { + select { + case <-ctx.Done(): + return ctx.Err() + default: + } + + describeHostUpdateRecordDetailReq := tcssl.NewDescribeHostUpdateRecordDetailRequest() + describeHostUpdateRecordDetailReq.DeployRecordId = common.StringPtr(deployRecordId) + describeHostUpdateRecordDetailResp, err := d.sdkClient.DescribeHostUpdateRecordDetail(describeHostUpdateRecordDetailReq) + d.logger.Debug("sdk request 'ssl.DescribeHostUpdateRecordDetail'", slog.Any("request", describeHostUpdateRecordDetailReq), slog.Any("response", describeHostUpdateRecordDetailResp)) + if err != nil { + return fmt.Errorf("failed to execute sdk request 'ssl.DescribeHostUpdateRecordDetail': %w", err) + } + + var runningCount, succeededCount, failedCount, totalCount int64 + if describeHostUpdateRecordDetailResp.Response.TotalCount == nil { + return errors.New("unexpected deployment job status") + } else { + if describeHostUpdateRecordDetailResp.Response.RunningTotalCount != nil { + runningCount = *describeHostUpdateRecordDetailResp.Response.RunningTotalCount + } + if describeHostUpdateRecordDetailResp.Response.SuccessTotalCount != nil { + succeededCount = *describeHostUpdateRecordDetailResp.Response.SuccessTotalCount + } + if describeHostUpdateRecordDetailResp.Response.FailedTotalCount != nil { + failedCount = *describeHostUpdateRecordDetailResp.Response.FailedTotalCount + } + if describeHostUpdateRecordDetailResp.Response.TotalCount != nil { + totalCount = *describeHostUpdateRecordDetailResp.Response.TotalCount + } + + if succeededCount+failedCount == totalCount { + break + } + } + + d.logger.Info(fmt.Sprintf("waiting for deployment job completion (running: %d, succeeded: %d, failed: %d, total: %d) ...", runningCount, succeededCount, failedCount, totalCount)) + time.Sleep(time.Second * 5) + } + + return nil +} + +func (d *SSLDeployerProvider) executeUploadUpdateCertificateInstance(ctx context.Context, certPEM string, privkeyPEM string) error { + // 更新证书内容并更新关联的云资源 + // REF: https://cloud.tencent.com/document/product/400/119791 + // var deployRecordId string + for { + select { + case <-ctx.Done(): + return ctx.Err() + default: + } + + uploadUpdateCertificateInstanceReq := tcssl.NewUploadUpdateCertificateInstanceRequest() + uploadUpdateCertificateInstanceReq.OldCertificateId = common.StringPtr(d.config.CertificiateId) + uploadUpdateCertificateInstanceReq.CertificatePublicKey = common.StringPtr(certPEM) + uploadUpdateCertificateInstanceReq.CertificatePrivateKey = common.StringPtr(privkeyPEM) + uploadUpdateCertificateInstanceReq.ResourceTypes = common.StringPtrs(d.config.ResourceTypes) + uploadUpdateCertificateInstanceReq.ResourceTypesRegions = wrapResourceTypeRegions(d.config.ResourceTypes, d.config.ResourceRegions) + uploadUpdateCertificateInstanceResp, err := d.sdkClient.UploadUpdateCertificateInstance(uploadUpdateCertificateInstanceReq) + d.logger.Debug("sdk request 'ssl.UploadUpdateCertificateInstance'", slog.Any("request", uploadUpdateCertificateInstanceReq), slog.Any("response", uploadUpdateCertificateInstanceResp)) + if err != nil { + return fmt.Errorf("failed to execute sdk request 'ssl.UploadUpdateCertificateInstance': %w", err) + } + + if uploadUpdateCertificateInstanceResp.Response.DeployStatus == nil { + return errors.New("unexpected deployment job status") + } else if *uploadUpdateCertificateInstanceResp.Response.DeployStatus == 1 { + // deployRecordId = fmt.Sprintf("%d", *uploadUpdateCertificateInstanceResp.Response.DeployRecordId) + break + } + + time.Sleep(time.Second * 5) + } + + // // 循环查询证书云资源更新记录详情,等待任务状态变更 + // for { + // select { + // case <-ctx.Done(): + // return ctx.Err() + // default: + // } + + // describeHostUploadUpdateRecordDetailReq := tcssl.NewDescribeHostUploadUpdateRecordDetailRequest() + // describeHostUploadUpdateRecordDetailReq.DeployRecordId = common.StringPtr(deployRecordId) + // describeHostUploadUpdateRecordDetailResp, err := d.sdkClient.DescribeHostUpdateRecord(describeHostUploadUpdateRecordDetailReq) + // d.logger.Debug("sdk request 'ssl.DescribeHostUploadUpdateRecordDetail'", slog.Any("request", describeHostUploadUpdateRecordDetailReq), slog.Any("response", describeHostUploadUpdateRecordDetailResp)) + // if err != nil { + // return fmt.Errorf("failed to execute sdk request 'ssl.DescribeHostUploadUpdateRecordDetail': %w", err) + // } + + // var runningCount, succeededCount, failedCount, totalCount int64 + // if describeHostUploadUpdateRecordDetailResp.Response.TotalCount == nil { + // return errors.New("unexpected deployment job status") + // } else { + // for _, record := range describeHostUploadUpdateRecordDetailResp.Response.DeployRecordDetail { + // if record.RunningTotalCount != nil { + // runningCount = *record.RunningTotalCount + // } + // if record.SuccessTotalCount != nil { + // succeededCount = *record.SuccessTotalCount + // } + // if record.FailedTotalCount != nil { + // failedCount = *record.FailedTotalCount + // } + // if record.TotalCount != nil { + // totalCount = *record.TotalCount + // } + // } + + // if succeededCount+failedCount == totalCount { + // break + // } + // } + + // d.logger.Info(fmt.Sprintf("waiting for deployment job completion (running: %d, succeeded: %d, failed: %d, total: %d) ...", runningCount, succeededCount, failedCount, totalCount)) + // time.Sleep(time.Second * 5) + // } + + return nil +} + +func createSDKClient(secretId, secretKey, endpoint string) (*tcssl.Client, error) { + credential := common.NewCredential(secretId, secretKey) + + cpf := profile.NewClientProfile() + if endpoint != "" { + cpf.HttpProfile.Endpoint = endpoint + } + + client, err := tcssl.NewClient(credential, "", cpf) + if err != nil { + return nil, err + } + + return client, nil +} + +func wrapResourceTypeRegions(resourceTypes, resourceRegions []string) []*tcssl.ResourceTypeRegions { + if len(resourceTypes) == 0 || len(resourceRegions) == 0 { + return nil + } + + // 仅以下云资源类型支持地域 + resourceTypesRequireRegion := []string{"apigateway", "clb", "cos", "tcb", "tke", "tse", "waf"} + + temp := make([]*tcssl.ResourceTypeRegions, 0) + for _, resourceType := range resourceTypes { + if slices.Contains(resourceTypesRequireRegion, resourceType) { + temp = append(temp, &tcssl.ResourceTypeRegions{ + ResourceType: common.StringPtr(resourceType), + Regions: common.StringPtrs(resourceRegions), + }) + } + } + + return temp +} diff --git a/ui/src/components/workflow/node/DeployNodeConfigForm.tsx b/ui/src/components/workflow/node/DeployNodeConfigForm.tsx index 16e587ea..baf4dcf4 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigForm.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigForm.tsx @@ -87,6 +87,7 @@ import DeployNodeConfigFormTencentCloudGAAPConfig from "./DeployNodeConfigFormTe import DeployNodeConfigFormTencentCloudSCFConfig from "./DeployNodeConfigFormTencentCloudSCFConfig"; import DeployNodeConfigFormTencentCloudSSLConfig from "./DeployNodeConfigFormTencentCloudSSLConfig"; import DeployNodeConfigFormTencentCloudSSLDeployConfig from "./DeployNodeConfigFormTencentCloudSSLDeployConfig"; +import DeployNodeConfigFormTencentCloudSSLUpdateConfig from "./DeployNodeConfigFormTencentCloudSSLUpdateConfig"; import DeployNodeConfigFormTencentCloudVODConfig from "./DeployNodeConfigFormTencentCloudVODConfig"; import DeployNodeConfigFormTencentCloudWAFConfig from "./DeployNodeConfigFormTencentCloudWAFConfig"; import DeployNodeConfigFormUCloudUCDNConfig from "./DeployNodeConfigFormUCloudUCDNConfig.tsx"; @@ -347,6 +348,8 @@ const DeployNodeConfigForm = forwardRef; case DEPLOYMENT_PROVIDERS.TENCENTCLOUD_SSL_DEPLOY: return ; + case DEPLOYMENT_PROVIDERS.TENCENTCLOUD_SSL_UPDATE: + return ; case DEPLOYMENT_PROVIDERS.TENCENTCLOUD_VOD: return ; case DEPLOYMENT_PROVIDERS.TENCENTCLOUD_WAF: diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunCASDeployConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunCASDeployConfig.tsx index f16a0c79..be1747e8 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigFormAliyunCASDeployConfig.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigFormAliyunCASDeployConfig.tsx @@ -69,6 +69,10 @@ const DeployNodeConfigFormAliyunCASDeployConfig = ({ name={formName} onValuesChange={handleFormChange} > + + } /> + + - - - } /> - ); }; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudSSLDeployConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudSSLDeployConfig.tsx index 37c82584..1a104bf2 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudSSLDeployConfig.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudSSLDeployConfig.tsx @@ -65,6 +65,10 @@ const DeployNodeConfigFormTencentCloudSSLDeployConfig = ({ name={formName} onValuesChange={handleFormChange} > + + } /> + + - - - } /> - ); }; diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudSSLUpdateConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudSSLUpdateConfig.tsx new file mode 100644 index 00000000..6c0fe497 --- /dev/null +++ b/ui/src/components/workflow/node/DeployNodeConfigFormTencentCloudSSLUpdateConfig.tsx @@ -0,0 +1,130 @@ +import { useTranslation } from "react-i18next"; +import { Alert, Form, type FormInstance, Input, Switch } from "antd"; +import { createSchemaFieldRule } from "antd-zod"; +import { z } from "zod/v4"; + +import MultipleSplitValueInput from "@/components/MultipleSplitValueInput"; + +type DeployNodeConfigFormTencentCloudSSLUpdateConfigFieldValues = Nullish<{ + endpoint?: string; + certificateId: string; + resourceTypes: string; + resourceRegions?: string; + isReplaced?: boolean; +}>; + +export type DeployNodeConfigFormTencentCloudSSLUpdateConfigProps = { + form: FormInstance; + formName: string; + disabled?: boolean; + initialValues?: DeployNodeConfigFormTencentCloudSSLUpdateConfigFieldValues; + onValuesChange?: (values: DeployNodeConfigFormTencentCloudSSLUpdateConfigFieldValues) => void; +}; + +const MULTIPLE_INPUT_SEPARATOR = ";"; + +const initFormModel = (): DeployNodeConfigFormTencentCloudSSLUpdateConfigFieldValues => { + return {}; +}; + +const DeployNodeConfigFormTencentCloudSSLUpdateConfig = ({ + form: formInst, + formName, + disabled, + initialValues, + onValuesChange, +}: DeployNodeConfigFormTencentCloudSSLUpdateConfigProps) => { + const { t } = useTranslation(); + + const formSchema = z.object({ + endpoint: z.string().nullish(), + certificateId: z + .string(t("workflow_node.deploy.form.tencentcloud_ssl_update_certificate_id.placeholder")) + .nonempty(t("workflow_node.deploy.form.tencentcloud_ssl_update_certificate_id.placeholder")), + resourceTypes: z.string(t("workflow_node.deploy.form.tencentcloud_ssl_update_resource_types.placeholder")).refine((v) => { + if (!v) return false; + return String(v) + .split(MULTIPLE_INPUT_SEPARATOR) + .every((e) => !!e.trim()); + }, t("workflow_node.deploy.form.tencentcloud_ssl_update_resource_types.placeholder")), + resourceRegions: z.string(t("workflow_node.deploy.form.tencentcloud_ssl_update_resource_regions.placeholder")).refine((v) => { + if (!v) return false; + return String(v) + .split(MULTIPLE_INPUT_SEPARATOR) + .every((e) => !!e.trim()); + }, t("workflow_node.deploy.form.tencentcloud_ssl_update_resource_regions.placeholder")), + isReplaced: z.boolean().nullish(), + }); + const formRule = createSchemaFieldRule(formSchema); + + const handleFormChange = (_: unknown, values: z.infer) => { + onValuesChange?.(values); + }; + + return ( +
+ + } /> + + + } + > + + + + } + > + + + + } + > + + + + } + > + + + + + + +
+ ); +}; + +export default DeployNodeConfigFormTencentCloudSSLUpdateConfig; diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts index 1100e797..fb1e2e12 100644 --- a/ui/src/domain/provider.ts +++ b/ui/src/domain/provider.ts @@ -455,6 +455,7 @@ export const DEPLOYMENT_PROVIDERS = Object.freeze({ TENCENTCLOUD_SCF: `${ACCESS_PROVIDERS.TENCENTCLOUD}-scf`, TENCENTCLOUD_SSL: `${ACCESS_PROVIDERS.TENCENTCLOUD}-ssl`, TENCENTCLOUD_SSL_DEPLOY: `${ACCESS_PROVIDERS.TENCENTCLOUD}-ssldeploy`, + TENCENTCLOUD_SSL_UPDATE: `${ACCESS_PROVIDERS.TENCENTCLOUD}-sslupdate`, TENCENTCLOUD_VOD: `${ACCESS_PROVIDERS.TENCENTCLOUD}-vod`, TENCENTCLOUD_WAF: `${ACCESS_PROVIDERS.TENCENTCLOUD}-waf`, UCLOUD_UCDN: `${ACCESS_PROVIDERS.UCLOUD}-ucdn`, @@ -543,6 +544,7 @@ export const deploymentProvidersMap: Maphttps://cloud.tencent.com/document/product/400/91667", "workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_ids.multiple_input_modal.title": "Change Tencent Cloud resource IDs", "workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_ids.multiple_input_modal.placeholder": "Please enter Tencent Cloud resouce ID", + "workflow_node.deploy.form.tencentcloud_ssl_update.guide": "TIPS: You need to go to the Tencent Cloud console to check the actual deployment results by yourself, because Tencent Cloud deployment tasks are running asynchronously.", + "workflow_node.deploy.form.tencentcloud_ssl_update_endpoint.label": "Tencent Cloud SSL API endpoint (Optional)", + "workflow_node.deploy.form.tencentcloud_ssl_update_endpoint.placeholder": "Please enter Tencent Cloud SSL API endpoint (e.g. ssl.intl.tencentcloudapi.com)", + "workflow_node.deploy.form.tencentcloud_ssl_update_endpoint.tooltip": "
  • ssl.intl.tencentcloudapi.com for Tencent Cloud International
  • ssl.tencentcloudapi.com for Tencent Cloud in China
", + "workflow_node.deploy.form.tencentcloud_ssl_update_certificate_id.label": "Tencent Cloud SSL certificate ID", + "workflow_node.deploy.form.tencentcloud_ssl_update_certificate_id.placeholder": "Please enter Tencent Cloud SSL certificate ID", + "workflow_node.deploy.form.tencentcloud_ssl_update_certificate_id.tooltip": "For more information, see https://console.cloud.tencent.com/certoverview", + "workflow_node.deploy.form.tencentcloud_ssl_update_resource_types.label": "Tencent Cloud resource types", + "workflow_node.deploy.form.tencentcloud_ssl_update_resource_types.placeholder": "Please enter Tencent Cloud resource types (separated by semicolons)", + "workflow_node.deploy.form.tencentcloud_ssl_update_resource_types.tooltip": "For more information, see https://www.tencentcloud.com/document/product/1007/57981", + "workflow_node.deploy.form.tencentcloud_ssl_update_resource_types.multiple_input_modal.title": "Change Tencent Cloud resource types", + "workflow_node.deploy.form.tencentcloud_ssl_update_resource_types.multiple_input_modal.placeholder": "Please enter Tencent Cloud resource type", + "workflow_node.deploy.form.tencentcloud_ssl_update_resource_regions.label": "Tencent Cloud resource regions (Optional)", + "workflow_node.deploy.form.tencentcloud_ssl_update_resource_regions.placeholder": "Please enter Tencent Cloud resource regions (separated by semicolons)", + "workflow_node.deploy.form.tencentcloud_ssl_update_resource_regions.tooltip": "For more information, see https://www.tencentcloud.com/document/product/1007/57981", + "workflow_node.deploy.form.tencentcloud_ssl_update_resource_regions.multiple_input_modal.title": "Change Tencent Cloud resource regions", + "workflow_node.deploy.form.tencentcloud_ssl_update_resource_regions.multiple_input_modal.placeholder": "Please enter Tencent Cloud resource region", + "workflow_node.deploy.form.tencentcloud_ssl_update_is_replaced.label": "Renewal certificate (certificate ID unchanged)", "workflow_node.deploy.form.tencentcloud_vod_endpoint.label": "Tencent Cloud VOD API endpoint (Optional)", "workflow_node.deploy.form.tencentcloud_vod_endpoint.placeholder": "Please enter Tencent Cloud VOD API endpoint (e.g. vod.intl.tencentcloudapi.com)", "workflow_node.deploy.form.tencentcloud_vod_endpoint.tooltip": "
  • vod.intl.tencentcloudapi.com for Tencent Cloud International
  • vod.tencentcloudapi.com for Tencent Cloud in China
", diff --git a/ui/src/i18n/locales/zh/nls.provider.json b/ui/src/i18n/locales/zh/nls.provider.json index 865f5b48..36e01d37 100644 --- a/ui/src/i18n/locales/zh/nls.provider.json +++ b/ui/src/i18n/locales/zh/nls.provider.json @@ -7,8 +7,8 @@ "provider.aliyun": "阿里云", "provider.aliyun.alb": "阿里云 - 应用型负载均衡 ALB", "provider.aliyun.apigw": "阿里云 - API 网关", - "provider.aliyun.cas_upload": "阿里云 - 上传到数字证书管理服务 CAS", "provider.aliyun.cas_deploy": "阿里云 - 通过数字证书管理服务 CAS 创建部署任务", + "provider.aliyun.cas_upload": "阿里云 - 上传到数字证书管理服务 CAS", "provider.aliyun.cdn": "阿里云 - 内容分发网络 CDN", "provider.aliyun.clb": "阿里云 - 传统型负载均衡 CLB", "provider.aliyun.dcdn": "阿里云 - 全站加速 DCDN", @@ -143,8 +143,9 @@ "provider.tencentcloud.eo": "腾讯云 - 边缘安全加速平台 EdgeOne", "provider.tencentcloud.gaap": "腾讯云 - 全球应用加速 GAAP", "provider.tencentcloud.scf": "腾讯云 - 云函数 SCF", - "provider.tencentcloud.ssl_upload": "腾讯云 - 上传到 SSL 证书服务", "provider.tencentcloud.ssl_deploy": "腾讯云 - 通过 SSL 证书服务创建部署任务", + "provider.tencentcloud.ssl_update": "腾讯云 - 通过 SSL 证书服务更新云资源证书", + "provider.tencentcloud.ssl_upload": "腾讯云 - 上传到 SSL 证书服务", "provider.tencentcloud.vod": "腾讯云 - 云点播 VOD", "provider.tencentcloud.waf": "腾讯云 - Web 应用防火墙 WAF", "provider.ucloud": "优刻得", diff --git a/ui/src/i18n/locales/zh/nls.workflow.nodes.json b/ui/src/i18n/locales/zh/nls.workflow.nodes.json index 1639339a..28c0176c 100644 --- a/ui/src/i18n/locales/zh/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/zh/nls.workflow.nodes.json @@ -168,7 +168,7 @@ "workflow_node.deploy.form.aliyun_cas_region.label": "阿里云 CAS 服务地域", "workflow_node.deploy.form.aliyun_cas_region.placeholder": "请输入阿里云 CAS 服务地域(例如:cn-hangzhou)", "workflow_node.deploy.form.aliyun_cas_region.tooltip": "这是什么?请参阅 https://help.aliyun.com/zh/ssl-certificate/developer-reference/endpoints", - "workflow_node.deploy.form.aliyun_cas_deploy.guide": "小贴士:由于阿里云证书部署任务是异步的,此节点若执行成功仅代表已创建部署任务,实际部署结果需要你自行前往阿里云控制台查询。", + "workflow_node.deploy.form.aliyun_cas_deploy.guide": "小贴士:由于阿里云证书部署任务是异步的,此部署目标若执行成功仅代表已创建部署任务,实际部署结果需要你自行前往阿里云控制台查询。", "workflow_node.deploy.form.aliyun_cas_deploy_region.label": "阿里云 CAS 服务地域", "workflow_node.deploy.form.aliyun_cas_deploy_region.placeholder": "请输入阿里云 CAS 服务地域(例如:cn-hangzhou)", "workflow_node.deploy.form.aliyun_cas_deploy_region.tooltip": "这是什么?请参阅 https://help.aliyun.com/zh/ssl-certificate/developer-reference/endpoints", @@ -740,7 +740,7 @@ "workflow_node.deploy.form.tencentcloud_ssl_endpoint.label": "腾讯云 SSL 接口端点(可选)", "workflow_node.deploy.form.tencentcloud_ssl_endpoint.placeholder": "请输入腾讯云 SSL 接口端点(例如:ssl.tencentcloudapi.com)", "workflow_node.deploy.form.tencentcloud_ssl_endpoint.tooltip": "这是什么?请参阅 https://cloud.tencent.com/document/product/400/41659", - "workflow_node.deploy.form.tencentcloud_ssl_deploy.guide": "小贴士:由于腾讯云证书部署任务是异步的,此节点若执行成功仅代表已创建部署任务,实际部署结果需要你自行前往腾讯云控制台查询。", + "workflow_node.deploy.form.tencentcloud_ssl_deploy.guide": "小贴士:由于腾讯云证书部署任务是异步的,此部署目标若执行成功仅代表已创建部署任务,实际部署结果需要你自行前往腾讯云控制台查询。", "workflow_node.deploy.form.tencentcloud_ssl_deploy_endpoint.label": "腾讯云 SSL 接口端点(可选)", "workflow_node.deploy.form.tencentcloud_ssl_deploy_endpoint.placeholder": "请输入腾讯云 SSL 接口端点(例如:ssl.tencentcloudapi.com)", "workflow_node.deploy.form.tencentcloud_ssl_deploy_endpoint.tooltip": "这是什么?请参阅 https://cloud.tencent.com/document/product/400/41659", @@ -756,6 +756,24 @@ "workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_ids.tooltip": "这是什么?请参阅 https://cloud.tencent.com/document/product/400/91667

注意与各产品本身的实例 ID 区分。", "workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_ids.multiple_input_modal.title": "修改腾讯云云产品资源 ID", "workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_ids.multiple_input_modal.placeholder": "请输入腾讯云云产品资源 ID", + "workflow_node.deploy.form.tencentcloud_ssl_update.guide": "小贴士:由于腾讯云证书部署任务是异步的,此部署目标若执行成功仅代表已创建部署任务,实际部署结果需要你自行前往腾讯云控制台查询。", + "workflow_node.deploy.form.tencentcloud_ssl_update_endpoint.label": "腾讯云 SSL 接口端点(可选)", + "workflow_node.deploy.form.tencentcloud_ssl_update_endpoint.placeholder": "请输入腾讯云 SSL 接口端点(例如:ssl.tencentcloudapi.com)", + "workflow_node.deploy.form.tencentcloud_ssl_update_endpoint.tooltip": "这是什么?请参阅 https://cloud.tencent.com/document/product/400/41659", + "workflow_node.deploy.form.tencentcloud_ssl_update_certificate_id.label": "腾讯云原证书 ID", + "workflow_node.deploy.form.tencentcloud_ssl_update_certificate_id.placeholder": "请输入腾讯云原证书 ID", + "workflow_node.deploy.form.tencentcloud_ssl_update_certificate_id.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/certoverview", + "workflow_node.deploy.form.tencentcloud_ssl_update_resource_types.label": "腾讯云云产品资源类型", + "workflow_node.deploy.form.tencentcloud_ssl_update_resource_types.placeholder": "请输入腾讯云云产品资源类型(多个值请用半角分号隔开)", + "workflow_node.deploy.form.tencentcloud_ssl_update_resource_types.tooltip": "这是什么?请参阅 https://cloud.tencent.com/document/product/400/91649", + "workflow_node.deploy.form.tencentcloud_ssl_update_resource_types.multiple_input_modal.title": "修改腾讯云云产品资源类型", + "workflow_node.deploy.form.tencentcloud_ssl_update_resource_types.multiple_input_modal.placeholder": "请输入腾讯云云产品资源类型", + "workflow_node.deploy.form.tencentcloud_ssl_update_resource_regions.label": "腾讯云云产品部署地域(可选)", + "workflow_node.deploy.form.tencentcloud_ssl_update_resource_regions.placeholder": "请输入腾讯云云产品部署地域(多个值请用半角分号隔开)", + "workflow_node.deploy.form.tencentcloud_ssl_update_resource_regions.tooltip": "这是什么?请参阅 https://cloud.tencent.com/document/product/400/91649", + "workflow_node.deploy.form.tencentcloud_ssl_update_resource_regions.multiple_input_modal.title": "修改腾讯云云产品资源类型", + "workflow_node.deploy.form.tencentcloud_ssl_update_resource_regions.multiple_input_modal.placeholder": "请输入腾讯云云产品资源类型", + "workflow_node.deploy.form.tencentcloud_ssl_update_is_replaced.label": "是否更新原证书(即证书 ID 保持不变)", "workflow_node.deploy.form.tencentcloud_vod_endpoint.label": "腾讯云云点播接口端点(可选)", "workflow_node.deploy.form.tencentcloud_vod_endpoint.placeholder": "请输入腾讯云云点播接口端点(例如:vod.tencentcloudapi.com)", "workflow_node.deploy.form.tencentcloud_vod_endpoint.tooltip": "这是什么?请参阅 https://cloud.tencent.com/document/product/266/31755",