From d3e207cb2f0fade77cc4a44ee79b9df3b72f673a Mon Sep 17 00:00:00 2001 From: 131 <11222509+Netrvin@users.noreply.github.com> Date: Sun, 13 Jul 2025 21:51:09 +0800 Subject: [PATCH 1/7] =?UTF-8?q?fix:=20=E8=85=BE=E8=AE=AF=E4=BA=91=E6=9B=B4?= =?UTF-8?q?=E6=96=B0ssl=E5=85=B3=E8=81=94=E8=B5=84=E6=BA=90=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tencentcloud-ssl-update/tencentcloud_ssl_update.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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 index 753e8be48..6303eda8b 100644 --- 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 @@ -130,9 +130,9 @@ func (d *SSLDeployerProvider) executeUpdateCertificateInstance(ctx context.Conte return fmt.Errorf("failed to execute sdk request 'ssl.UpdateCertificateInstance': %w", err) } - if updateCertificateInstanceResp.Response.DeployStatus == nil { + if updateCertificateInstanceResp.Response.DeployStatus == nil || updateCertificateInstanceResp.Response.DeployRecordId == nil { return errors.New("unexpected deployment job status") - } else if *updateCertificateInstanceResp.Response.DeployStatus == 1 { + } else if *updateCertificateInstanceResp.Response.DeployRecordId > 0 { deployRecordId = fmt.Sprintf("%d", *updateCertificateInstanceResp.Response.DeployRecordId) break } @@ -175,6 +175,9 @@ func (d *SSLDeployerProvider) executeUpdateCertificateInstance(ctx context.Conte } if succeededCount+failedCount == totalCount { + if failedCount > 0 { + return fmt.Errorf("deployment job failed (succeeded: %d, failed: %d, total: %d)", succeededCount, failedCount, totalCount) + } break } } From 41f83d75026016a3974b56ac155a9da684d9002c Mon Sep 17 00:00:00 2001 From: 131 <11222509+Netrvin@users.noreply.github.com> Date: Mon, 14 Jul 2025 21:57:58 +0800 Subject: [PATCH 2/7] =?UTF-8?q?fix:=20=E9=83=A8=E5=88=86=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E6=97=B6=E4=BB=BB=E5=8A=A1=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E4=BB=8D=E6=9C=AA=E6=88=90=E5=8A=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../providers/tencentcloud-clb/tencentcloud_clb.go | 3 +++ .../providers/tencentcloud-cos/tencentcloud_cos.go | 3 +++ .../tencentcloud-ssl-deploy/tencentcloud_ssl_deploy.go | 3 +++ .../tencentcloud-ssl-update/tencentcloud_ssl_update.go | 3 +++ 4 files changed, 12 insertions(+) diff --git a/pkg/core/ssl-deployer/providers/tencentcloud-clb/tencentcloud_clb.go b/pkg/core/ssl-deployer/providers/tencentcloud-clb/tencentcloud_clb.go index dbde47153..710733c4c 100644 --- a/pkg/core/ssl-deployer/providers/tencentcloud-clb/tencentcloud_clb.go +++ b/pkg/core/ssl-deployer/providers/tencentcloud-clb/tencentcloud_clb.go @@ -194,6 +194,9 @@ func (d *SSLDeployerProvider) deployViaSslService(ctx context.Context, cloudCert } if succeededCount+failedCount == totalCount { + if failedCount > 0 { + return fmt.Errorf("deployment job failed (succeeded: %d, failed: %d, total: %d)", succeededCount, failedCount, totalCount) + } break } } diff --git a/pkg/core/ssl-deployer/providers/tencentcloud-cos/tencentcloud_cos.go b/pkg/core/ssl-deployer/providers/tencentcloud-cos/tencentcloud_cos.go index 0e5e5f66b..3be36998e 100644 --- a/pkg/core/ssl-deployer/providers/tencentcloud-cos/tencentcloud_cos.go +++ b/pkg/core/ssl-deployer/providers/tencentcloud-cos/tencentcloud_cos.go @@ -141,6 +141,9 @@ func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privke } if succeededCount+failedCount == totalCount { + if failedCount > 0 { + return nil, fmt.Errorf("deployment job failed (succeeded: %d, failed: %d, total: %d)", succeededCount, failedCount, totalCount) + } break } } diff --git a/pkg/core/ssl-deployer/providers/tencentcloud-ssl-deploy/tencentcloud_ssl_deploy.go b/pkg/core/ssl-deployer/providers/tencentcloud-ssl-deploy/tencentcloud_ssl_deploy.go index 5f9229f6b..9b3babe1b 100644 --- a/pkg/core/ssl-deployer/providers/tencentcloud-ssl-deploy/tencentcloud_ssl_deploy.go +++ b/pkg/core/ssl-deployer/providers/tencentcloud-ssl-deploy/tencentcloud_ssl_deploy.go @@ -142,6 +142,9 @@ func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privke } if succeededCount+failedCount == totalCount { + if failedCount > 0 { + return nil, fmt.Errorf("deployment job failed (succeeded: %d, failed: %d, total: %d)", succeededCount, failedCount, totalCount) + } break } } 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 index 6303eda8b..ddc2d432d 100644 --- 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 @@ -260,6 +260,9 @@ func (d *SSLDeployerProvider) executeUploadUpdateCertificateInstance(ctx context } if succeededCount+failedCount == totalCount { + if failedCount > 0 { + return fmt.Errorf("deployment job failed (succeeded: %d, failed: %d, total: %d)", succeededCount, failedCount, totalCount) + } break } } From 44bd03f5cd9a26f313cdef5fa591a02601fa8798 Mon Sep 17 00:00:00 2001 From: Netrvin <11222509+Netrvin@users.noreply.github.com> Date: Mon, 14 Jul 2025 12:58:35 +0800 Subject: [PATCH 3/7] =?UTF-8?q?fix:=20=E8=85=BE=E8=AE=AF=E4=BA=91edgeone?= =?UTF-8?q?=20DNS=E4=B8=8D=E6=94=AF=E6=8C=81=E7=AD=BE=E5=8F=91=E5=90=8C?= =?UTF-8?q?=E6=97=B6=E5=8C=85=E5=90=ABexample.com=E5=92=8C*.example.com?= =?UTF-8?q?=E7=9A=84=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tencentcloud-eo/internal/lego.go | 57 +++++-------------- 1 file changed, 15 insertions(+), 42 deletions(-) diff --git a/pkg/core/ssl-applicator/acme-dns01/providers/tencentcloud-eo/internal/lego.go b/pkg/core/ssl-applicator/acme-dns01/providers/tencentcloud-eo/internal/lego.go index 69ad8a80c..db33ea90b 100644 --- a/pkg/core/ssl-applicator/acme-dns01/providers/tencentcloud-eo/internal/lego.go +++ b/pkg/core/ssl-applicator/acme-dns01/providers/tencentcloud-eo/internal/lego.go @@ -90,7 +90,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) { func (d *DNSProvider) Present(domain, token, keyAuth string) error { info := dns01.GetChallengeInfo(domain, keyAuth) - if err := d.addOrUpdateDNSRecord(dns01.UnFqdn(info.EffectiveFQDN), info.Value); err != nil { + if err := d.addDNSRecord(dns01.UnFqdn(info.EffectiveFQDN), info.Value); err != nil { return fmt.Errorf("tencentcloud-eo: %w", err) } @@ -100,7 +100,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error { func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error { info := dns01.GetChallengeInfo(domain, keyAuth) - if err := d.removeDNSRecord(dns01.UnFqdn(info.EffectiveFQDN)); err != nil { + if err := d.removeDNSRecord(dns01.UnFqdn(info.EffectiveFQDN), info.Value); err != nil { return fmt.Errorf("tencentcloud-eo: %w", err) } @@ -111,7 +111,7 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) { return d.config.PropagationTimeout, d.config.PollingInterval } -func (d *DNSProvider) findDNSRecord(effectiveFQDN string) (*teo.DnsRecord, error) { +func (d *DNSProvider) findDNSRecord(effectiveFQDN, value string) (*teo.DnsRecord, error) { pageOffset := 0 pageLimit := 1000 for { @@ -135,7 +135,7 @@ func (d *DNSProvider) findDNSRecord(effectiveFQDN string) (*teo.DnsRecord, error break } else { for _, record := range response.Response.DnsRecords { - if *record.Name == effectiveFQDN { + if *record.Name == effectiveFQDN && *record.Content == value { return record, nil } } @@ -151,46 +151,19 @@ func (d *DNSProvider) findDNSRecord(effectiveFQDN string) (*teo.DnsRecord, error return nil, nil } -func (d *DNSProvider) addOrUpdateDNSRecord(effectiveFQDN, value string) error { - record, err := d.findDNSRecord(effectiveFQDN) - if err != nil { - return err - } - - if record == nil { - request := teo.NewCreateDnsRecordRequest() - request.ZoneId = common.StringPtr(d.config.ZoneID) - request.Name = common.StringPtr(effectiveFQDN) - request.Type = common.StringPtr("TXT") - request.Content = common.StringPtr(value) - request.TTL = common.Int64Ptr(int64(d.config.TTL)) - _, err := d.client.CreateDnsRecord(request) - return err - } else { - record.Content = common.StringPtr(value) - record.TTL = common.Int64Ptr(int64(d.config.TTL)) - request := teo.NewModifyDnsRecordsRequest() - request.ZoneId = common.StringPtr(d.config.ZoneID) - request.DnsRecords = []*teo.DnsRecord{record} - if _, err := d.client.ModifyDnsRecords(request); err != nil { - return err - } - - if *record.Status == "disable" { - request := teo.NewModifyDnsRecordsStatusRequest() - request.ZoneId = common.StringPtr(d.config.ZoneID) - request.RecordsToEnable = []*string{record.RecordId} - if _, err = d.client.ModifyDnsRecordsStatus(request); err != nil { - return err - } - } - - return nil - } +func (d *DNSProvider) addDNSRecord(effectiveFQDN, value string) error { + request := teo.NewCreateDnsRecordRequest() + request.ZoneId = common.StringPtr(d.config.ZoneID) + request.Name = common.StringPtr(effectiveFQDN) + request.Type = common.StringPtr("TXT") + request.Content = common.StringPtr(value) + request.TTL = common.Int64Ptr(int64(d.config.TTL)) + _, err := d.client.CreateDnsRecord(request) + return err } -func (d *DNSProvider) removeDNSRecord(effectiveFQDN string) error { - record, err := d.findDNSRecord(effectiveFQDN) +func (d *DNSProvider) removeDNSRecord(effectiveFQDN, value string) error { + record, err := d.findDNSRecord(effectiveFQDN, value) if err != nil { return err } From d472915f428d91369ceabb9b4358faca6e7c08d4 Mon Sep 17 00:00:00 2001 From: Netrvin <11222509+Netrvin@users.noreply.github.com> Date: Mon, 14 Jul 2025 20:01:56 +0800 Subject: [PATCH 4/7] =?UTF-8?q?fix:=20=E8=85=BE=E8=AE=AF=E4=BA=91edgeone?= =?UTF-8?q?=20DNS=E4=B8=8D=E6=94=AF=E6=8C=81=E7=AD=BE=E5=8F=91=E5=90=8C?= =?UTF-8?q?=E6=97=B6=E5=8C=85=E5=90=ABexample.com=E5=92=8C*.example.com?= =?UTF-8?q?=E7=9A=84=E8=AF=81=E4=B9=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tencentcloud-eo/internal/lego.go | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/pkg/core/ssl-applicator/acme-dns01/providers/tencentcloud-eo/internal/lego.go b/pkg/core/ssl-applicator/acme-dns01/providers/tencentcloud-eo/internal/lego.go index db33ea90b..6f7addc0f 100644 --- a/pkg/core/ssl-applicator/acme-dns01/providers/tencentcloud-eo/internal/lego.go +++ b/pkg/core/ssl-applicator/acme-dns01/providers/tencentcloud-eo/internal/lego.go @@ -152,14 +152,31 @@ func (d *DNSProvider) findDNSRecord(effectiveFQDN, value string) (*teo.DnsRecord } func (d *DNSProvider) addDNSRecord(effectiveFQDN, value string) error { - request := teo.NewCreateDnsRecordRequest() - request.ZoneId = common.StringPtr(d.config.ZoneID) - request.Name = common.StringPtr(effectiveFQDN) - request.Type = common.StringPtr("TXT") - request.Content = common.StringPtr(value) - request.TTL = common.Int64Ptr(int64(d.config.TTL)) - _, err := d.client.CreateDnsRecord(request) - return err + record, err := d.findDNSRecord(effectiveFQDN, value) + if err != nil { + return err + } + + if record == nil { + request := teo.NewCreateDnsRecordRequest() + request.ZoneId = common.StringPtr(d.config.ZoneID) + request.Name = common.StringPtr(effectiveFQDN) + request.Type = common.StringPtr("TXT") + request.Content = common.StringPtr(value) + request.TTL = common.Int64Ptr(int64(d.config.TTL)) + _, err := d.client.CreateDnsRecord(request) + return err + } else { + if *record.Status == "disable" { + request := teo.NewModifyDnsRecordsStatusRequest() + request.ZoneId = common.StringPtr(d.config.ZoneID) + request.RecordsToEnable = []*string{record.RecordId} + if _, err = d.client.ModifyDnsRecordsStatus(request); err != nil { + return err + } + } + return nil + } } func (d *DNSProvider) removeDNSRecord(effectiveFQDN, value string) error { From 655465431c4ab19ed12921985658fb3b13f3e793 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Mon, 14 Jul 2025 21:22:23 +0800 Subject: [PATCH 5/7] fix: #861 --- .../tencentcloud-clb/tencentcloud_clb.go | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/pkg/core/ssl-deployer/providers/tencentcloud-clb/tencentcloud_clb.go b/pkg/core/ssl-deployer/providers/tencentcloud-clb/tencentcloud_clb.go index 710733c4c..72baecd9f 100644 --- a/pkg/core/ssl-deployer/providers/tencentcloud-clb/tencentcloud_clb.go +++ b/pkg/core/ssl-deployer/providers/tencentcloud-clb/tencentcloud_clb.go @@ -303,6 +303,33 @@ func (d *SSLDeployerProvider) deployToRuleDomain(ctx context.Context, cloudCertI return fmt.Errorf("failed to execute sdk request 'clb.ModifyDomainAttributes': %w", err) } + // 循环查询异步任务状态,等待任务状态变更 + // REF: https://cloud.tencent.com/document/product/214/30683 + for { + select { + case <-ctx.Done(): + return ctx.Err() + default: + } + + describeTaskStatusReq := tcclb.NewDescribeTaskStatusRequest() + describeTaskStatusReq.TaskId = modifyDomainAttributesResp.Response.RequestId + describeTaskStatusResp, err := d.sdkClients.CLB.DescribeTaskStatus(describeTaskStatusReq) + d.logger.Debug("sdk request 'clb.DescribeTaskStatus'", slog.Any("request", describeTaskStatusReq), slog.Any("response", describeTaskStatusResp)) + if err != nil { + return fmt.Errorf("failed to execute sdk request 'clb.DescribeTaskStatus': %w", err) + } + + if describeTaskStatusResp.Response.Status == nil || *describeTaskStatusResp.Response.Status == 1 { + return errors.New("unexpected task status") + } else if *describeTaskStatusResp.Response.Status == 0 { + break + } + + d.logger.Info("waiting for task completion ...") + time.Sleep(time.Second * 5) + } + return nil } @@ -338,6 +365,33 @@ func (d *SSLDeployerProvider) modifyListenerCertificate(ctx context.Context, clo return fmt.Errorf("failed to execute sdk request 'clb.ModifyListener': %w", err) } + // 循环查询异步任务状态,等待任务状态变更 + // REF: https://cloud.tencent.com/document/product/214/30683 + for { + select { + case <-ctx.Done(): + return ctx.Err() + default: + } + + describeTaskStatusReq := tcclb.NewDescribeTaskStatusRequest() + describeTaskStatusReq.TaskId = modifyListenerResp.Response.RequestId + describeTaskStatusResp, err := d.sdkClients.CLB.DescribeTaskStatus(describeTaskStatusReq) + d.logger.Debug("sdk request 'clb.DescribeTaskStatus'", slog.Any("request", describeTaskStatusReq), slog.Any("response", describeTaskStatusResp)) + if err != nil { + return fmt.Errorf("failed to execute sdk request 'clb.DescribeTaskStatus': %w", err) + } + + if describeTaskStatusResp.Response.Status == nil || *describeTaskStatusResp.Response.Status == 1 { + return errors.New("unexpected task status") + } else if *describeTaskStatusResp.Response.Status == 0 { + break + } + + d.logger.Info("waiting for task completion ...") + time.Sleep(time.Second * 5) + } + return nil } From 9ae7a902274211f2fc413a152c2ba2fc6848d504 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Mon, 14 Jul 2025 21:22:48 +0800 Subject: [PATCH 6/7] fix: fix typo --- .../ssl-deployer/providers/huaweicloud-cdn/huaweicloud_cdn.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/core/ssl-deployer/providers/huaweicloud-cdn/huaweicloud_cdn.go b/pkg/core/ssl-deployer/providers/huaweicloud-cdn/huaweicloud_cdn.go index ef514c66e..d8616a94b 100644 --- a/pkg/core/ssl-deployer/providers/huaweicloud-cdn/huaweicloud_cdn.go +++ b/pkg/core/ssl-deployer/providers/huaweicloud-cdn/huaweicloud_cdn.go @@ -121,9 +121,9 @@ func (d *SSLDeployerProvider) Deploy(ctx context.Context, certPEM string, privke }, } updateDomainMultiCertificatesResp, err := d.sdkClient.UpdateDomainMultiCertificates(updateDomainMultiCertificatesReq) - d.logger.Debug("sdk request 'cdn.UploadDomainMultiCertificates'", slog.Any("request", updateDomainMultiCertificatesReq), slog.Any("response", updateDomainMultiCertificatesResp)) + d.logger.Debug("sdk request 'cdn.UpdateDomainMultiCertificates'", slog.Any("request", updateDomainMultiCertificatesReq), slog.Any("response", updateDomainMultiCertificatesResp)) if err != nil { - return nil, fmt.Errorf("failed to execute sdk request 'cdn.UploadDomainMultiCertificates': %w", err) + return nil, fmt.Errorf("failed to execute sdk request 'cdn.UpdateDomainMultiCertificates': %w", err) } return &core.SSLDeployResult{}, nil From dfd5bff043c5668e97548195145d38d9168b3644 Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Mon, 14 Jul 2025 22:09:43 +0800 Subject: [PATCH 7/7] fix: #870 --- .../ssl-deployer/providers/huaweicloud-cdn/huaweicloud_cdn.go | 2 +- .../node/DeployNodeConfigFormHuaweiCloudCDNConfig.tsx | 4 +++- ui/src/i18n/locales/zh/nls.workflow.nodes.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/pkg/core/ssl-deployer/providers/huaweicloud-cdn/huaweicloud_cdn.go b/pkg/core/ssl-deployer/providers/huaweicloud-cdn/huaweicloud_cdn.go index d8616a94b..b7293de4b 100644 --- a/pkg/core/ssl-deployer/providers/huaweicloud-cdn/huaweicloud_cdn.go +++ b/pkg/core/ssl-deployer/providers/huaweicloud-cdn/huaweicloud_cdn.go @@ -25,7 +25,7 @@ type SSLDeployerProviderConfig struct { EnterpriseProjectId string `json:"enterpriseProjectId,omitempty"` // 华为云区域。 Region string `json:"region"` - // 加速域名(不支持泛域名)。 + // 加速域名(支持泛域名)。 Domain string `json:"domain"` } diff --git a/ui/src/components/workflow/node/DeployNodeConfigFormHuaweiCloudCDNConfig.tsx b/ui/src/components/workflow/node/DeployNodeConfigFormHuaweiCloudCDNConfig.tsx index 9bdab801f..634a062c4 100644 --- a/ui/src/components/workflow/node/DeployNodeConfigFormHuaweiCloudCDNConfig.tsx +++ b/ui/src/components/workflow/node/DeployNodeConfigFormHuaweiCloudCDNConfig.tsx @@ -35,7 +35,9 @@ const DeployNodeConfigFormHuaweiCloudCDNConfig = ({ region: z .string(t("workflow_node.deploy.form.huaweicloud_cdn_region.placeholder")) .nonempty(t("workflow_node.deploy.form.huaweicloud_cdn_region.placeholder")), - domain: z.string(t("workflow_node.deploy.form.huaweicloud_cdn_domain.placeholder")).refine((v) => validDomainName(v), t("common.errmsg.domain_invalid")), + domain: z + .string(t("workflow_node.deploy.form.huaweicloud_cdn_domain.placeholder")) + .refine((v) => validDomainName(v, { allowWildcard: true }), t("common.errmsg.domain_invalid")), }); const formRule = createSchemaFieldRule(formSchema); diff --git a/ui/src/i18n/locales/zh/nls.workflow.nodes.json b/ui/src/i18n/locales/zh/nls.workflow.nodes.json index 09fc27e95..795b3153b 100644 --- a/ui/src/i18n/locales/zh/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/zh/nls.workflow.nodes.json @@ -453,7 +453,7 @@ "workflow_node.deploy.form.huaweicloud_cdn_region.placeholder": "请输入华为云 CDN 服务区域(例如:cn-north-1)", "workflow_node.deploy.form.huaweicloud_cdn_region.tooltip": "这是什么?请参阅 https://console.huaweicloud.com/apiexplorer/#/endpoint", "workflow_node.deploy.form.huaweicloud_cdn_domain.label": "华为云 CDN 加速域名", - "workflow_node.deploy.form.huaweicloud_cdn_domain.placeholder": "请输入华为云 CDN 加速域名", + "workflow_node.deploy.form.huaweicloud_cdn_domain.placeholder": "请输入华为云 CDN 加速域名(支持泛域名)", "workflow_node.deploy.form.huaweicloud_cdn_domain.tooltip": "这是什么?请参阅 https://console.huaweicloud.com/cdn", "workflow_node.deploy.form.huaweicloud_elb_region.label": "华为云 ELB 服务区域", "workflow_node.deploy.form.huaweicloud_elb_region.placeholder": "请输入华为云 ELB 服务区域(例如:cn-north-1)",