feat: support tencent clb deployment in multiple ways

This commit is contained in:
Fu Diwei 2024-10-31 13:24:43 +08:00
parent 83264a6946
commit 369c146eca
10 changed files with 394 additions and 233 deletions

7
go.mod
View File

@ -12,7 +12,6 @@ require (
github.com/alibabacloud-go/nlb-20220430/v2 v2.0.3
github.com/alibabacloud-go/slb-20140515/v4 v4.0.9
github.com/alibabacloud-go/tea v1.2.2
github.com/alibabacloud-go/tea-utils/v2 v2.0.6
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
github.com/go-acme/lego/v4 v4.19.2
github.com/gojek/heimdall/v7 v7.0.3
@ -25,7 +24,8 @@ require (
github.com/pocketbase/pocketbase v0.22.18
github.com/qiniu/go-sdk/v7 v7.22.0
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1017
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1030
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1031
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1031
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.992
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/teo v1.0.1030
golang.org/x/crypto v0.28.0
@ -41,6 +41,7 @@ require (
github.com/alibabacloud-go/tea-fileform v1.1.1 // indirect
github.com/alibabacloud-go/tea-oss-sdk v1.1.3 // indirect
github.com/alibabacloud-go/tea-oss-utils v1.1.0 // indirect
github.com/alibabacloud-go/tea-utils/v2 v2.0.6 // indirect
github.com/aws/aws-sdk-go-v2/service/route53 v1.43.2 // indirect
github.com/blinkbean/dingtalk v1.1.3 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
@ -141,7 +142,7 @@ require (
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/nrdcg/namesilo v0.2.1 // indirect
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/errors v0.9.1
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/cobra v1.8.1 // indirect

7
go.sum
View File

@ -204,8 +204,6 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I=
github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s=
github.com/gabriel-vasile/mimetype v1.4.6 h1:3+PzJTKLkvgjeTbts6msPJt4DixhT4YtFNf1gtGe3zc=
github.com/gabriel-vasile/mimetype v1.4.6/go.mod h1:JX1qVKqZd40hUPpAfiNTe0Sne7hdfKSbOqqmkq8GCXc=
github.com/gammazero/toposort v0.1.1/go.mod h1:H2cozTnNpMw0hg2VHAYsAxmkHXBYroNangj2NTBQDvw=
@ -460,11 +458,14 @@ github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQ
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1017 h1:OymmfmyFkvHirY3WHsoRT3cdTEsqygLbMn8jM41erK4=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/cdn v1.0.1017/go.mod h1:gnLxGXlLmF+jDqWR1/RVoF/UUwxQxomQhkc0oN7KeuI=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1031 h1:/eVMCl+jadCex6HxNN6/hFbC0iWl+e8s4PSIcI8aqS4=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb v1.0.1031/go.mod h1:8Km0fRIaDS7PssuyxDFvRRFBUFmECqG+ICpViCs/Vak=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.992/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1002/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1017/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1030 h1:kwiUoCkooUgy7iPyhEEbio7WT21kGJUeZ5JeJfb/dYk=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1030/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1031 h1:3ouglYKE5cwhx2vwICGeW7pAlwyCLnpQd7O0l3hCSTg=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1031/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1002 h1:QwE0dRkAAbdf+eACnkNULgDn9ZKUJpPWRyXdqJolP5E=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1002/go.mod h1:WdC0FYbqYhJwQ3kbqri6hVP5HAEp+rzX9FToItTAzUg=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ssl v1.0.992 h1:A6O89OlCJQUpNxGqC/E5By04UNKBryIt5olQIGOx8mg=

View File

@ -4,7 +4,6 @@ import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/global"
hcCdn "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/cdn/v2"
@ -67,6 +66,14 @@ func (d *HuaweiCloudCDNDeployer) GetInfos() []string {
}
func (d *HuaweiCloudCDNDeployer) Deploy(ctx context.Context) error {
// 上传证书到 SCM
upres, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey)
if err != nil {
return err
}
d.infos = append(d.infos, toStr("已上传证书", upres))
// 查询加速域名配置
// REF: https://support.huaweicloud.com/api-cdn/ShowDomainFullConfig.html
showDomainFullConfigReq := &hcCdnModel.ShowDomainFullConfigRequest{
@ -85,24 +92,9 @@ func (d *HuaweiCloudCDNDeployer) Deploy(ctx context.Context) error {
updateDomainMultiCertificatesReqBodyContent := &hcCdnEx.UpdateDomainMultiCertificatesExRequestBodyContent{}
updateDomainMultiCertificatesReqBodyContent.DomainName = d.option.DeployConfig.GetConfigAsString("domain")
updateDomainMultiCertificatesReqBodyContent.HttpsSwitch = 1
if d.option.DeployConfig.GetConfigAsBool("useSCM") {
// 上传证书到 SCM
upres, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey)
if err != nil {
return err
}
d.infos = append(d.infos, toStr("已上传证书", upres))
updateDomainMultiCertificatesReqBodyContent.CertificateType = cast.Int32Ptr(2)
updateDomainMultiCertificatesReqBodyContent.SCMCertificateId = cast.StringPtr(upres.CertId)
updateDomainMultiCertificatesReqBodyContent.CertName = cast.StringPtr(upres.CertName)
} else {
updateDomainMultiCertificatesReqBodyContent.CertificateType = cast.Int32Ptr(0)
updateDomainMultiCertificatesReqBodyContent.CertName = cast.StringPtr(fmt.Sprintf("certimate-%d", time.Now().UnixMilli()))
updateDomainMultiCertificatesReqBodyContent.Certificate = cast.StringPtr(d.option.Certificate.Certificate)
updateDomainMultiCertificatesReqBodyContent.PrivateKey = cast.StringPtr(d.option.Certificate.PrivateKey)
}
updateDomainMultiCertificatesReqBodyContent.CertificateType = cast.Int32Ptr(2)
updateDomainMultiCertificatesReqBodyContent.SCMCertificateId = cast.StringPtr(upres.CertId)
updateDomainMultiCertificatesReqBodyContent.CertName = cast.StringPtr(upres.CertName)
updateDomainMultiCertificatesReqBodyContent = updateDomainMultiCertificatesReqBodyContent.MergeConfig(showDomainFullConfigResp.Configs)
updateDomainMultiCertificatesReq := &hcCdnEx.UpdateDomainMultiCertificatesExRequest{
Body: &hcCdnEx.UpdateDomainMultiCertificatesExRequestBody{

View File

@ -268,7 +268,7 @@ func (d *HuaweiCloudELBDeployer) deployToLoadbalancer(ctx context.Context) error
// 批量更新监听器证书
var errs []error
for _, hcListenerId := range hcListenerIds {
if err := d.updateListenerCertificate(ctx, hcListenerId, upres.CertId); err != nil {
if err := d.modifyListenerCertificate(ctx, hcListenerId, upres.CertId); err != nil {
errs = append(errs, err)
}
}
@ -294,14 +294,14 @@ func (d *HuaweiCloudELBDeployer) deployToListener(ctx context.Context) error {
d.infos = append(d.infos, toStr("已上传证书", upres))
// 更新监听器证书
if err := d.updateListenerCertificate(ctx, hcListenerId, upres.CertId); err != nil {
if err := d.modifyListenerCertificate(ctx, hcListenerId, upres.CertId); err != nil {
return err
}
return nil
}
func (d *HuaweiCloudELBDeployer) updateListenerCertificate(ctx context.Context, hcListenerId string, hcCertId string) error {
func (d *HuaweiCloudELBDeployer) modifyListenerCertificate(ctx context.Context, hcListenerId string, hcCertId string) error {
// 查询监听器详情
// REF: https://support.huaweicloud.com/api-elb/ShowListener.html
showListenerReq := &hcElbModel.ShowListenerRequest{

View File

@ -7,6 +7,7 @@ import (
"fmt"
xerrors "github.com/pkg/errors"
tcClb "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/clb/v20180317"
"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"
@ -25,6 +26,7 @@ type TencentCLBDeployer struct {
type tencentCLBDeployerSdkClients struct {
ssl *tcSsl.Client
clb *tcClb.Client
}
func NewTencentCLBDeployer(option *DeployerOption) (Deployer, error) {
@ -69,10 +71,30 @@ func (d *TencentCLBDeployer) GetInfos() []string {
func (d *TencentCLBDeployer) Deploy(ctx context.Context) error {
// TODO: 直接部署方式
// 通过 SSL 服务部署到云资源实例
err := d.deployToInstanceUseSsl(ctx)
if err != nil {
return err
switch d.option.DeployConfig.GetConfigAsString("resourceType") {
case "ssl-deploy":
// 通过 SSL 服务部署到云资源实例
err := d.deployToInstanceUseSsl(ctx)
if err != nil {
return err
}
case "loadbalancer":
// 部署到指定负载均衡器
if err := d.deployToLoadbalancer(ctx); err != nil {
return err
}
case "listener":
// 部署到指定监听器
if err := d.deployToListener(ctx); err != nil {
return err
}
case "ruledomain":
// 部署到指定七层监听转发规则域名
if err := d.deployToRuleDomain(ctx); err != nil {
return err
}
default:
return errors.New("unsupported resource type")
}
return nil
@ -86,14 +108,20 @@ func (d *TencentCLBDeployer) createSdkClients(secretId, secretKey, region string
return nil, err
}
clbClient, err := tcClb.NewClient(credential, region, profile.NewClientProfile())
if err != nil {
return nil, err
}
return &tencentCLBDeployerSdkClients{
ssl: sslClient,
clb: clbClient,
}, nil
}
func (d *TencentCLBDeployer) deployToInstanceUseSsl(ctx context.Context) error {
tcLoadbalancerId := d.option.DeployConfig.GetConfigAsString("clbId")
tcListenerId := d.option.DeployConfig.GetConfigAsString("lsnId")
tcLoadbalancerId := d.option.DeployConfig.GetConfigAsString("loadbalancerId")
tcListenerId := d.option.DeployConfig.GetConfigAsString("listenerId")
tcDomain := d.option.DeployConfig.GetConfigAsString("domain")
if tcLoadbalancerId == "" {
return errors.New("`loadbalancerId` is required")
@ -132,3 +160,170 @@ func (d *TencentCLBDeployer) deployToInstanceUseSsl(ctx context.Context) error {
return nil
}
func (d *TencentCLBDeployer) deployToLoadbalancer(ctx context.Context) error {
tcLoadbalancerId := d.option.DeployConfig.GetConfigAsString("loadbalancerId")
tcListenerIds := make([]string, 0)
if tcLoadbalancerId == "" {
return errors.New("`loadbalancerId` is required")
}
// 查询负载均衡器详细信息
// REF: https://cloud.tencent.com/document/api/214/46916
describeLoadBalancersDetailReq := tcClb.NewDescribeLoadBalancersDetailRequest()
describeLoadBalancersDetailResp, err := d.sdkClients.clb.DescribeLoadBalancersDetail(describeLoadBalancersDetailReq)
if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'clb.DescribeLoadBalancersDetail'")
}
d.infos = append(d.infos, toStr("已查询到负载均衡详细信息", describeLoadBalancersDetailResp))
// 查询监听器列表
// REF: https://cloud.tencent.com/document/api/214/30686
describeListenersReq := tcClb.NewDescribeListenersRequest()
describeListenersReq.LoadBalancerId = common.StringPtr(tcLoadbalancerId)
describeListenersResp, err := d.sdkClients.clb.DescribeListeners(describeListenersReq)
if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'clb.DescribeListeners'")
} else {
if describeListenersResp.Response.Listeners != nil {
for _, listener := range describeListenersResp.Response.Listeners {
if listener.Protocol == nil || (*listener.Protocol != "HTTPS" && *listener.Protocol != "TCP_SSL" && *listener.Protocol != "QUIC") {
continue
}
tcListenerIds = append(tcListenerIds, *listener.ListenerId)
}
}
}
d.infos = append(d.infos, toStr("已查询到负载均衡器下的监听器", tcListenerIds))
// 上传证书到 SCM
upres, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey)
if err != nil {
return err
}
d.infos = append(d.infos, toStr("已上传证书", upres))
// 批量更新监听器证书
var errs []error
for _, tcListenerId := range tcListenerIds {
if err := d.modifyListenerCertificate(ctx, tcLoadbalancerId, tcListenerId, upres.CertId); err != nil {
errs = append(errs, err)
}
}
if len(errs) > 0 {
return errors.Join(errs...)
}
return nil
}
func (d *TencentCLBDeployer) deployToListener(ctx context.Context) error {
tcLoadbalancerId := d.option.DeployConfig.GetConfigAsString("loadbalancerId")
tcListenerId := d.option.DeployConfig.GetConfigAsString("listenerId")
if tcLoadbalancerId == "" {
return errors.New("`loadbalancerId` is required")
}
if tcListenerId == "" {
return errors.New("`listenerId` is required")
}
// 上传证书到 SSL
upres, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey)
if err != nil {
return err
}
d.infos = append(d.infos, toStr("已上传证书", upres))
// 更新监听器证书
if err := d.modifyListenerCertificate(ctx, tcLoadbalancerId, tcListenerId, upres.CertId); err != nil {
return err
}
return nil
}
func (d *TencentCLBDeployer) deployToRuleDomain(ctx context.Context) error {
tcLoadbalancerId := d.option.DeployConfig.GetConfigAsString("loadbalancerId")
tcListenerId := d.option.DeployConfig.GetConfigAsString("listenerId")
tcDomain := d.option.DeployConfig.GetConfigAsString("domain")
if tcLoadbalancerId == "" {
return errors.New("`loadbalancerId` is required")
}
if tcListenerId == "" {
return errors.New("`listenerId` is required")
}
if tcDomain == "" {
return errors.New("`domain` is required")
}
// 上传证书到 SSL
upres, err := d.sslUploader.Upload(ctx, d.option.Certificate.Certificate, d.option.Certificate.PrivateKey)
if err != nil {
return err
}
d.infos = append(d.infos, toStr("已上传证书", upres))
// 修改负载均衡七层监听器转发规则的域名级别属性
// REF: https://cloud.tencent.com/document/api/214/38092
modifyDomainAttributesReq := tcClb.NewModifyDomainAttributesRequest()
modifyDomainAttributesReq.LoadBalancerId = common.StringPtr(tcLoadbalancerId)
modifyDomainAttributesReq.ListenerId = common.StringPtr(tcListenerId)
modifyDomainAttributesReq.Domain = common.StringPtr(tcDomain)
modifyDomainAttributesReq.Certificate = &tcClb.CertificateInput{
SSLMode: common.StringPtr("UNIDIRECTIONAL"),
CertId: common.StringPtr(upres.CertId),
}
modifyDomainAttributesResp, err := d.sdkClients.clb.ModifyDomainAttributes(modifyDomainAttributesReq)
if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'clb.ModifyDomainAttributes'")
}
d.infos = append(d.infos, toStr("已修改七层监听器转发规则的域名级别属性", modifyDomainAttributesResp.Response))
return nil
}
func (d *TencentCLBDeployer) modifyListenerCertificate(ctx context.Context, tcLoadbalancerId, tcListenerId, tcCertId string) error {
// 查询监听器列表
// REF: https://cloud.tencent.com/document/api/214/30686
describeListenersReq := tcClb.NewDescribeListenersRequest()
describeListenersReq.LoadBalancerId = common.StringPtr(tcLoadbalancerId)
describeListenersReq.ListenerIds = common.StringPtrs([]string{tcListenerId})
describeListenersResp, err := d.sdkClients.clb.DescribeListeners(describeListenersReq)
if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'clb.DescribeListeners'")
}
if len(describeListenersResp.Response.Listeners) == 0 {
d.infos = append(d.infos, toStr("未找到监听器", nil))
return errors.New("listener not found")
}
d.infos = append(d.infos, toStr("已查询到监听器属性", describeListenersResp.Response))
// 修改监听器属性
// REF: https://cloud.tencent.com/document/product/214/30681
modifyListenerReq := tcClb.NewModifyListenerRequest()
modifyListenerReq.LoadBalancerId = common.StringPtr(tcLoadbalancerId)
modifyListenerReq.ListenerId = common.StringPtr(tcListenerId)
modifyListenerReq.Certificate = &tcClb.CertificateInput{CertId: common.StringPtr(tcCertId)}
if describeListenersResp.Response.Listeners[0].Certificate != nil && describeListenersResp.Response.Listeners[0].Certificate.SSLMode != nil {
modifyListenerReq.Certificate.SSLMode = describeListenersResp.Response.Listeners[0].Certificate.SSLMode
modifyListenerReq.Certificate.CertCaId = describeListenersResp.Response.Listeners[0].Certificate.CertCaId
} else {
modifyListenerReq.Certificate.SSLMode = common.StringPtr("UNIDIRECTIONAL")
}
modifyListenerResp, err := d.sdkClients.clb.ModifyListener(modifyListenerReq)
if err != nil {
return xerrors.Wrap(err, "failed to execute sdk request 'clb.ModifyListener'")
}
d.infos = append(d.infos, toStr("已修改监听器属性", modifyListenerResp.Response))
return nil
}

View File

@ -5,106 +5,76 @@ 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 DeployToTencentCLB = () => {
const { deploy: data, setDeploy, error, setError } = useDeployEditContext();
const { t } = useTranslation();
useEffect(() => {
setError({});
}, []);
useEffect(() => {
const resp = domainSchema.safeParse(data.config?.domain);
if (!resp.success) {
setError({
...error,
domain: JSON.parse(resp.error.message)[0].message,
});
} else {
setError({
...error,
domain: "",
});
}
}, [data]);
useEffect(() => {
const clbIdresp = clbIdSchema.safeParse(data.config?.clbId);
if (!clbIdresp.success) {
setError({
...error,
clbId: JSON.parse(clbIdresp.error.message)[0].message,
});
} else {
setError({
...error,
clbId: "",
});
}
}, [data]);
useEffect(() => {
const lsnIdresp = lsnIdSchema.safeParse(data.config?.lsnId);
if (!lsnIdresp.success) {
setError({
...error,
lsnId: JSON.parse(lsnIdresp.error.message)[0].message,
});
} else {
setError({
...error,
lsnId: "",
});
}
}, [data]);
useEffect(() => {
const regionResp = regionSchema.safeParse(data.config?.region);
if (!regionResp.success) {
setError({
...error,
region: JSON.parse(regionResp.error.message)[0].message,
});
} else {
setError({
...error,
region: "",
});
}
}, []);
const { deploy: data, setDeploy, error, setError } = useDeployEditContext();
useEffect(() => {
if (!data.id) {
setDeploy({
...data,
config: {
lsnId: "",
clbId: "",
region: "ap-guangzhou",
resourceType: "",
loadbalancerId: "",
listenerId: "",
domain: "",
region: "",
},
});
}
}, []);
const regionSchema = z.string().regex(/^ap-[a-z]+$/, {
message: t("domain.deployment.form.tencent_clb_region.placeholder"),
});
useEffect(() => {
setError({});
}, []);
const domainSchema = z.string().regex(/^$|^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
message: t("common.errmsg.domain_invalid"),
});
const formSchema = z
.object({
region: z.string().min(1, t("domain.deployment.form.tencent_clb_region.placeholder")),
resourceType: z.union([z.literal("ssl-deploy"), z.literal("loadbalancer"), z.literal("listener"), z.literal("ruledomain")], {
message: t("domain.deployment.form.tencent_clb_resource_type.placeholder"),
}),
loadbalancerId: z.string().min(1, t("domain.deployment.form.tencent_clb_loadbalancer_id.placeholder")),
listenerId: z.string().optional(),
domain: z.string().regex(/^$|^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
message: t("common.errmsg.domain_invalid"),
}),
})
.refine(
(data) => {
switch (data.resourceType) {
case "ssl-deploy":
case "listener":
case "ruledomain":
return !!data.listenerId?.trim();
}
return true;
},
{
message: t("domain.deployment.form.tencent_clb_listener_id.placeholder"),
path: ["listenerId"],
}
)
.refine((data) => (data.resourceType === "ruledomain" ? !!data.domain?.trim() : true), {
message: t("domain.deployment.form.tencent_clb_ruledomain.placeholder"),
path: ["domain"],
});
const clbIdSchema = z.string().regex(/^lb-[a-zA-Z0-9]{8}$/, {
message: t("domain.deployment.form.tencent_clb_id.placeholder"),
});
const lsnIdSchema = z.string().regex(/^lbl-.{8}$/, {
message: t("domain.deployment.form.tencent_clb_listener.placeholder"),
});
useEffect(() => {
const res = formSchema.safeParse(data.config);
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,
domain: res.error?.errors?.find((e) => e.path[0] === "domain")?.message,
});
}, [data]);
return (
<div className="flex flex-col space-y-8">
@ -115,26 +85,9 @@ const DeployToTencentCLB = () => {
className="w-full mt-1"
value={data?.config?.region}
onChange={(e) => {
const temp = e.target.value;
const resp = regionSchema.safeParse(temp);
if (!resp.success) {
setError({
...error,
region: JSON.parse(resp.error.message)[0].message,
});
} else {
setError({
...error,
region: "",
});
}
const newData = produce(data, (draft) => {
if (!draft.config) {
draft.config = {};
}
draft.config.region = temp;
draft.config ??= {};
draft.config.region = e.target.value?.trim();
});
setDeploy(newData);
}}
@ -143,106 +96,111 @@ const DeployToTencentCLB = () => {
</div>
<div>
<Label>{t("domain.deployment.form.tencent_clb_id.label")}</Label>
<Input
placeholder={t("domain.deployment.form.tencent_clb_id.placeholder")}
className="w-full mt-1"
value={data?.config?.clbId}
onChange={(e) => {
const temp = e.target.value;
const resp = clbIdSchema.safeParse(temp);
if (!resp.success) {
setError({
...error,
clbId: JSON.parse(resp.error.message)[0].message,
});
} else {
setError({
...error,
clbId: "",
});
}
<Label>{t("domain.deployment.form.tencent_clb_resource_type.label")}</Label>
<Select
value={data?.config?.resourceType}
onValueChange={(value) => {
const newData = produce(data, (draft) => {
if (!draft.config) {
draft.config = {};
}
draft.config.clbId = temp;
draft.config ??= {};
draft.config.resourceType = value;
});
setDeploy(newData);
}}
/>
<div className="text-red-600 text-sm mt-1">{error?.clbId}</div>
>
<SelectTrigger>
<SelectValue placeholder={t("domain.deployment.form.tencent_clb_resource_type.placeholder")} />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="ssl-deploy">{t("domain.deployment.form.tencent_clb_resource_type.option.ssl_deploy.label")}</SelectItem>
<SelectItem value="loadbalancer">{t("domain.deployment.form.tencent_clb_resource_type.option.loadbalancer.label")}</SelectItem>
<SelectItem value="listener">{t("domain.deployment.form.tencent_clb_resource_type.option.listener.label")}</SelectItem>
<SelectItem value="ruledomain">{t("domain.deployment.form.tencent_clb_resource_type.option.ruledomain.label")}</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<div className="text-red-600 text-sm mt-1">{error?.resourceType}</div>
</div>
<div>
<Label>{t("domain.deployment.form.tencent_clb_listener.label")}</Label>
<Label>{t("domain.deployment.form.tencent_clb_loadbalancer_id.label")}</Label>
<Input
placeholder={t("domain.deployment.form.tencent_clb_listener.placeholder")}
placeholder={t("domain.deployment.form.tencent_clb_loadbalancer_id.placeholder")}
className="w-full mt-1"
value={data?.config?.lsnId}
value={data?.config?.loadbalancerId}
onChange={(e) => {
const temp = e.target.value;
const resp = lsnIdSchema.safeParse(temp);
if (!resp.success) {
setError({
...error,
lsnId: JSON.parse(resp.error.message)[0].message,
});
} else {
setError({
...error,
lsnId: "",
});
}
const newData = produce(data, (draft) => {
if (!draft.config) {
draft.config = {};
}
draft.config.lsnId = temp;
draft.config ??= {};
draft.config.loadbalancerId = e.target.value?.trim();
});
setDeploy(newData);
}}
/>
<div className="text-red-600 text-sm mt-1">{error?.lsnId}</div>
<div className="text-red-600 text-sm mt-1">{error?.loadbalancerId}</div>
</div>
<div>
<Label>{t("domain.deployment.form.tencent_clb_domain.label")}</Label>
<Input
placeholder={t("domain.deployment.form.tencent_clb_domain.placeholder")}
className="w-full mt-1"
value={data?.config?.domain}
onChange={(e) => {
const temp = e.target.value;
const resp = domainSchema.safeParse(temp);
if (!resp.success) {
setError({
...error,
domain: JSON.parse(resp.error.message)[0].message,
{data?.config?.resourceType === "ssl-deploy" || data?.config?.resourceType === "listener" || data?.config?.resourceType === "ruledomain" ? (
<div>
<Label>{t("domain.deployment.form.tencent_clb_listener_id.label")}</Label>
<Input
placeholder={t("domain.deployment.form.tencent_clb_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();
});
} else {
setError({
...error,
domain: "",
});
}
setDeploy(newData);
}}
/>
<div className="text-red-600 text-sm mt-1">{error?.listenerId}</div>
</div>
) : (
<></>
)}
const newData = produce(data, (draft) => {
if (!draft.config) {
draft.config = {};
}
draft.config.domain = temp;
});
setDeploy(newData);
}}
/>
<div className="text-red-600 text-sm mt-1">{error?.domain}</div>
</div>
{data?.config?.resourceType === "ssl-deploy" ? (
<div>
<Label>{t("domain.deployment.form.tencent_clb_domain.label")}</Label>
<Input
placeholder={t("domain.deployment.form.tencent_clb_domain.placeholder")}
className="w-full mt-1"
value={data?.config?.domain}
onChange={(e) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.domain = e.target.value?.trim();
});
setDeploy(newData);
}}
/>
<div className="text-red-600 text-sm mt-1">{error?.domain}</div>
</div>
) : (
<></>
)}
{data?.config?.resourceType === "ruledomain" ? (
<div>
<Label>{t("domain.deployment.form.tencent_clb_ruledomain.label")}</Label>
<Input
placeholder={t("domain.deployment.form.tencent_clb_ruledomain.placeholder")}
className="w-full mt-1"
value={data?.config?.domain}
onChange={(e) => {
const newData = produce(data, (draft) => {
draft.config ??= {};
draft.config.domain = e.target.value?.trim();
});
setDeploy(newData);
}}
/>
<div className="text-red-600 text-sm mt-1">{error?.domain}</div>
</div>
) : (
<></>
)}
</div>
);
};

View File

@ -65,7 +65,7 @@
"common.provider.tencent.ecdn": "Tencent Cloud - ECDN",
"common.provider.tencent.clb": "Tencent Cloud - CLB",
"common.provider.tencent.cos": "Tencent Cloud - COS",
"common.provider.tencent.teo": "Tencent Cloud - TEO",
"common.provider.tencent.teo": "Tencent Cloud - EdgeOne",
"common.provider.huaweicloud": "Huawei Cloud",
"common.provider.huaweicloud.cdn": "Huawei Cloud - CDN",
"common.provider.huaweicloud.elb": "Huawei Cloud - ELB",

View File

@ -97,12 +97,19 @@
"domain.deployment.form.tencent_cos_bucket.placeholder": "Please enter bucket",
"domain.deployment.form.tencent_clb_region.label": "Region",
"domain.deployment.form.tencent_clb_region.placeholder": "Please enter region (e.g. ap-guangzhou)",
"domain.deployment.form.tencent_clb_id.label": "CLB ID",
"domain.deployment.form.tencent_clb_id.placeholder": "Please enter CLB ID (e.g. lb-xxxxxxxx)",
"domain.deployment.form.tencent_clb_listener.label": "Listener ID",
"domain.deployment.form.tencent_clb_listener.placeholder": "Please enter listener ID (e.g. lbl-xxxxxxxx). The specific listener should have set the corresponding domain HTTPS forwarding, and the original certificate domain should be consistent with the certificate to be deployed.",
"domain.deployment.form.tencent_clb_resource_type.label": "Resource Type",
"domain.deployment.form.tencent_clb_resource_type.placeholder": "Please select CLB resource type",
"domain.deployment.form.tencent_clb_resource_type.option.ssl_deploy.label": "Through SSL Deploy",
"domain.deployment.form.tencent_clb_resource_type.option.loadbalancer.label": "CLB LoadBalancer",
"domain.deployment.form.tencent_clb_resource_type.option.listener.label": "CLB Listener",
"domain.deployment.form.tencent_clb_loadbalancer_id.label": "Loadbalancer ID",
"domain.deployment.form.tencent_clb_loadbalancer_id.placeholder": "Please enter Loadbalancer ID",
"domain.deployment.form.tencent_clb_listener_id.label": "Listener ID",
"domain.deployment.form.tencent_clb_listener_id.placeholder": "Please enter listener ID. The specific listener should have set the corresponding domain HTTPS forwarding, and the original certificate domain should be consistent with the certificate to be deployed.",
"domain.deployment.form.tencent_clb_domain.label": "Deploy to domain (Wildcard domain is also supported)",
"domain.deployment.form.tencent_clb_domain.placeholder": "Please enter domain to be deployed. If SNI is not enabled, you can leave it blank.",
"domain.deployment.form.tencent_clb_ruledomain.label": "Rule Domain",
"domain.deployment.form.tencent_clb_ruledomain.placeholder": "Please enter rule domain",
"domain.deployment.form.tencent_teo_zone_id.label": "Zone ID",
"domain.deployment.form.tencent_teo_zone_id.placeholder": "Please enter zone id, e.g. zone-xxxxxxxxx",
"domain.deployment.form.tencent_teo_domain.label": "Deploy to domain (Wildcard domain is also supported, but should be same as the config on server, one domain each line)",

View File

@ -65,7 +65,7 @@
"common.provider.tencent.cdn": "腾讯云 - 内容分发网络 CDN",
"common.provider.tencent.ecdn": "腾讯云 - 全站加速网络 ECDN",
"common.provider.tencent.clb": "腾讯云 - 负载均衡 CLB",
"common.provider.tencent.teo": "腾讯云 - 边缘安全加速平台 EO",
"common.provider.tencent.teo": "腾讯云 - 边缘安全加速平台 EdgeOne",
"common.provider.huaweicloud": "华为云",
"common.provider.huaweicloud.cdn": "华为云 - 内容分发网络 CDN",
"common.provider.huaweicloud.elb": "华为云 - 弹性负载均衡 ELB",
@ -88,4 +88,3 @@
"common.provider.lark": "飞书",
"common.provider.mail": "电子邮件"
}

View File

@ -65,7 +65,7 @@
"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": "替换指定负载均衡器的全部监听的证书(仅支持 HTTPS 监听)",
"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",
@ -75,8 +75,8 @@
"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/QUIC 监听)",
"domain.deployment.form.aliyun_alb_resource_type.option.listener.label": "替换指定监听器的证书",
"domain.deployment.form.aliyun_alb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 HTTPS/QUIC 监听的证书",
"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",
@ -85,8 +85,8 @@
"domain.deployment.form.aliyun_nlb_region.placeholder": "请输入地域(如 cn-hangzhou",
"domain.deployment.form.aliyun_nlb_resource_type.label": "替换方式",
"domain.deployment.form.aliyun_nlb_resource_type.placeholder": "请选择替换方式",
"domain.deployment.form.aliyun_nlb_resource_type.option.loadbalancer.label": "替换指定负载均衡器的全部监听的证书(仅支持 TCPSSL 监听)",
"domain.deployment.form.aliyun_nlb_resource_type.option.listener.label": "替换指定监听器的证书",
"domain.deployment.form.aliyun_nlb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 TCPSSL 监听的证书",
"domain.deployment.form.aliyun_nlb_resource_type.option.listener.label": "替换指定负载均衡监听器的证书",
"domain.deployment.form.aliyun_nlb_loadbalancer_id.label": "负载均衡器 ID",
"domain.deployment.form.aliyun_nlb_loadbalancer_id.placeholder": "请输入负载均衡器 ID",
"domain.deployment.form.aliyun_nlb_listener_id.label": "监听器 ID",
@ -97,12 +97,20 @@
"domain.deployment.form.tencent_cos_bucket.placeholder": "请输入存储桶名",
"domain.deployment.form.tencent_clb_region.label": "地域",
"domain.deployment.form.tencent_clb_region.placeholder": "请输入地域(如 ap-guangzhou",
"domain.deployment.form.tencent_clb_id.label": "负载均衡器 ID",
"domain.deployment.form.tencent_clb_id.placeholder": "请输入负载均衡器实例 ID如 lb-xxxxxxxx",
"domain.deployment.form.tencent_clb_listener.label": "监听器 ID对应监听器应已设置对应域名 HTTPS 转发, 且原证书对应域名应与待部署证书的一致)",
"domain.deployment.form.tencent_clb_listener.placeholder": "请输入监听器 ID如 lb-xxxxxxxx",
"domain.deployment.form.tencent_clb_resource_type.label": "替换方式",
"domain.deployment.form.tencent_clb_resource_type.placeholder": "请选择替换方式",
"domain.deployment.form.tencent_clb_resource_type.option.ssl_deploy.label": "通过 SSL 服务部署到云资源实例",
"domain.deployment.form.tencent_clb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 HTTPS/TCPSSL/QUIC 监听器的证书",
"domain.deployment.form.tencent_clb_resource_type.option.listener.label": "替换指定负载均衡监听器的证书",
"domain.deployment.form.tencent_clb_resource_type.option.ruledomain.label": "替换指定七层监听转发规则域名的证书",
"domain.deployment.form.tencent_clb_loadbalancer_id.label": "负载均衡器 ID",
"domain.deployment.form.tencent_clb_loadbalancer_id.placeholder": "请输入负载均衡器实例 ID",
"domain.deployment.form.tencent_clb_listener_id.label": "监听器 ID",
"domain.deployment.form.tencent_clb_listener_id.placeholder": "请输入监听器 ID",
"domain.deployment.form.tencent_clb_domain.label": "部署到域名(支持泛域名)",
"domain.deployment.form.tencent_clb_domain.placeholder": "请输入部署到的域名, 如未开启 SNI, 可置空忽略此项",
"domain.deployment.form.tencent_clb_ruledomain.label": "转发域名",
"domain.deployment.form.tencent_clb_ruledomain.placeholder": "请输入七层监听转发规则域名",
"domain.deployment.form.tencent_teo_zone_id.label": "Zone ID",
"domain.deployment.form.tencent_teo_zone_id.placeholder": "请输入 Zone ID",
"domain.deployment.form.tencent_teo_domain.label": "部署到域名(支持泛域名, 应与服务器上配置的域名完全一致, 每行一个域名)",
@ -112,8 +120,8 @@
"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": "替换指定负载均衡器的全部监听器的证书(仅支持 HTTPS 监听)",
"domain.deployment.form.huaweicloud_elb_resource_type.option.listener.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",
"domain.deployment.form.huaweicloud_elb_loadbalancer_id.label": "负载均衡器 ID",