feat: add aliyun alb deployer

This commit is contained in:
Fu Diwei 2024-10-26 12:40:45 +08:00
parent 20d2c5699c
commit 1690963aaf
14 changed files with 460 additions and 34 deletions

View File

@ -73,7 +73,7 @@ make local.run
| 服务商 | 支持申请证书 | 支持部署证书 | 备注 |
| :--------: | :----------: | :----------: | ------------------------------------------------------------ |
| 阿里云 | √ | √ | 可签发在阿里云注册的域名;可部署到阿里云 OSS、CDN、CLB(SLB) |
| 阿里云 | √ | √ | 可签发在阿里云注册的域名;可部署到阿里云 OSS、CDN、SLB |
| 腾讯云 | √ | √ | 可签发在腾讯云注册的域名;可部署到腾讯云 COS、CDN、CLB |
| 华为云 | √ | √ | 可签发在华为云注册的域名;可部署到华为云 CDN、ELB |
| 七牛云 | | √ | 可部署到七牛云 CDN |

View File

@ -70,22 +70,22 @@ password1234567890
## List of Supported Providers
| Provider | Registration | Deployment | Remarks |
| :-----------: | :----------: | :--------: | ----------------------------------------------------------------------------------------------------- |
| Alibaba Cloud | √ | √ | Supports domains registered on Alibaba Cloud; supports deployment to Alibaba Cloud OSS, CDN, CLB(SLB) |
| Tencent Cloud | √ | √ | Supports domains registered on Tencent Cloud; supports deployment to Tencent Cloud COS, CDN, CLB |
| Huawei Cloud | √ | √ | Supports domains registered on Huawei Cloud; supports deployment to Huawei Cloud CDN, ELB |
| Qiniu Cloud | | √ | Supports deployment to Qiniu Cloud CDN |
| AWS | √ | | Supports domains managed on AWS Route53 |
| CloudFlare | √ | | Supports domains registered on CloudFlare; CloudFlare services come with SSL certificates |
| GoDaddy | √ | | Supports domains registered on GoDaddy |
| Namesilo | √ | | Supports domains registered on Namesilo |
| PowerDNS | √ | | Supports domains managed on PowerDNS |
| HTTP Request | √ | | Supports domains which allow managing DNS by HTTP request |
| Local Deploy | | √ | Supports deployment to local servers |
| SSH | | √ | Supports deployment to SSH servers |
| Webhook | | √ | Supports callback to Webhook |
| Kubernetes | | √ | Supports deployment to Kubernetes Secret |
| Provider | Registration | Deployment | Remarks |
| :-----------: | :----------: | :--------: | ------------------------------------------------------------------------------------------------ |
| Alibaba Cloud | √ | √ | Supports domains registered on Alibaba Cloud; supports deployment to Alibaba Cloud OSS, CDN, SLB |
| Tencent Cloud | √ | √ | Supports domains registered on Tencent Cloud; supports deployment to Tencent Cloud COS, CDN, CLB |
| Huawei Cloud | √ | √ | Supports domains registered on Huawei Cloud; supports deployment to Huawei Cloud CDN, ELB |
| Qiniu Cloud | | √ | Supports deployment to Qiniu Cloud CDN |
| AWS | √ | | Supports domains managed on AWS Route53 |
| CloudFlare | √ | | Supports domains registered on CloudFlare; CloudFlare services come with SSL certificates |
| GoDaddy | √ | | Supports domains registered on GoDaddy |
| Namesilo | √ | | Supports domains registered on Namesilo |
| PowerDNS | √ | | Supports domains managed on PowerDNS |
| HTTP Request | √ | | Supports domains which allow managing DNS by HTTP request |
| Local Deploy | | √ | Supports deployment to local servers |
| SSH | | √ | Supports deployment to SSH servers |
| Webhook | | √ | Supports callback to Webhook |
| Kubernetes | | √ | Supports deployment to Kubernetes Secret |
## Screenshots

1
go.mod
View File

@ -5,6 +5,7 @@ go 1.22.0
toolchain go1.23.2
require (
github.com/alibabacloud-go/alb-20200616/v2 v2.2.1
github.com/alibabacloud-go/cas-20200407/v3 v3.0.1
github.com/alibabacloud-go/cdn-20180510/v5 v5.0.0
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10

2
go.sum
View File

@ -29,6 +29,8 @@ github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDe
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
github.com/alex-ant/gomath v0.0.0-20160516115720-89013a210a82/go.mod h1:nLnM0KdK1CmygvjpDUO6m1TjSsiQtL61juhNsvV/JVI=
github.com/alibabacloud-go/alb-20200616/v2 v2.2.1 h1:b8ixnrkFhWrmJQd+iEE1UWPD5vdyC3d9l7G0uvkfi2s=
github.com/alibabacloud-go/alb-20200616/v2 v2.2.1/go.mod h1:cPdZwovbqpv+5nM/HnMwZpG5q0/gBuX31hu2H1VoyrM=
github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 h1:eIf+iGJxdU4U9ypaUfbtOWCsZSbTb8AUHvyPrxu6mAA=
github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6/go.mod h1:4EUIoxs/do24zMOGGqYVWgw0s9NtiylnJglOeEB5UJo=
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc=

View File

@ -0,0 +1,232 @@
package deployer
import (
"context"
"encoding/json"
"errors"
"fmt"
alb20200616 "github.com/alibabacloud-go/alb-20200616/v2/client"
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
"github.com/alibabacloud-go/tea/tea"
"github.com/usual2970/certimate/internal/domain"
"github.com/usual2970/certimate/internal/pkg/core/uploader"
)
type AliyunALBDeployer struct {
option *DeployerOption
infos []string
sdkClient *alb20200616.Client
sslUploader uploader.Uploader
}
func NewAliyunALBDeployer(option *DeployerOption) (Deployer, error) {
access := &domain.AliyunAccess{}
json.Unmarshal([]byte(option.Access), access)
client, err := (&AliyunALBDeployer{}).createSdkClient(
access.AccessKeyId,
access.AccessKeySecret,
option.DeployConfig.GetConfigAsString("region"),
)
if err != nil {
return nil, err
}
uploader, err := uploader.NewAliyunCASUploader(&uploader.AliyunCASUploaderConfig{
AccessKeyId: access.AccessKeyId,
AccessKeySecret: access.AccessKeySecret,
Region: option.DeployConfig.GetConfigAsString("region"),
})
if err != nil {
return nil, err
}
return &AliyunALBDeployer{
option: option,
infos: make([]string, 0),
sdkClient: client,
sslUploader: uploader,
}, nil
}
func (d *AliyunALBDeployer) GetID() string {
return fmt.Sprintf("%s-%s", d.option.AccessRecord.GetString("name"), d.option.AccessRecord.Id)
}
func (d *AliyunALBDeployer) GetInfo() []string {
return d.infos
}
func (d *AliyunALBDeployer) Deploy(ctx context.Context) error {
switch d.option.DeployConfig.GetConfigAsString("resourceType") {
case "loadbalancer":
if err := d.deployToLoadbalancer(ctx); err != nil {
return err
}
case "listener":
if err := d.deployToListener(ctx); err != nil {
return err
}
default:
return errors.New("unsupported resource type")
}
return nil
}
func (d *AliyunALBDeployer) createSdkClient(accessKeyId, accessKeySecret, region string) (*alb20200616.Client, error) {
if region == "" {
region = "cn-hangzhou" // ALB 服务默认区域:华东一杭州
}
aConfig := &openapi.Config{
AccessKeyId: tea.String(accessKeyId),
AccessKeySecret: tea.String(accessKeySecret),
}
var endpoint string
switch region {
case "cn-hangzhou-finance":
endpoint = "alb.cn-hangzhou.aliyuncs.com"
default:
endpoint = fmt.Sprintf("alb.%s.aliyuncs.com", region)
}
aConfig.Endpoint = tea.String(endpoint)
client, err := alb20200616.NewClient(aConfig)
if err != nil {
return nil, err
}
return client, nil
}
func (d *AliyunALBDeployer) deployToLoadbalancer(ctx context.Context) error {
aliLoadbalancerId := d.option.DeployConfig.GetConfigAsString("loadbalancerId")
if aliLoadbalancerId == "" {
return errors.New("`loadbalancerId` is required")
}
// 查询负载均衡实例的详细信息
// REF: https://help.aliyun.com/zh/slb/application-load-balancer/developer-reference/api-alb-2020-06-16-getloadbalancerattribute
getLoadBalancerAttributeReq := &alb20200616.GetLoadBalancerAttributeRequest{
LoadBalancerId: tea.String(aliLoadbalancerId),
}
getLoadBalancerAttributeResp, err := d.sdkClient.GetLoadBalancerAttribute(getLoadBalancerAttributeReq)
if err != nil {
return fmt.Errorf("failed to execute sdk request 'alb.GetLoadBalancerAttribute': %w", err)
}
d.infos = append(d.infos, toStr("已查询到 ALB 负载均衡实例", getLoadBalancerAttributeResp))
// 查询监听列表
// REF: https://help.aliyun.com/zh/slb/application-load-balancer/developer-reference/api-alb-2020-06-16-listlisteners
aliListenerIds := make([]string, 0)
listListenersPage := 1
listListenersLimit := int32(100)
var listListenersToken *string = nil
for {
listListenersReq := &alb20200616.ListListenersRequest{
MaxResults: tea.Int32(listListenersLimit),
NextToken: listListenersToken,
LoadBalancerIds: []*string{tea.String(aliLoadbalancerId)},
ListenerProtocol: tea.String("HTTPS"),
}
listListenersResp, err := d.sdkClient.ListListeners(listListenersReq)
if err != nil {
return fmt.Errorf("failed to execute sdk request 'alb.ListListeners': %w", err)
}
if listListenersResp.Body.Listeners != nil {
for _, listener := range listListenersResp.Body.Listeners {
aliListenerIds = append(aliListenerIds, *listener.ListenerId)
}
}
if listListenersResp.Body.NextToken == nil {
break
} else {
listListenersToken = listListenersResp.Body.NextToken
listListenersPage += 1
}
}
d.infos = append(d.infos, toStr("已查询到 ALB 负载均衡实例下的全部 HTTPS 监听", aliListenerIds))
// 上传证书到 SSL
uploadResult, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey)
if err != nil {
return err
}
d.infos = append(d.infos, toStr("已上传证书", uploadResult))
// 批量更新监听证书
var errs []error
for _, aliListenerId := range aliListenerIds {
if err := d.updateListenerCertificate(ctx, aliListenerId, uploadResult.CertId); err != nil {
errs = append(errs, err)
}
}
if len(errs) > 0 {
return errors.Join(errs...)
}
return nil
}
func (d *AliyunALBDeployer) deployToListener(ctx context.Context) error {
aliListenerId := d.option.DeployConfig.GetConfigAsString("listenerId")
if aliListenerId == "" {
return errors.New("`listenerId` is required")
}
// 上传证书到 SSL
uploadResult, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey)
if err != nil {
return err
}
d.infos = append(d.infos, toStr("已上传证书", uploadResult))
// 更新监听
if err := d.updateListenerCertificate(ctx, aliListenerId, uploadResult.CertId); err != nil {
return err
}
return nil
}
func (d *AliyunALBDeployer) updateListenerCertificate(ctx context.Context, aliListenerId string, aliCertId string) error {
// 查询监听的属性
// REF: https://help.aliyun.com/zh/slb/application-load-balancer/developer-reference/api-alb-2020-06-16-getlistenerattribute
getListenerAttributeReq := &alb20200616.GetListenerAttributeRequest{
ListenerId: tea.String(aliListenerId),
}
getListenerAttributeResp, err := d.sdkClient.GetListenerAttribute(getListenerAttributeReq)
if err != nil {
return fmt.Errorf("failed to execute sdk request 'alb.GetListenerAttribute': %w", err)
}
d.infos = append(d.infos, toStr("已查询到 ALB 监听配置", getListenerAttributeResp))
// 修改监听的属性
// REF: https://help.aliyun.com/zh/slb/application-load-balancer/developer-reference/api-alb-2020-06-16-updatelistenerattribute
updateListenerAttributeReq := &alb20200616.UpdateListenerAttributeRequest{
ListenerId: tea.String(aliListenerId),
Certificates: []*alb20200616.UpdateListenerAttributeRequestCertificates{{
CertificateId: tea.String(aliCertId),
}},
}
updateListenerAttributeResp, err := d.sdkClient.UpdateListenerAttribute(updateListenerAttributeReq)
if err != nil {
return fmt.Errorf("failed to execute sdk request 'alb.UpdateListenerAttribute': %w", err)
}
d.infos = append(d.infos, toStr("已更新 ALB 监听配置", updateListenerAttributeResp))
return nil
}

View File

@ -113,7 +113,7 @@ func (d *AliyunCLBDeployer) deployToLoadbalancer(ctx context.Context) error {
return errors.New("`loadbalancerId` is required")
}
// 查询负载均衡实例的详细信息
// 查询负载均衡实例的详细信息
// REF: https://help.aliyun.com/zh/slb/classic-load-balancer/developer-reference/api-slb-2014-05-15-describeloadbalancerattribute
describeLoadBalancerAttributeReq := &slb20140515.DescribeLoadBalancerAttributeRequest{
RegionId: tea.String(d.option.DeployConfig.GetConfigAsString("region")),
@ -124,7 +124,7 @@ func (d *AliyunCLBDeployer) deployToLoadbalancer(ctx context.Context) error {
return fmt.Errorf("failed to execute sdk request 'slb.DescribeLoadBalancerAttribute': %w", err)
}
d.infos = append(d.infos, toStr("已查询到 CLB 负载均衡实例", describeLoadBalancerAttributeResp))
d.infos = append(d.infos, toStr("已查询到 CLB 负载均衡实例", describeLoadBalancerAttributeResp))
// 查询监听列表
// REF: https://help.aliyun.com/zh/slb/classic-load-balancer/developer-reference/api-slb-2014-05-15-describeloadbalancerlisteners
@ -159,7 +159,7 @@ func (d *AliyunCLBDeployer) deployToLoadbalancer(ctx context.Context) error {
}
}
d.infos = append(d.infos, toStr("已查询到 ELB 负载均衡器下的监听器", aliListenerPorts))
d.infos = append(d.infos, toStr("已查询到 CLB 负载均衡实例下的全部 HTTPS 监听", aliListenerPorts))
// 上传证书到 SLB
uploadResult, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey)

View File

@ -12,6 +12,7 @@ import { Context as DeployEditContext } from "./DeployEdit";
import DeployToAliyunOSS from "./DeployToAliyunOSS";
import DeployToAliyunCDN from "./DeployToAliyunCDN";
import DeployToAliyunCLB from "./DeployToAliyunCLB";
import DeployToAliyunALB from "./DeployToAliyunALB";
import DeployToTencentCDN from "./DeployToTencentCDN";
import DeployToTencentCLB from "./DeployToTencentCLB";
import DeployToTencentCOS from "./DeployToTencentCOS";
@ -122,6 +123,9 @@ const DeployEditDialog = ({ trigger, deployConfig, onSave }: DeployEditDialogPro
case "aliyun-clb":
childComponent = <DeployToAliyunCLB />;
break;
case "aliyun-alb":
childComponent = <DeployToAliyunALB />;
break;
case "tencent-cdn":
childComponent = <DeployToTencentCDN />;
break;

View File

@ -0,0 +1,162 @@
import { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { z } from "zod";
import { produce } from "immer";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { useDeployEditContext } from "./DeployEdit";
const DeployToAliyunALB = () => {
const { t } = useTranslation();
const { deploy: data, setDeploy, error, setError } = useDeployEditContext();
useEffect(() => {
if (!data.id) {
setDeploy({
...data,
config: {
region: "cn-hangzhou",
resourceType: "",
loadbalancerId: "",
listenerId: "",
},
});
}
}, []);
useEffect(() => {
setError({});
}, []);
const formSchema = z
.object({
region: z.string().min(1, t("domain.deployment.form.aliyun_alb_region.placeholder")),
resourceType: z.union([z.literal("loadbalancer"), z.literal("listener")], {
message: t("domain.deployment.form.aliyun_alb_resource_type.placeholder"),
}),
loadbalancerId: z.string().optional(),
listenerId: z.string().optional(),
})
.refine((data) => (data.resourceType === "loadbalancer" ? !!data.loadbalancerId?.trim() : true), {
message: t("domain.deployment.form.aliyun_alb_loadbalancer_id.placeholder"),
path: ["loadbalancerId"],
})
.refine((data) => (data.resourceType === "listener" ? !!data.listenerId?.trim() : true), {
message: t("domain.deployment.form.aliyun_alb_listener_id.placeholder"),
path: ["listenerId"],
});
useEffect(() => {
const res = formSchema.safeParse(data.config);
if (!res.success) {
setError({
...error,
region: res.error.errors.find((e) => e.path[0] === "region")?.message,
resourceType: res.error.errors.find((e) => e.path[0] === "resourceType")?.message,
loadbalancerId: res.error.errors.find((e) => e.path[0] === "loadbalancerId")?.message,
listenerId: res.error.errors.find((e) => e.path[0] === "listenerId")?.message,
});
} else {
setError({
...error,
region: undefined,
resourceType: undefined,
loadbalancerId: undefined,
listenerId: undefined,
});
}
}, [data]);
return (
<div className="flex flex-col space-y-8">
<div>
<Label>{t("domain.deployment.form.aliyun_alb_region.label")}</Label>
<Input
placeholder={t("domain.deployment.form.aliyun_alb_region.placeholder")}
className="w-full mt-1"
value={data?.config?.region}
onChange={(e) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.region = e.target.value?.trim();
});
setDeploy(newData);
}}
/>
<div className="text-red-600 text-sm mt-1">{error?.region}</div>
</div>
<div>
<Label>{t("domain.deployment.form.aliyun_alb_resource_type.label")}</Label>
<Select
value={data?.config?.resourceType}
onValueChange={(value) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.resourceType = value?.trim();
});
setDeploy(newData);
}}
>
<SelectTrigger>
<SelectValue placeholder={t("domain.deployment.form.aliyun_alb_resource_type.placeholder")} />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="loadbalancer">{t("domain.deployment.form.aliyun_alb_resource_type.option.loadbalancer.label")}</SelectItem>
<SelectItem value="listener">{t("domain.deployment.form.aliyun_alb_resource_type.option.listener.label")}</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<div className="text-red-600 text-sm mt-1">{error?.resourceType}</div>
</div>
{data?.config?.resourceType === "loadbalancer" ? (
<div>
<Label>{t("domain.deployment.form.aliyun_alb_loadbalancer_id.label")}</Label>
<Input
placeholder={t("domain.deployment.form.aliyun_alb_loadbalancer_id.placeholder")}
className="w-full mt-1"
value={data?.config?.loadbalancerId}
onChange={(e) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.loadbalancerId = e.target.value?.trim();
});
setDeploy(newData);
}}
/>
<div className="text-red-600 text-sm mt-1">{error?.loadbalancerId}</div>
</div>
) : (
<></>
)}
{data?.config?.resourceType === "listener" ? (
<div>
<Label>{t("domain.deployment.form.aliyun_alb_listener_id.label")}</Label>
<Input
placeholder={t("domain.deployment.form.aliyun_alb_listener_id.placeholder")}
className="w-full mt-1"
value={data?.config?.listenerId}
onChange={(e) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.listenerId = e.target.value?.trim();
});
setDeploy(newData);
}}
/>
<div className="text-red-600 text-sm mt-1">{error?.listenerId}</div>
</div>
) : (
<></>
)}
</div>
);
};
export default DeployToAliyunALB;

View File

@ -34,7 +34,9 @@ const DeployToAliyunCLB = () => {
const formSchema = z
.object({
region: z.string().min(1, t("domain.deployment.form.aliyun_clb_region.placeholder")),
resourceType: z.string().min(1, t("domain.deployment.form.aliyun_clb_resource_type.placeholder")),
resourceType: z.union([z.literal("certificate"), z.literal("loadbalancer"), z.literal("listener")], {
message: t("domain.deployment.form.aliyun_clb_resource_type.placeholder"),
}),
loadbalancerId: z.string().optional(),
listenerPort: z.string().optional(),
})

View File

@ -76,6 +76,7 @@ export const deployTargetsMap: Map<DeployTarget["type"], DeployTarget> = new Map
["aliyun-cdn", "common.provider.aliyun.cdn", "/imgs/providers/aliyun.svg"],
["aliyun-dcdn", "common.provider.aliyun.dcdn", "/imgs/providers/aliyun.svg"],
["aliyun-clb", "common.provider.aliyun.clb", "/imgs/providers/aliyun.svg"],
["aliyun-alb", "common.provider.aliyun.alb", "/imgs/providers/aliyun.svg"],
["tencent-cdn", "common.provider.tencent.cdn", "/imgs/providers/tencent.svg"],
["tencent-clb", "common.provider.tencent.clb", "/imgs/providers/tencent.svg"],
["tencent-cos", "common.provider.tencent.cos", "/imgs/providers/tencent.svg"],

View File

@ -56,7 +56,8 @@
"common.provider.aliyun.oss": "Alibaba Cloud - OSS",
"common.provider.aliyun.cdn": "Alibaba Cloud - CDN",
"common.provider.aliyun.dcdn": "Alibaba Cloud - DCDN",
"common.provider.aliyun.clb": "Alibaba Cloud - CLB(SLB)",
"common.provider.aliyun.clb": "Alibaba Cloud - CLB",
"common.provider.aliyun.alb": "Alibaba Cloud - ALB",
"common.provider.tencent": "Tencent Cloud",
"common.provider.tencent.cdn": "Tencent Cloud - CDN",
"common.provider.tencent.clb": "Tencent Cloud - CLB",

View File

@ -71,6 +71,16 @@
"domain.deployment.form.aliyun_clb_loadbalancer_id.placeholder": "Please enter CLB loadbalancer ID",
"domain.deployment.form.aliyun_clb_listener_port.label": "Listener Port",
"domain.deployment.form.aliyun_clb_listener_port.placeholder": "Please enter CLB listener port",
"domain.deployment.form.aliyun_alb_region.label": "Region",
"domain.deployment.form.aliyun_alb_region.placeholder": "Please enter region (e.g. cn-hangzhou)",
"domain.deployment.form.aliyun_alb_resource_type.label": "Resource Type",
"domain.deployment.form.aliyun_alb_resource_type.placeholder": "Please select ALB resource type",
"domain.deployment.form.aliyun_alb_resource_type.option.loadbalancer.label": "ALB LoadBalancer",
"domain.deployment.form.aliyun_alb_resource_type.option.listener.label": "ALB Listener",
"domain.deployment.form.aliyun_alb_loadbalancer_id.label": "LoadBalancer ID",
"domain.deployment.form.aliyun_alb_loadbalancer_id.placeholder": "Please enter ALB loadbalancer ID",
"domain.deployment.form.aliyun_alb_listener_id.label": "Listener ID",
"domain.deployment.form.aliyun_alb_listener_id.placeholder": "Please enter ALB listener ID",
"domain.deployment.form.tencent_cos_region.label": "Region",
"domain.deployment.form.tencent_cos_region.placeholder": "Please enter region (e.g. ap-guangzhou)",
"domain.deployment.form.tencent_cos_bucket.label": "Bucket",

View File

@ -52,19 +52,20 @@
"common.errmsg.ip_invalid": "请输入正确的 IP 地址",
"common.errmsg.url_invalid": "请输入正确的 URL",
"common.provider.aliyun": "阿里云",
"common.provider.aliyun.oss": "阿里云 - OSS",
"common.provider.aliyun.cdn": "阿里云 - CDN",
"common.provider.aliyun.dcdn": "阿里云 - DCDN",
"common.provider.aliyun.clb": "阿里云 - CLB原 SLB",
"common.provider.aliyun.oss": "阿里云 - 对象存储 OSS",
"common.provider.aliyun.cdn": "阿里云 - 内容分发网络 CDN",
"common.provider.aliyun.dcdn": "阿里云 - 全站加速 DCDN",
"common.provider.aliyun.clb": "阿里云 - 传统型负载均衡 CLB",
"common.provider.aliyun.alb": "阿里云 - 应用型负载均衡 ALB",
"common.provider.tencent": "腾讯云",
"common.provider.tencent.cos": "腾讯云 - COS",
"common.provider.tencent.cdn": "腾讯云 - CDN",
"common.provider.tencent.clb": "腾讯云 - CLB",
"common.provider.tencent.cos": "腾讯云 - 对象存储 COS",
"common.provider.tencent.cdn": "腾讯云 - 内容分发网络 CDN",
"common.provider.tencent.clb": "腾讯云 - 负载均衡 CLB",
"common.provider.huaweicloud": "华为云",
"common.provider.huaweicloud.cdn": "华为云 - CDN",
"common.provider.huaweicloud.elb": "华为云 - ELB",
"common.provider.huaweicloud.cdn": "华为云 - 内容分发网络 CDN",
"common.provider.huaweicloud.elb": "华为云 - 弹性负载均衡 ELB",
"common.provider.qiniu": "七牛云",
"common.provider.qiniu.cdn": "七牛云 - CDN",
"common.provider.qiniu.cdn": "七牛云 - 内容分发网络 CDN",
"common.provider.aws": "AWS",
"common.provider.cloudflare": "Cloudflare",
"common.provider.namesilo": "Namesilo",

View File

@ -65,12 +65,22 @@
"domain.deployment.form.aliyun_clb_region.placeholder": "请输入地域(如 cn-hangzhou",
"domain.deployment.form.aliyun_clb_resource_type.label": "替换方式",
"domain.deployment.form.aliyun_clb_resource_type.placeholder": "请选择替换方式",
"domain.deployment.form.aliyun_clb_resource_type.option.loadbalancer.label": "替换指定负载均衡器的全部监听的证书",
"domain.deployment.form.aliyun_clb_resource_type.option.loadbalancer.label": "替换指定负载均衡器的全部监听的证书(仅支持 HTTPS 监听)",
"domain.deployment.form.aliyun_clb_resource_type.option.listener.label": "替换指定负载均衡器监听的证书",
"domain.deployment.form.aliyun_clb_loadbalancer_id.label": "负载均衡器 ID",
"domain.deployment.form.aliyun_clb_loadbalancer_id.placeholder": "请输入负载均衡器 ID",
"domain.deployment.form.aliyun_clb_listener_port.label": "监听端口",
"domain.deployment.form.aliyun_clb_listener_port.placeholder": "请输入监听端口",
"domain.deployment.form.aliyun_alb_region.label": "地域",
"domain.deployment.form.aliyun_alb_region.placeholder": "请输入地域(如 cn-hangzhou",
"domain.deployment.form.aliyun_alb_resource_type.label": "替换方式",
"domain.deployment.form.aliyun_alb_resource_type.placeholder": "请选择替换方式",
"domain.deployment.form.aliyun_alb_resource_type.option.loadbalancer.label": "替换指定负载均衡器的全部监听的证书(仅支持 HTTPS 监听)",
"domain.deployment.form.aliyun_alb_resource_type.option.listener.label": "替换指定负载均衡器监听的证书",
"domain.deployment.form.aliyun_alb_loadbalancer_id.label": "负载均衡器 ID",
"domain.deployment.form.aliyun_alb_loadbalancer_id.placeholder": "请输入负载均衡器 ID",
"domain.deployment.form.aliyun_alb_listener_id.label": "监听器 ID",
"domain.deployment.form.aliyun_alb_listener_id.placeholder": "请输入监听器 ID",
"domain.deployment.form.tencent_cos_region.label": "地域",
"domain.deployment.form.tencent_cos_region.placeholder": "请输入地域(如 ap-guangzhou",
"domain.deployment.form.tencent_cos_bucket.label": "存储桶",
@ -88,7 +98,7 @@
"domain.deployment.form.huaweicloud_elb_resource_type.label": "替换方式",
"domain.deployment.form.huaweicloud_elb_resource_type.placeholder": "请选择替换方式",
"domain.deployment.form.huaweicloud_elb_resource_type.option.certificate.label": "替换指定证书",
"domain.deployment.form.huaweicloud_elb_resource_type.option.loadbalancer.label": "替换指定负载均衡器的全部监听器的证书",
"domain.deployment.form.huaweicloud_elb_resource_type.option.loadbalancer.label": "替换指定负载均衡器的全部监听器的证书(仅支持 HTTPS 监听)",
"domain.deployment.form.huaweicloud_elb_resource_type.option.listener.label": "替换指定监听器",
"domain.deployment.form.huaweicloud_elb_certificate_id.label": "证书 ID",
"domain.deployment.form.huaweicloud_elb_certificate_id.placeholder": "请输入证书 ID",