This commit is contained in:
Fu Diwei 2025-03-20 21:41:56 +08:00
parent 09b1bf6e2d
commit 8e4b3d12bd
6 changed files with 57 additions and 23 deletions

View File

@ -69,12 +69,12 @@ func (d *DeployerProvider) WithLogger(logger *slog.Logger) deployer.Deployer {
func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) {
switch d.config.ServiceVersion { switch d.config.ServiceVersion {
case "3.0": case "3", "3.0":
if err := d.deployToFC3(ctx, certPem, privkeyPem); err != nil { if err := d.deployToFC3(ctx, certPem, privkeyPem); err != nil {
return nil, err return nil, err
} }
case "2.0": case "2", "2.0":
if err := d.deployToFC2(ctx, certPem, privkeyPem); err != nil { if err := d.deployToFC2(ctx, certPem, privkeyPem); err != nil {
return nil, err return nil, err
} }

View File

@ -24,6 +24,8 @@ type DeployerConfig struct {
AccessKeySecret string `json:"accessKeySecret"` AccessKeySecret string `json:"accessKeySecret"`
// 阿里云地域。 // 阿里云地域。
Region string `json:"region"` Region string `json:"region"`
// 服务版本。
ServiceVersion string `json:"serviceVersion"`
// WAF 实例 ID。 // WAF 实例 ID。
InstanceId string `json:"instanceId"` InstanceId string `json:"instanceId"`
// 接入域名(支持泛域名)。 // 接入域名(支持泛域名)。
@ -77,10 +79,24 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
return nil, errors.New("config `instanceId` is required") return nil, errors.New("config `instanceId` is required")
} }
switch d.config.ServiceVersion {
case "3", "3.0":
if err := d.deployToWAF3(ctx, certPem, privkeyPem); err != nil {
return nil, err
}
default:
return nil, xerrors.Errorf("unsupported service version: %s", d.config.ServiceVersion)
}
return &deployer.DeployResult{}, nil
}
func (d *DeployerProvider) deployToWAF3(ctx context.Context, certPem string, privkeyPem string) error {
// 上传证书到 CAS // 上传证书到 CAS
upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem) upres, err := d.sslUploader.Upload(ctx, certPem, privkeyPem)
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to upload certificate file") return xerrors.Wrap(err, "failed to upload certificate file")
} else { } else {
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres)) d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
} }
@ -97,7 +113,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
describeDefaultHttpsResp, err := d.sdkClient.DescribeDefaultHttps(describeDefaultHttpsReq) describeDefaultHttpsResp, err := d.sdkClient.DescribeDefaultHttps(describeDefaultHttpsReq)
d.logger.Debug("sdk request 'waf.DescribeDefaultHttps'", slog.Any("request", describeDefaultHttpsReq), slog.Any("response", describeDefaultHttpsResp)) d.logger.Debug("sdk request 'waf.DescribeDefaultHttps'", slog.Any("request", describeDefaultHttpsReq), slog.Any("response", describeDefaultHttpsResp))
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'waf.DescribeDefaultHttps'") return xerrors.Wrap(err, "failed to execute sdk request 'waf.DescribeDefaultHttps'")
} }
// 修改默认 SSL/TLS 设置 // 修改默认 SSL/TLS 设置
@ -116,7 +132,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
modifyDefaultHttpsResp, err := d.sdkClient.ModifyDefaultHttps(modifyDefaultHttpsReq) modifyDefaultHttpsResp, err := d.sdkClient.ModifyDefaultHttps(modifyDefaultHttpsReq)
d.logger.Debug("sdk request 'waf.ModifyDefaultHttps'", slog.Any("request", modifyDefaultHttpsReq), slog.Any("response", modifyDefaultHttpsResp)) d.logger.Debug("sdk request 'waf.ModifyDefaultHttps'", slog.Any("request", modifyDefaultHttpsReq), slog.Any("response", modifyDefaultHttpsResp))
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'waf.ModifyDefaultHttps'") return xerrors.Wrap(err, "failed to execute sdk request 'waf.ModifyDefaultHttps'")
} }
} else { } else {
// 指定接入域名 // 指定接入域名
@ -131,7 +147,7 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
describeDomainDetailResp, err := d.sdkClient.DescribeDomainDetail(describeDomainDetailReq) describeDomainDetailResp, err := d.sdkClient.DescribeDomainDetail(describeDomainDetailReq)
d.logger.Debug("sdk request 'waf.DescribeDomainDetail'", slog.Any("request", describeDomainDetailReq), slog.Any("response", describeDomainDetailResp)) d.logger.Debug("sdk request 'waf.DescribeDomainDetail'", slog.Any("request", describeDomainDetailReq), slog.Any("response", describeDomainDetailResp))
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'waf.DescribeDomainDetail'") return xerrors.Wrap(err, "failed to execute sdk request 'waf.DescribeDomainDetail'")
} }
// 修改 CNAME 接入资源 // 修改 CNAME 接入资源
@ -163,11 +179,11 @@ func (d *DeployerProvider) Deploy(ctx context.Context, certPem string, privkeyPe
modifyDomainResp, err := d.sdkClient.ModifyDomain(modifyDomainReq) modifyDomainResp, err := d.sdkClient.ModifyDomain(modifyDomainReq)
d.logger.Debug("sdk request 'waf.ModifyDomain'", slog.Any("request", modifyDomainReq), slog.Any("response", modifyDomainResp)) d.logger.Debug("sdk request 'waf.ModifyDomain'", slog.Any("request", modifyDomainReq), slog.Any("response", modifyDomainResp))
if err != nil { if err != nil {
return nil, xerrors.Wrap(err, "failed to execute sdk request 'waf.ModifyDomain'") return xerrors.Wrap(err, "failed to execute sdk request 'waf.ModifyDomain'")
} }
} }
return &deployer.DeployResult{}, nil return nil
} }
func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunWaf.Client, error) { func createSdkClient(accessKeyId, accessKeySecret, region string) (*aliyunWaf.Client, error) {

View File

@ -55,6 +55,15 @@ const DeployNodeConfigFormAliyunFCConfig = ({ form: formInst, formName, disabled
name={formName} name={formName}
onValuesChange={handleFormChange} onValuesChange={handleFormChange}
> >
<Form.Item
name="region"
label={t("workflow_node.deploy.form.aliyun_fc_region.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_fc_region.tooltip") }}></span>}
>
<Input placeholder={t("workflow_node.deploy.form.aliyun_fc_region.placeholder")} />
</Form.Item>
<Form.Item name="serviceVersion" label={t("workflow_node.deploy.form.aliyun_fc_service_version.label")} rules={[formRule]}> <Form.Item name="serviceVersion" label={t("workflow_node.deploy.form.aliyun_fc_service_version.label")} rules={[formRule]}>
<Select placeholder={t("workflow_node.deploy.form.aliyun_fc_service_version.placeholder")}> <Select placeholder={t("workflow_node.deploy.form.aliyun_fc_service_version.placeholder")}>
<Select.Option key="2.0" value="2.0"> <Select.Option key="2.0" value="2.0">
@ -66,15 +75,6 @@ const DeployNodeConfigFormAliyunFCConfig = ({ form: formInst, formName, disabled
</Select> </Select>
</Form.Item> </Form.Item>
<Form.Item
name="region"
label={t("workflow_node.deploy.form.aliyun_fc_region.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_fc_region.tooltip") }}></span>}
>
<Input placeholder={t("workflow_node.deploy.form.aliyun_fc_region.placeholder")} />
</Form.Item>
<Form.Item <Form.Item
name="domain" name="domain"
label={t("workflow_node.deploy.form.aliyun_fc_domain.label")} label={t("workflow_node.deploy.form.aliyun_fc_domain.label")}

View File

@ -1,5 +1,5 @@
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Form, type FormInstance, Input } from "antd"; import { Form, type FormInstance, Input, Select } from "antd";
import { createSchemaFieldRule } from "antd-zod"; import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod"; import { z } from "zod";
@ -7,6 +7,7 @@ import { validDomainName } from "@/utils/validators";
type DeployNodeConfigFormAliyunWAFConfigFieldValues = Nullish<{ type DeployNodeConfigFormAliyunWAFConfigFieldValues = Nullish<{
region: string; region: string;
serviceVersion: string;
instanceId: string; instanceId: string;
domain?: string; domain?: string;
}>; }>;
@ -20,7 +21,9 @@ export type DeployNodeConfigFormAliyunWAFConfigProps = {
}; };
const initFormModel = (): DeployNodeConfigFormAliyunWAFConfigFieldValues => { const initFormModel = (): DeployNodeConfigFormAliyunWAFConfigFieldValues => {
return {}; return {
serviceVersion: "3.0",
};
}; };
const DeployNodeConfigFormAliyunWAFConfig = ({ const DeployNodeConfigFormAliyunWAFConfig = ({
@ -37,6 +40,9 @@ const DeployNodeConfigFormAliyunWAFConfig = ({
.string({ message: t("workflow_node.deploy.form.aliyun_waf_region.placeholder") }) .string({ message: t("workflow_node.deploy.form.aliyun_waf_region.placeholder") })
.nonempty(t("workflow_node.deploy.form.aliyun_waf_region.placeholder")) .nonempty(t("workflow_node.deploy.form.aliyun_waf_region.placeholder"))
.trim(), .trim(),
serviceVersion: z.literal("3.0", {
message: t("workflow_node.deploy.form.aliyun_waf_service_version.placeholder"),
}),
instanceId: z instanceId: z
.string({ message: t("workflow_node.deploy.form.aliyun_waf_instance_id.placeholder") }) .string({ message: t("workflow_node.deploy.form.aliyun_waf_instance_id.placeholder") })
.nonempty(t("workflow_node.deploy.form.aliyun_waf_instance_id.placeholder")) .nonempty(t("workflow_node.deploy.form.aliyun_waf_instance_id.placeholder"))
@ -73,6 +79,14 @@ const DeployNodeConfigFormAliyunWAFConfig = ({
<Input placeholder={t("workflow_node.deploy.form.aliyun_waf_region.placeholder")} /> <Input placeholder={t("workflow_node.deploy.form.aliyun_waf_region.placeholder")} />
</Form.Item> </Form.Item>
<Form.Item name="serviceVersion" label={t("workflow_node.deploy.form.aliyun_waf_service_version.label")} rules={[formRule]}>
<Select placeholder={t("workflow_node.deploy.form.aliyun_waf_service_version.placeholder")}>
<Select.Option key="3.0" value="3.0">
3.0
</Select.Option>
</Select>
</Form.Item>
<Form.Item <Form.Item
name="instanceId" name="instanceId"
label={t("workflow_node.deploy.form.aliyun_waf_instance_id.label")} label={t("workflow_node.deploy.form.aliyun_waf_instance_id.label")}

View File

@ -88,7 +88,7 @@
"workflow_node.deploy.form.provider_access.guide_for_local": "Tips: Due to the form validations, youe need to select an authorization for local deployment also, even if it means nothing.", "workflow_node.deploy.form.provider_access.guide_for_local": "Tips: Due to the form validations, youe need to select an authorization for local deployment also, even if it means nothing.",
"workflow_node.deploy.form.certificate.label": "Certificate", "workflow_node.deploy.form.certificate.label": "Certificate",
"workflow_node.deploy.form.certificate.placeholder": "Please select certificate", "workflow_node.deploy.form.certificate.placeholder": "Please select certificate",
"workflow_node.deploy.form.certificate.tooltip": "The certificate to be deployed comes from the previous application stage node.", "workflow_node.deploy.form.certificate.tooltip": "The certificate to be deployed comes from the previous nodes of application or upload.",
"workflow_node.deploy.form.params_config.label": "Parameter settings", "workflow_node.deploy.form.params_config.label": "Parameter settings",
"workflow_node.deploy.form.1panel_console_auto_restart.label": "Auto restart after deployment", "workflow_node.deploy.form.1panel_console_auto_restart.label": "Auto restart after deployment",
"workflow_node.deploy.form.1panel_site_website_id.label": "1Panel website ID", "workflow_node.deploy.form.1panel_site_website_id.label": "1Panel website ID",
@ -199,6 +199,8 @@
"workflow_node.deploy.form.aliyun_waf_region.label": "Alibaba Cloud WAF region", "workflow_node.deploy.form.aliyun_waf_region.label": "Alibaba Cloud WAF region",
"workflow_node.deploy.form.aliyun_waf_region.placeholder": "Please enter Alibaba Cloud WAF region (e.g. cn-hangzhou)", "workflow_node.deploy.form.aliyun_waf_region.placeholder": "Please enter Alibaba Cloud WAF region (e.g. cn-hangzhou)",
"workflow_node.deploy.form.aliyun_waf_region.tooltip": "For more information, see <a href=\"https://www.alibabacloud.com/help/en/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-endpoint\" target=\"_blank\">https://www.alibabacloud.com/help/en/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-endpoint</a>", "workflow_node.deploy.form.aliyun_waf_region.tooltip": "For more information, see <a href=\"https://www.alibabacloud.com/help/en/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-endpoint\" target=\"_blank\">https://www.alibabacloud.com/help/en/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-endpoint</a>",
"workflow_node.deploy.form.aliyun_waf_service_version.label": "Alibaba Cloud WAF version",
"workflow_node.deploy.form.aliyun_waf_service_version.placeholder": "Please select Alibaba Cloud WAF version",
"workflow_node.deploy.form.aliyun_waf_instance_id.label": "Alibaba Cloud WAF instance ID", "workflow_node.deploy.form.aliyun_waf_instance_id.label": "Alibaba Cloud WAF instance ID",
"workflow_node.deploy.form.aliyun_waf_instance_id.placeholder": "Please enter Alibaba Cloud WAF instance ID", "workflow_node.deploy.form.aliyun_waf_instance_id.placeholder": "Please enter Alibaba Cloud WAF instance ID",
"workflow_node.deploy.form.aliyun_waf_instance_id.tooltip": "For more information, see <a href=\"https://waf.console.aliyun.com\" target=\"_blank\">https://waf.console.aliyun.com</a>", "workflow_node.deploy.form.aliyun_waf_instance_id.tooltip": "For more information, see <a href=\"https://waf.console.aliyun.com\" target=\"_blank\">https://waf.console.aliyun.com</a>",

View File

@ -39,7 +39,7 @@
"workflow_node.apply.form.provider_access.button": "新建", "workflow_node.apply.form.provider_access.button": "新建",
"workflow_node.apply.form.aws_route53_region.label": "AWS Route53 服务区域", "workflow_node.apply.form.aws_route53_region.label": "AWS Route53 服务区域",
"workflow_node.apply.form.aws_route53_region.placeholder": "请输入 AWS Route53 服务区域例如us-east-1", "workflow_node.apply.form.aws_route53_region.placeholder": "请输入 AWS Route53 服务区域例如us-east-1",
"workflow_node.apply.form.aws_route53_region.tooltip": "这是什么?请参阅 <a href=\"https://docs.aws.amazon.com/zh_cn/general/latest/gr/rande.html#regional-endpoints\" tworkflow_node.applyank\">https://docs.aws.amazon.com/zh_cn/general/latest/gr/rande.html#regional-endpoints</a>", "workflow_node.apply.form.aws_route53_region.tooltip": "这是什么?请参阅 <a href=\"https://docs.aws.amazon.com/zh_cn/general/latest/gr/rande.html#regional-endpoints\" target=\"_blank\">https://docs.aws.amazon.com/zh_cn/general/latest/gr/rande.html#regional-endpoints</a>",
"workflow_node.apply.form.aws_route53_hosted_zone_id.label": "AWS Route53 托管区域 ID", "workflow_node.apply.form.aws_route53_hosted_zone_id.label": "AWS Route53 托管区域 ID",
"workflow_node.apply.form.aws_route53_hosted_zone_id.placeholder": "请输入 AWS Route53 托管区域 ID", "workflow_node.apply.form.aws_route53_hosted_zone_id.placeholder": "请输入 AWS Route53 托管区域 ID",
"workflow_node.apply.form.aws_route53_hosted_zone_id.tooltip": "这是什么?请参阅 <a href=\"https://docs.aws.amazon.com/zh_cn/Route53/latest/DeveloperGuide/hosted-zones-working-with.html\" target=\"_blank\">https://docs.aws.amazon.com/zh_cn/Route53/latest/DeveloperGuide/hosted-zones-working-with.html</a>", "workflow_node.apply.form.aws_route53_hosted_zone_id.tooltip": "这是什么?请参阅 <a href=\"https://docs.aws.amazon.com/zh_cn/Route53/latest/DeveloperGuide/hosted-zones-working-with.html\" target=\"_blank\">https://docs.aws.amazon.com/zh_cn/Route53/latest/DeveloperGuide/hosted-zones-working-with.html</a>",
@ -88,7 +88,7 @@
"workflow_node.deploy.form.provider_access.guide_for_local": "小贴士:由于表单限制,你同样需要为本地部署选择一个授权 —— 即使它是空白的。<br>请注意,如果你使用 Docker 安装 Certimate“本地部署”将会部署到容器内而非宿主机上。", "workflow_node.deploy.form.provider_access.guide_for_local": "小贴士:由于表单限制,你同样需要为本地部署选择一个授权 —— 即使它是空白的。<br>请注意,如果你使用 Docker 安装 Certimate“本地部署”将会部署到容器内而非宿主机上。",
"workflow_node.deploy.form.certificate.label": "待部署证书", "workflow_node.deploy.form.certificate.label": "待部署证书",
"workflow_node.deploy.form.certificate.placeholder": "请选择待部署证书", "workflow_node.deploy.form.certificate.placeholder": "请选择待部署证书",
"workflow_node.deploy.form.certificate.tooltip": "待部署证书来自之前的申请阶段。如果选项为空请先确保前序节点配置正确。", "workflow_node.deploy.form.certificate.tooltip": "待部署证书来自之前的申请或上传节点。如果选项为空请先确保前序节点配置正确。",
"workflow_node.deploy.form.params_config.label": "参数设置", "workflow_node.deploy.form.params_config.label": "参数设置",
"workflow_node.deploy.form.1panel_console_auto_restart.label": "部署后自动重启面板服务", "workflow_node.deploy.form.1panel_console_auto_restart.label": "部署后自动重启面板服务",
"workflow_node.deploy.form.1panel_site_website_id.label": "1Panel 网站 ID", "workflow_node.deploy.form.1panel_site_website_id.label": "1Panel 网站 ID",
@ -199,6 +199,8 @@
"workflow_node.deploy.form.aliyun_waf_region.label": "阿里云 WAF 服务地域", "workflow_node.deploy.form.aliyun_waf_region.label": "阿里云 WAF 服务地域",
"workflow_node.deploy.form.aliyun_waf_region.placeholder": "请输入阿里云 WAF 服务地域例如cn-hangzhou", "workflow_node.deploy.form.aliyun_waf_region.placeholder": "请输入阿里云 WAF 服务地域例如cn-hangzhou",
"workflow_node.deploy.form.aliyun_waf_region.tooltip": "这是什么?请参阅 <a href=\"https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-endpoint\" target=\"_blank\">https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-endpoint</a>", "workflow_node.deploy.form.aliyun_waf_region.tooltip": "这是什么?请参阅 <a href=\"https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-endpoint\" target=\"_blank\">https://help.aliyun.com/zh/waf/web-application-firewall-3-0/developer-reference/api-waf-openapi-2021-10-01-endpoint</a>",
"workflow_node.deploy.form.aliyun_waf_service_version.label": "阿里云 WAF 服务版本",
"workflow_node.deploy.form.aliyun_waf_service_version.placeholder": "请选择阿里云 WAF 服务版本",
"workflow_node.deploy.form.aliyun_waf_instance_id.label": "阿里云 WAF 实例 ID", "workflow_node.deploy.form.aliyun_waf_instance_id.label": "阿里云 WAF 实例 ID",
"workflow_node.deploy.form.aliyun_waf_instance_id.placeholder": "请输入阿里云 WAF 实例 ID", "workflow_node.deploy.form.aliyun_waf_instance_id.placeholder": "请输入阿里云 WAF 实例 ID",
"workflow_node.deploy.form.aliyun_waf_instance_id.tooltip": "这是什么?请参阅 <a href=\"https://waf.console.aliyun.com\" target=\"_blank\">https://waf.console.aliyun.com</a><br><br>仅支持 CNAME 接入。", "workflow_node.deploy.form.aliyun_waf_instance_id.tooltip": "这是什么?请参阅 <a href=\"https://waf.console.aliyun.com\" target=\"_blank\">https://waf.console.aliyun.com</a><br><br>仅支持 CNAME 接入。",
@ -207,7 +209,7 @@
"workflow_node.deploy.form.aliyun_waf_domain.tooltip": "这是什么?请参阅 <a href=\"https://waf.console.aliyun.com\" target=\"_blank\">waf.console.aliyun.com</a><br><br>不填写时,将替换实例的默认证书。", "workflow_node.deploy.form.aliyun_waf_domain.tooltip": "这是什么?请参阅 <a href=\"https://waf.console.aliyun.com\" target=\"_blank\">waf.console.aliyun.com</a><br><br>不填写时,将替换实例的默认证书。",
"workflow_node.deploy.form.aws_cloudfront_region.label": "AWS CloudFront 服务区域", "workflow_node.deploy.form.aws_cloudfront_region.label": "AWS CloudFront 服务区域",
"workflow_node.deploy.form.aws_cloudfront_region.placeholder": "请输入 AWS CloudFront 服务区域例如us-east-1", "workflow_node.deploy.form.aws_cloudfront_region.placeholder": "请输入 AWS CloudFront 服务区域例如us-east-1",
"workflow_node.deploy.form.aws_cloudfront_region.tooltip": "这是什么?请参阅 <a href=\"https://docs.aws.amazon.com/zh_cn/general/latest/gr/rande.html#regional-endpoints\" tworkflow_node.applyank\">https://docs.aws.amazon.com/zh_cn/general/latest/gr/rande.html#regional-endpoints</a>", "workflow_node.deploy.form.aws_cloudfront_region.tooltip": "这是什么?请参阅 <a href=\"https://docs.aws.amazon.com/zh_cn/general/latest/gr/rande.html#regional-endpoints\" target=\"_blank\">https://docs.aws.amazon.com/zh_cn/general/latest/gr/rande.html#regional-endpoints</a>",
"workflow_node.deploy.form.aws_cloudfront_distribution_id.label": "AWS CloudFront 分配 ID", "workflow_node.deploy.form.aws_cloudfront_distribution_id.label": "AWS CloudFront 分配 ID",
"workflow_node.deploy.form.aws_cloudfront_distribution_id.placeholder": "请输入 AWS CloudFront 分配 ID", "workflow_node.deploy.form.aws_cloudfront_distribution_id.placeholder": "请输入 AWS CloudFront 分配 ID",
"workflow_node.deploy.form.aws_cloudfront_distribution_id.tooltip": "这是什么?请参阅 <a href=\"https://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/distribution-working-with.html\" target=\"_blank\">https://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/distribution-working-with.html</a>", "workflow_node.deploy.form.aws_cloudfront_distribution_id.tooltip": "这是什么?请参阅 <a href=\"https://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/distribution-working-with.html\" target=\"_blank\">https://docs.aws.amazon.com/zh_cn/AmazonCloudFront/latest/DeveloperGuide/distribution-working-with.html</a>",