mirror of
https://github.com/certimate-go/certimate.git
synced 2026-09-01 15:39:35 +08:00
feat(provider): new deployment provider: ucloud ualb
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
package deployers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/certimate-go/certimate/internal/domain"
|
||||
"github.com/certimate-go/certimate/pkg/core/deployer"
|
||||
ucloudualb "github.com/certimate-go/certimate/pkg/core/deployer/providers/ucloud-ualb"
|
||||
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Registries.MustRegister(domain.DeploymentProviderTypeUCloudUALB, func(options *ProviderFactoryOptions) (deployer.Provider, error) {
|
||||
credentials := domain.AccessConfigForUCloud{}
|
||||
if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
|
||||
return nil, fmt.Errorf("failed to populate provider access config: %w", err)
|
||||
}
|
||||
|
||||
provider, err := ucloudualb.NewDeployer(&ucloudualb.DeployerConfig{
|
||||
PrivateKey: credentials.PrivateKey,
|
||||
PublicKey: credentials.PublicKey,
|
||||
ProjectId: credentials.ProjectId,
|
||||
Region: xmaps.GetString(options.ProviderExtendedConfig, "region"),
|
||||
ResourceType: xmaps.GetString(options.ProviderExtendedConfig, "resourceType"),
|
||||
LoadbalancerId: xmaps.GetString(options.ProviderExtendedConfig, "loadbalancerId"),
|
||||
ListenerId: xmaps.GetString(options.ProviderExtendedConfig, "listenerId"),
|
||||
Domain: xmaps.GetString(options.ProviderExtendedConfig, "domain"),
|
||||
})
|
||||
return provider, err
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package ucloudualb
|
||||
|
||||
const (
|
||||
// 资源类型:部署到指定负载均衡器。
|
||||
RESOURCE_TYPE_LOADBALANCER = "loadbalancer"
|
||||
// 资源类型:部署到指定监听器。
|
||||
RESOURCE_TYPE_LISTENER = "listener"
|
||||
)
|
||||
@@ -0,0 +1,329 @@
|
||||
package ucloudualb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"github.com/samber/lo"
|
||||
ucloudlb "github.com/ucloud/ucloud-sdk-go/services/ulb"
|
||||
"github.com/ucloud/ucloud-sdk-go/ucloud"
|
||||
"github.com/ucloud/ucloud-sdk-go/ucloud/auth"
|
||||
|
||||
"github.com/certimate-go/certimate/pkg/core/certmgr"
|
||||
mcertmgr "github.com/certimate-go/certimate/pkg/core/certmgr/providers/ucloud-ulb"
|
||||
"github.com/certimate-go/certimate/pkg/core/deployer"
|
||||
usdklb "github.com/certimate-go/certimate/pkg/sdk3rd/ucloud/ulb"
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// 优刻得 API 私钥。
|
||||
PrivateKey string `json:"privateKey"`
|
||||
// 优刻得 API 公钥。
|
||||
PublicKey string `json:"publicKey"`
|
||||
// 优刻得项目 ID。
|
||||
ProjectId string `json:"projectId,omitempty"`
|
||||
// 优刻得地域。
|
||||
Region string `json:"region"`
|
||||
// 部署资源类型。
|
||||
ResourceType string `json:"resourceType"`
|
||||
// 负载均衡实例 ID。
|
||||
// 部署资源类型为 [RESOURCE_TYPE_LOADBALANCER]、[RESOURCE_TYPE_LISTENER] 时必填。
|
||||
LoadbalancerId string `json:"loadbalancerId,omitempty"`
|
||||
// 负载均衡监听器 ID。
|
||||
// 部署资源类型为 [RESOURCE_TYPE_LISTENER] 时必填。
|
||||
ListenerId string `json:"listenerId,omitempty"`
|
||||
// SNI 域名(不支持泛域名)。
|
||||
// 部署资源类型为 [RESOURCE_TYPE_LISTENER] 时选填。
|
||||
Domain string `json:"domain,omitempty"`
|
||||
}
|
||||
|
||||
type Deployer struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
sdkClient *usdklb.ULBClient
|
||||
sdkCertmgr certmgr.Provider
|
||||
}
|
||||
|
||||
var _ deployer.Provider = (*Deployer)(nil)
|
||||
|
||||
func NewDeployer(config *DeployerConfig) (*Deployer, error) {
|
||||
if config == nil {
|
||||
return nil, errors.New("the configuration of the deployer provider is nil")
|
||||
}
|
||||
|
||||
client, err := createSDKClient(config.PrivateKey, config.PublicKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create client: %w", err)
|
||||
}
|
||||
|
||||
pcertmgr, err := mcertmgr.NewCertmgr(&mcertmgr.CertmgrConfig{
|
||||
PrivateKey: config.PrivateKey,
|
||||
PublicKey: config.PublicKey,
|
||||
ProjectId: config.ProjectId,
|
||||
Region: config.Region,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create certmgr: %w", err)
|
||||
}
|
||||
|
||||
return &Deployer{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
sdkClient: client,
|
||||
sdkCertmgr: pcertmgr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Deployer) SetLogger(logger *slog.Logger) {
|
||||
if logger == nil {
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
|
||||
d.sdkCertmgr.SetLogger(logger)
|
||||
}
|
||||
|
||||
func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*deployer.DeployResult, error) {
|
||||
// 上传证书
|
||||
upres, err := d.sdkCertmgr.Upload(ctx, certPEM, privkeyPEM)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to upload certificate file: %w", err)
|
||||
} else {
|
||||
d.logger.Info("ssl certificate uploaded", slog.Any("result", upres))
|
||||
}
|
||||
|
||||
// 根据部署资源类型决定部署方式
|
||||
switch d.config.ResourceType {
|
||||
case RESOURCE_TYPE_LOADBALANCER:
|
||||
if err := d.deployToLoadbalancer(ctx, upres.CertId); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
case RESOURCE_TYPE_LISTENER:
|
||||
if err := d.deployToListener(ctx, upres.CertId); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported resource type '%s'", d.config.ResourceType)
|
||||
}
|
||||
|
||||
return &deployer.DeployResult{}, nil
|
||||
}
|
||||
|
||||
func (d *Deployer) deployToLoadbalancer(ctx context.Context, cloudCertId string) error {
|
||||
if d.config.LoadbalancerId == "" {
|
||||
return errors.New("config `loadbalancerId` is required")
|
||||
}
|
||||
|
||||
// 获取 ALB 下的 HTTPS 监听器列表
|
||||
// REF: https://docs.ucloud.cn/api/ulb-api/describe_listeners
|
||||
listenerIds := make([]string, 0)
|
||||
describeListenersOffset := 0
|
||||
describeListenersLimit := 100
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
describeListenerReq := d.sdkClient.NewDescribeListenersRequest()
|
||||
describeListenerReq.Region = ucloud.String(d.config.Region)
|
||||
describeListenerReq.LoadBalancerId = ucloud.String(d.config.LoadbalancerId)
|
||||
describeListenerReq.Offset = ucloud.Int(describeListenersOffset)
|
||||
describeListenerReq.Limit = ucloud.Int(describeListenersLimit)
|
||||
if d.config.ProjectId != "" {
|
||||
describeListenerReq.ProjectId = ucloud.String(d.config.ProjectId)
|
||||
}
|
||||
describeListenerResp, err := d.sdkClient.DescribeListeners(describeListenerReq)
|
||||
d.logger.Debug("sdk request 'ulb.DescribeListeners'", slog.Any("request", describeListenerReq), slog.Any("response", describeListenerResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'ulb.DescribeListeners': %w", err)
|
||||
}
|
||||
|
||||
for _, listenerItem := range describeListenerResp.Listeners {
|
||||
if listenerItem.ListenerProtocol == "HTTPS" {
|
||||
listenerIds = append(listenerIds, listenerItem.ListenerId)
|
||||
}
|
||||
}
|
||||
|
||||
if len(describeListenerResp.Listeners) < describeListenersLimit {
|
||||
break
|
||||
}
|
||||
|
||||
describeListenersOffset += describeListenersLimit
|
||||
}
|
||||
|
||||
// 遍历更新 Listener 证书
|
||||
if len(listenerIds) == 0 {
|
||||
d.logger.Info("no alb listeners to deploy")
|
||||
} else {
|
||||
d.logger.Info("found https listeners to deploy", slog.Any("listenerIds", listenerIds))
|
||||
var errs []error
|
||||
|
||||
for _, listenerId := range listenerIds {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
if err := d.updateListenerCertificate(ctx, d.config.LoadbalancerId, listenerId, cloudCertId); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Deployer) deployToListener(ctx context.Context, cloudCertId string) error {
|
||||
if d.config.LoadbalancerId == "" {
|
||||
return errors.New("config `loadbalancerId` is required")
|
||||
}
|
||||
if d.config.ListenerId == "" {
|
||||
return errors.New("config `listenerId` is required")
|
||||
}
|
||||
|
||||
if err := d.updateListenerCertificate(ctx, d.config.LoadbalancerId, d.config.ListenerId, cloudCertId); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Deployer) updateListenerCertificate(ctx context.Context, cloudLoadbalancerId, cloudListenerId string, cloudCertId string) error {
|
||||
// 描述应用型负载均衡监听器
|
||||
// REF: https://docs.ucloud.cn/api/ulb-api/describe_listeners
|
||||
describeListenersReq := d.sdkClient.NewDescribeListenersRequest()
|
||||
describeListenersReq.Region = ucloud.String(d.config.Region)
|
||||
describeListenersReq.LoadBalancerId = ucloud.String(cloudLoadbalancerId)
|
||||
describeListenersReq.ListenerId = ucloud.String(cloudListenerId)
|
||||
describeListenersReq.Limit = ucloud.Int(1)
|
||||
if d.config.ProjectId != "" {
|
||||
describeListenersReq.ProjectId = ucloud.String(d.config.ProjectId)
|
||||
}
|
||||
describeListenerResp, err := d.sdkClient.DescribeListeners(describeListenersReq)
|
||||
d.logger.Debug("sdk request 'ulb.DescribeListeners'", slog.Any("request", describeListenersReq), slog.Any("response", describeListenerResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'ulb.DescribeListeners': %w", err)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'ulb.DescribeListeners': %w", err)
|
||||
} else if len(describeListenerResp.Listeners) == 0 {
|
||||
return fmt.Errorf("could not find listener '%s'", cloudListenerId)
|
||||
}
|
||||
|
||||
// 跳过已部署过的监听器
|
||||
listenerInfo := describeListenerResp.Listeners[0]
|
||||
if d.config.Domain == "" {
|
||||
if lo.ContainsBy(listenerInfo.Certificates, func(item ucloudlb.Certificate) bool { return item.SSLId == cloudCertId && item.IsDefault }) {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
if lo.ContainsBy(listenerInfo.Certificates, func(item ucloudlb.Certificate) bool { return item.SSLId == cloudCertId && !item.IsDefault }) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if d.config.Domain == "" {
|
||||
// 未指定 SNI,只需部署到监听器
|
||||
|
||||
updateListenerAttributeReq := d.sdkClient.NewUpdateListenerAttributeRequest()
|
||||
updateListenerAttributeReq.Region = ucloud.String(d.config.Region)
|
||||
updateListenerAttributeReq.LoadBalancerId = ucloud.String(cloudLoadbalancerId)
|
||||
updateListenerAttributeReq.ListenerId = ucloud.String(cloudListenerId)
|
||||
updateListenerAttributeReq.Certificates = []string{cloudCertId}
|
||||
if d.config.ProjectId != "" {
|
||||
updateListenerAttributeReq.ProjectId = ucloud.String(d.config.ProjectId)
|
||||
}
|
||||
updateListenerResp, err := d.sdkClient.UpdateListenerAttribute(updateListenerAttributeReq)
|
||||
d.logger.Debug("sdk request 'ulb.UpdateListenerAttribute'", slog.Any("request", updateListenerAttributeReq), slog.Any("response", updateListenerResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'ulb.UpdateListenerAttribute': %w", err)
|
||||
}
|
||||
} else {
|
||||
// 指定 SNI,需部署到扩展域名
|
||||
|
||||
// 新增监听器扩展证书
|
||||
// REF: https://docs.ucloud.cn/api/ulb-api/add_ssl_binding_json
|
||||
addSSLBindingReq := d.sdkClient.NewAddSSLBindingRequest()
|
||||
addSSLBindingReq.Region = ucloud.String(d.config.Region)
|
||||
addSSLBindingReq.LoadBalancerId = ucloud.String(cloudLoadbalancerId)
|
||||
addSSLBindingReq.ListenerId = ucloud.String(cloudListenerId)
|
||||
addSSLBindingReq.SSLIds = []string{cloudCertId}
|
||||
if d.config.ProjectId != "" {
|
||||
addSSLBindingReq.ProjectId = ucloud.String(d.config.ProjectId)
|
||||
}
|
||||
addSSLBindingResp, err := d.sdkClient.AddSSLBinding(addSSLBindingReq)
|
||||
d.logger.Debug("sdk request 'ulb.AddSSLBinding'", slog.Any("request", addSSLBindingReq), slog.Any("response", addSSLBindingResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'ulb.AddSSLBinding': %w", err)
|
||||
}
|
||||
|
||||
// 删除已过期的监听器绑定的扩展证书
|
||||
// REF: https://docs.ucloud.cn/api/ulb-api/describe_sslv2
|
||||
// REF: https://docs.ucloud.cn/api/ulb-api/delete_ssl_binding_json
|
||||
for _, certItem := range listenerInfo.Certificates {
|
||||
if certItem.IsDefault {
|
||||
continue
|
||||
}
|
||||
|
||||
describeSSLV2Req := d.sdkClient.NewDescribeSSLV2Request()
|
||||
describeSSLV2Req.Region = ucloud.String(d.config.Region)
|
||||
describeSSLV2Req.SSLId = ucloud.String(certItem.SSLId)
|
||||
describeSSLV2Req.Limit = ucloud.Int(1)
|
||||
if d.config.ProjectId != "" {
|
||||
describeSSLV2Req.ProjectId = ucloud.String(d.config.ProjectId)
|
||||
}
|
||||
describeSSLV2Resp, err := d.sdkClient.DescribeSSLV2(describeSSLV2Req)
|
||||
d.logger.Debug("sdk request 'ulb.DescribeSSLV2'", slog.Any("request", describeSSLV2Req), slog.Any("response", describeSSLV2Resp))
|
||||
if err != nil {
|
||||
continue
|
||||
} else if len(describeSSLV2Resp.DataSet) == 0 {
|
||||
continue
|
||||
} else {
|
||||
}
|
||||
|
||||
sslItem := describeSSLV2Resp.DataSet[0]
|
||||
if sslItem.NotAfter == 0 || int64(sslItem.NotAfter) >= time.Now().Unix() {
|
||||
continue
|
||||
}
|
||||
|
||||
deleteSSLBindingReq := d.sdkClient.NewDeleteSSLBindingRequest()
|
||||
deleteSSLBindingReq.Region = ucloud.String(d.config.Region)
|
||||
deleteSSLBindingReq.LoadBalancerId = ucloud.String(cloudLoadbalancerId)
|
||||
deleteSSLBindingReq.ListenerId = ucloud.String(cloudListenerId)
|
||||
deleteSSLBindingReq.SSLIds = []string{sslItem.SSLId}
|
||||
if d.config.ProjectId != "" {
|
||||
deleteSSLBindingReq.ProjectId = ucloud.String(d.config.ProjectId)
|
||||
}
|
||||
deleteSSLBindingResp, err := d.sdkClient.DeleteSSLBinding(deleteSSLBindingReq)
|
||||
d.logger.Debug("sdk request 'ulb.DeleteSSLBinding'", slog.Any("request", deleteSSLBindingReq), slog.Any("response", deleteSSLBindingResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'ulb.DeleteSSLBinding': %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createSDKClient(privateKey, publicKey string) (*usdklb.ULBClient, error) {
|
||||
cfg := ucloud.NewConfig()
|
||||
|
||||
credential := auth.NewCredential()
|
||||
credential.PrivateKey = privateKey
|
||||
credential.PublicKey = publicKey
|
||||
|
||||
client := usdklb.NewClient(&cfg, &credential)
|
||||
return client, nil
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package ucloudualb_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
provider "github.com/certimate-go/certimate/pkg/core/deployer/providers/ucloud-ualb"
|
||||
)
|
||||
|
||||
var (
|
||||
fInputCertPath string
|
||||
fInputKeyPath string
|
||||
fPrivateKey string
|
||||
fPublicKey string
|
||||
fRegion string
|
||||
fLoadbalancerId string
|
||||
fListenerId string
|
||||
)
|
||||
|
||||
func init() {
|
||||
argsPrefix := "UCLOUDUALB_"
|
||||
|
||||
flag.StringVar(&fInputCertPath, argsPrefix+"INPUTCERTPATH", "", "")
|
||||
flag.StringVar(&fInputKeyPath, argsPrefix+"INPUTKEYPATH", "", "")
|
||||
flag.StringVar(&fPrivateKey, argsPrefix+"PRIVATEKEY", "", "")
|
||||
flag.StringVar(&fPublicKey, argsPrefix+"PUBLICKEY", "", "")
|
||||
flag.StringVar(&fRegion, argsPrefix+"REGION", "", "")
|
||||
flag.StringVar(&fLoadbalancerId, argsPrefix+"LOADBALANCERID", "", "")
|
||||
flag.StringVar(&fListenerId, argsPrefix+"LISTENERID", "", "")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./ucloud_ualb_test.go -args \
|
||||
--UCLOUDUALB_INPUTCERTPATH="/path/to/your-input-cert.pem" \
|
||||
--UCLOUDUALB_INPUTKEYPATH="/path/to/your-input-key.pem" \
|
||||
--UCLOUDUALB_PRIVATEKEY="your-private-key" \
|
||||
--UCLOUDUALB_PUBLICKEY="your-public-key" \
|
||||
--UCLOUDUALB_REGION="cn-bj2" \
|
||||
--UCLOUDUALB_LOADBALANCERID="your-loadbalancer-id" \
|
||||
--UCLOUDUALB_LISTENERID="your-listener-id"
|
||||
*/
|
||||
func TestDeploy(t *testing.T) {
|
||||
flag.Parse()
|
||||
|
||||
t.Run("Deploy", func(t *testing.T) {
|
||||
t.Log(strings.Join([]string{
|
||||
"args:",
|
||||
fmt.Sprintf("INPUTCERTPATH: %v", fInputCertPath),
|
||||
fmt.Sprintf("INPUTKEYPATH: %v", fInputKeyPath),
|
||||
fmt.Sprintf("PRIVATEKEY: %v", fPrivateKey),
|
||||
fmt.Sprintf("PUBLICKEY: %v", fPublicKey),
|
||||
fmt.Sprintf("REGION: %v", fRegion),
|
||||
fmt.Sprintf("LOADBALANCERID: %v", fLoadbalancerId),
|
||||
fmt.Sprintf("LISTENERID: %v", fListenerId),
|
||||
}, "\n"))
|
||||
|
||||
provider, err := provider.NewDeployer(&provider.DeployerConfig{
|
||||
PrivateKey: fPrivateKey,
|
||||
PublicKey: fPublicKey,
|
||||
Region: fRegion,
|
||||
ResourceType: provider.RESOURCE_TYPE_LISTENER,
|
||||
LoadbalancerId: fLoadbalancerId,
|
||||
ListenerId: fListenerId,
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fInputCertData, _ := os.ReadFile(fInputCertPath)
|
||||
fInputKeyData, _ := os.ReadFile(fInputKeyPath)
|
||||
res, err := provider.Deploy(context.Background(), string(fInputCertData), string(fInputKeyData))
|
||||
if err != nil {
|
||||
t.Errorf("err: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
t.Logf("ok: %v", res)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package ulb
|
||||
|
||||
import (
|
||||
ucloudlb "github.com/ucloud/ucloud-sdk-go/services/ulb"
|
||||
)
|
||||
|
||||
type AddSSLBindingRequest = ucloudlb.AddSSLBindingRequest
|
||||
|
||||
type AddSSLBindingResponse = ucloudlb.AddSSLBindingResponse
|
||||
|
||||
func (c *ULBClient) NewAddSSLBindingRequest() *AddSSLBindingRequest {
|
||||
req := &AddSSLBindingRequest{}
|
||||
|
||||
c.Client.SetupRequest(req)
|
||||
|
||||
req.SetRetryable(true)
|
||||
return req
|
||||
}
|
||||
|
||||
func (c *ULBClient) AddSSLBinding(req *AddSSLBindingRequest) (*AddSSLBindingResponse, error) {
|
||||
var err error
|
||||
var res AddSSLBindingResponse
|
||||
|
||||
reqCopier := *req
|
||||
|
||||
err = c.Client.InvokeAction("AddSSLBinding", &reqCopier, &res)
|
||||
if err != nil {
|
||||
return &res, err
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package ulb
|
||||
|
||||
import (
|
||||
ucloudlb "github.com/ucloud/ucloud-sdk-go/services/ulb"
|
||||
)
|
||||
|
||||
type DeleteSSLBindingRequest = ucloudlb.DeleteSSLBindingRequest
|
||||
|
||||
type DeleteSSLBindingResponse = ucloudlb.DeleteSSLBindingResponse
|
||||
|
||||
func (c *ULBClient) NewDeleteSSLBindingRequest() *DeleteSSLBindingRequest {
|
||||
req := &DeleteSSLBindingRequest{}
|
||||
|
||||
c.Client.SetupRequest(req)
|
||||
|
||||
req.SetRetryable(true)
|
||||
return req
|
||||
}
|
||||
|
||||
func (c *ULBClient) DeleteSSLBinding(req *DeleteSSLBindingRequest) (*DeleteSSLBindingResponse, error) {
|
||||
var err error
|
||||
var res DeleteSSLBindingResponse
|
||||
|
||||
reqCopier := *req
|
||||
|
||||
err = c.Client.InvokeAction("DeleteSSLBinding", &reqCopier, &res)
|
||||
if err != nil {
|
||||
return &res, err
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package ulb
|
||||
|
||||
import (
|
||||
ucloudlb "github.com/ucloud/ucloud-sdk-go/services/ulb"
|
||||
)
|
||||
|
||||
type DescribeListenersRequest = ucloudlb.DescribeListenersRequest
|
||||
|
||||
type DescribeListenersResponse = ucloudlb.DescribeListenersResponse
|
||||
|
||||
func (c *ULBClient) NewDescribeListenersRequest() *DescribeListenersRequest {
|
||||
req := &DescribeListenersRequest{}
|
||||
|
||||
c.Client.SetupRequest(req)
|
||||
|
||||
req.SetRetryable(true)
|
||||
return req
|
||||
}
|
||||
|
||||
func (c *ULBClient) DescribeListeners(req *DescribeListenersRequest) (*DescribeListenersResponse, error) {
|
||||
var err error
|
||||
var res DescribeListenersResponse
|
||||
|
||||
reqCopier := *req
|
||||
|
||||
err = c.Client.InvokeAction("DescribeListeners", &reqCopier, &res)
|
||||
if err != nil {
|
||||
return &res, err
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package ulb
|
||||
|
||||
import (
|
||||
ucloudlb "github.com/ucloud/ucloud-sdk-go/services/ulb"
|
||||
)
|
||||
|
||||
type DescribeSSLV2Request = ucloudlb.DescribeSSLV2Request
|
||||
|
||||
type DescribeSSLV2Response = ucloudlb.DescribeSSLV2Response
|
||||
|
||||
func (c *ULBClient) NewDescribeSSLV2Request() *DescribeSSLV2Request {
|
||||
req := &DescribeSSLV2Request{}
|
||||
|
||||
c.Client.SetupRequest(req)
|
||||
|
||||
req.SetRetryable(true)
|
||||
return req
|
||||
}
|
||||
|
||||
func (c *ULBClient) DescribeSSLV2(req *DescribeSSLV2Request) (*DescribeSSLV2Response, error) {
|
||||
var err error
|
||||
var res DescribeSSLV2Response
|
||||
|
||||
reqCopier := *req
|
||||
|
||||
err = c.Client.InvokeAction("DescribeSSLV2", &reqCopier, &res)
|
||||
if err != nil {
|
||||
return &res, err
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package ulb
|
||||
|
||||
import (
|
||||
ucloudlb "github.com/ucloud/ucloud-sdk-go/services/ulb"
|
||||
)
|
||||
|
||||
type UpdateListenerAttributeRequest = ucloudlb.UpdateListenerAttributeRequest
|
||||
|
||||
type UpdateListenerAttributeResponse = ucloudlb.UpdateListenerAttributeResponse
|
||||
|
||||
func (c *ULBClient) NewUpdateListenerAttributeRequest() *UpdateListenerAttributeRequest {
|
||||
req := &UpdateListenerAttributeRequest{}
|
||||
|
||||
c.Client.SetupRequest(req)
|
||||
|
||||
req.SetRetryable(true)
|
||||
return req
|
||||
}
|
||||
|
||||
func (c *ULBClient) UpdateListenerAttribute(req *UpdateListenerAttributeRequest) (*UpdateListenerAttributeResponse, error) {
|
||||
var err error
|
||||
var res UpdateListenerAttributeResponse
|
||||
|
||||
reqCopier := *req
|
||||
|
||||
err = c.Client.InvokeAction("UpdateListenerAttribute", &reqCopier, &res)
|
||||
if err != nil {
|
||||
return &res, err
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
@@ -83,6 +83,7 @@ import BizDeployNodeConfigFieldsProviderTencentCloudSSLDeploy from "./BizDeployN
|
||||
import BizDeployNodeConfigFieldsProviderTencentCloudSSLUpdate from "./BizDeployNodeConfigFieldsProviderTencentCloudSSLUpdate";
|
||||
import BizDeployNodeConfigFieldsProviderTencentCloudVOD from "./BizDeployNodeConfigFieldsProviderTencentCloudVOD";
|
||||
import BizDeployNodeConfigFieldsProviderTencentCloudWAF from "./BizDeployNodeConfigFieldsProviderTencentCloudWAF";
|
||||
import BizDeployNodeConfigFieldsProviderUCloudUALB from "./BizDeployNodeConfigFieldsProviderUCloudUALB";
|
||||
import BizDeployNodeConfigFieldsProviderUCloudUCDN from "./BizDeployNodeConfigFieldsProviderUCloudUCDN";
|
||||
import BizDeployNodeConfigFieldsProviderUCloudUCLB from "./BizDeployNodeConfigFieldsProviderUCloudUCLB";
|
||||
import BizDeployNodeConfigFieldsProviderUCloudUS3 from "./BizDeployNodeConfigFieldsProviderUCloudUS3";
|
||||
@@ -189,6 +190,7 @@ const providerComponentMap: Partial<Record<DeploymentProviderType, React.Compone
|
||||
[DEPLOYMENT_PROVIDERS.TENCENTCLOUD_SSL_UPDATE]: BizDeployNodeConfigFieldsProviderTencentCloudSSLUpdate,
|
||||
[DEPLOYMENT_PROVIDERS.TENCENTCLOUD_VOD]: BizDeployNodeConfigFieldsProviderTencentCloudVOD,
|
||||
[DEPLOYMENT_PROVIDERS.TENCENTCLOUD_WAF]: BizDeployNodeConfigFieldsProviderTencentCloudWAF,
|
||||
[DEPLOYMENT_PROVIDERS.UCLOUD_UALB]: BizDeployNodeConfigFieldsProviderUCloudUALB,
|
||||
[DEPLOYMENT_PROVIDERS.UCLOUD_UCDN]: BizDeployNodeConfigFieldsProviderUCloudUCDN,
|
||||
[DEPLOYMENT_PROVIDERS.UCLOUD_UCLB]: BizDeployNodeConfigFieldsProviderUCloudUCLB,
|
||||
[DEPLOYMENT_PROVIDERS.UCLOUD_US3]: BizDeployNodeConfigFieldsProviderUCloudUS3,
|
||||
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input, Select } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import Show from "@/components/Show";
|
||||
import { validDomainName } from "@/utils/validators";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const RESOURCE_TYPE_LOADBALANCER = "loadbalancer" as const;
|
||||
const RESOURCE_TYPE_LISTENER = "listener" as const;
|
||||
|
||||
const BizDeployNodeConfigFieldsProviderUCloudUALB = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({
|
||||
[parentNamePath]: getSchema({ i18n }),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const formInst = Form.useFormInstance();
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
const fieldResourceType = Form.useWatch([parentNamePath, "resourceType"], formInst);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "region"]}
|
||||
initialValue={initialValues.region}
|
||||
label={t("workflow_node.deploy.form.ucloud_ualb_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.ucloud_ualb_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.ucloud_ualb_region.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "resourceType"]}
|
||||
initialValue={initialValues.resourceType}
|
||||
label={t("workflow_node.deploy.form.shared_resource_type.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Select
|
||||
options={[RESOURCE_TYPE_LOADBALANCER, RESOURCE_TYPE_LISTENER].map((s) => ({
|
||||
value: s,
|
||||
label: t(`workflow_node.deploy.form.ucloud_ualb_resource_type.option.${s}.label`),
|
||||
}))}
|
||||
placeholder={t("workflow_node.deploy.form.shared_resource_type.placeholder")}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "loadbalancerId"]}
|
||||
initialValue={initialValues.loadbalancerId}
|
||||
label={t("workflow_node.deploy.form.ucloud_ualb_loadbalancer_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.ucloud_ualb_loadbalancer_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.ucloud_ualb_loadbalancer_id.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Show when={fieldResourceType === RESOURCE_TYPE_LISTENER}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "listenerId"]}
|
||||
initialValue={initialValues.listenerId}
|
||||
label={t("workflow_node.deploy.form.ucloud_ualb_listener_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.ucloud_ualb_listener_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("workflow_node.deploy.form.ucloud_ualb_listener_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
|
||||
<Show when={fieldResourceType === RESOURCE_TYPE_LOADBALANCER || fieldResourceType === RESOURCE_TYPE_LISTENER}>
|
||||
<Form.Item
|
||||
name={[parentNamePath, "domain"]}
|
||||
initialValue={initialValues.domain}
|
||||
label={t("workflow_node.deploy.form.ucloud_ualb_snidomain.label")}
|
||||
extra={t("workflow_node.deploy.form.ucloud_ualb_snidomain.help")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Input allowClear placeholder={t("workflow_node.deploy.form.ucloud_ualb_snidomain.placeholder")} />
|
||||
</Form.Item>
|
||||
</Show>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
region: "",
|
||||
resourceType: RESOURCE_TYPE_LISTENER,
|
||||
loadbalancerId: "",
|
||||
listenerId: "",
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n?: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z
|
||||
.object({
|
||||
endpoint: z.string().nullish(),
|
||||
resourceType: z.literal([RESOURCE_TYPE_LOADBALANCER, RESOURCE_TYPE_LISTENER], t("workflow_node.deploy.form.shared_resource_type.placeholder")),
|
||||
region: z.string().nonempty(t("workflow_node.deploy.form.ucloud_ualb_region.placeholder")),
|
||||
loadbalancerId: z.string().nonempty(t("workflow_node.deploy.form.ucloud_ualb_loadbalancer_id.placeholder")),
|
||||
listenerId: z.string().nullish(),
|
||||
domain: z
|
||||
.string()
|
||||
.nullish()
|
||||
.refine((v) => {
|
||||
return !v || validDomainName(v);
|
||||
}, t("common.errmsg.domain_invalid")),
|
||||
})
|
||||
.superRefine((values, ctx) => {
|
||||
switch (values.resourceType) {
|
||||
case RESOURCE_TYPE_LISTENER:
|
||||
{
|
||||
if (!values.listenerId?.trim()) {
|
||||
ctx.addIssue({
|
||||
code: "custom",
|
||||
message: t("workflow_node.deploy.form.ucloud_ualb_listener_id.placeholder"),
|
||||
path: ["listenerId"],
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const _default = Object.assign(BizDeployNodeConfigFieldsProviderUCloudUALB, {
|
||||
getInitialValues,
|
||||
getSchema,
|
||||
});
|
||||
|
||||
export default _default;
|
||||
@@ -617,6 +617,7 @@ export const DEPLOYMENT_PROVIDERS = Object.freeze({
|
||||
TENCENTCLOUD_SSL_UPDATE: `${ACCESS_PROVIDERS.TENCENTCLOUD}-sslupdate`,
|
||||
TENCENTCLOUD_VOD: `${ACCESS_PROVIDERS.TENCENTCLOUD}-vod`,
|
||||
TENCENTCLOUD_WAF: `${ACCESS_PROVIDERS.TENCENTCLOUD}-waf`,
|
||||
UCLOUD_UALB: `${ACCESS_PROVIDERS.UCLOUD}-ualb`,
|
||||
UCLOUD_UCDN: `${ACCESS_PROVIDERS.UCLOUD}-ucdn`,
|
||||
UCLOUD_UCLB: `${ACCESS_PROVIDERS.UCLOUD}-uclb`,
|
||||
UCLOUD_US3: `${ACCESS_PROVIDERS.UCLOUD}-us3`,
|
||||
@@ -738,6 +739,7 @@ export const deploymentProvidersMap: Map<DeploymentProvider["type"] | string, De
|
||||
[DEPLOYMENT_PROVIDERS.UCLOUD_US3, "provider.ucloud_us3", DEPLOYMENT_CATEGORIES.STORAGE],
|
||||
[DEPLOYMENT_PROVIDERS.UCLOUD_UCDN, "provider.ucloud_ucdn", DEPLOYMENT_CATEGORIES.CDN],
|
||||
[DEPLOYMENT_PROVIDERS.UCLOUD_UCLB, "provider.ucloud_uclb", DEPLOYMENT_CATEGORIES.LOADBALANCE],
|
||||
[DEPLOYMENT_PROVIDERS.UCLOUD_UALB, "provider.ucloud_ualb", DEPLOYMENT_CATEGORIES.LOADBALANCE],
|
||||
[DEPLOYMENT_PROVIDERS.CTCCCLOUD_CDN, "provider.ctcccloud_cdn", DEPLOYMENT_CATEGORIES.CDN],
|
||||
[DEPLOYMENT_PROVIDERS.CTCCCLOUD_ICDN, "provider.ctcccloud_icdn", DEPLOYMENT_CATEGORIES.CDN],
|
||||
[DEPLOYMENT_PROVIDERS.CTCCCLOUD_AO, "provider.ctcccloud_ao", DEPLOYMENT_CATEGORIES.CDN],
|
||||
|
||||
@@ -183,6 +183,7 @@
|
||||
"provider.tencentcloud_vod": "Tencent Cloud - VOD (Video on Demand)",
|
||||
"provider.tencentcloud_waf": "Tencent Cloud - WAF (Web Application Firewall)",
|
||||
"provider.ucloud": "UCloud",
|
||||
"provider.ucloud_ualb": "UCloud - UALB (Application Load Balancer)",
|
||||
"provider.ucloud_ucdn": "UCloud - UCDN (Content Delivery Network)",
|
||||
"provider.ucloud_uclb": "UCloud - UCLB (Classic Load Balancer)",
|
||||
"provider.ucloud_udnr": "UCloud - UDNR (Domain Name Registrar)",
|
||||
|
||||
@@ -910,6 +910,20 @@
|
||||
"workflow_node.deploy.form.tencentcloud_waf_instance_id.label": "Tencent Cloud WAF instance ID",
|
||||
"workflow_node.deploy.form.tencentcloud_waf_instance_id.placeholder": "Please enter Tencent Cloud WAF instance ID",
|
||||
"workflow_node.deploy.form.tencentcloud_waf_instance_id.tooltip": "For more information, see <a href=\"https://console.tencentcloud.com/waf\" target=\"_blank\">https://console.tencentcloud.com/waf</a>",
|
||||
"workflow_node.deploy.form.ucloud_ualb_region.label": "UCloud region",
|
||||
"workflow_node.deploy.form.ucloud_ualb_region.placeholder": "Please enter UCloud ALB region (e.g. cn-bj2)",
|
||||
"workflow_node.deploy.form.ucloud_ualb_region.tooltip": "For more information, see <a href=\"https://www.ucloud-global.com/en/docs/api/summary/regionlist\" target=\"_blank\">https://www.ucloud-global.com/en/docs/api/summary/regionlist</a>",
|
||||
"workflow_node.deploy.form.ucloud_ualb_resource_type.option.loadbalancer.label": "UALB load balancer",
|
||||
"workflow_node.deploy.form.ucloud_ualb_resource_type.option.listener.label": "UALB listener",
|
||||
"workflow_node.deploy.form.ucloud_ualb_loadbalancer_id.label": "UCloud UALB load balancer ID",
|
||||
"workflow_node.deploy.form.ucloud_ualb_loadbalancer_id.placeholder": "Please enter UCloud ALB load balancer ID",
|
||||
"workflow_node.deploy.form.ucloud_ualb_loadbalancer_id.tooltip": "For more information, see <a href=\"https://console.ucloud-global.com/ulb/alb\" target=\"_blank\">https://console.ucloud-global.com/ulb/alb</a>",
|
||||
"workflow_node.deploy.form.ucloud_ualb_listener_id.label": "UCloud UALB listener ID",
|
||||
"workflow_node.deploy.form.ucloud_ualb_listener_id.placeholder": "Please enter UCloud ALB listener ID",
|
||||
"workflow_node.deploy.form.ucloud_ualb_listener_id.tooltip": "For more information, see <a href=\"https://console.ucloud-global.com/ulb/alb\" target=\"_blank\">https://console.ucloud-global.com/ulb/alb</a>",
|
||||
"workflow_node.deploy.form.ucloud_ualb_snidomain.label": "UCloud UALB SNI domain (Optional)",
|
||||
"workflow_node.deploy.form.ucloud_ualb_snidomain.placeholder": "Please enter UCloud UALB SNI domain name",
|
||||
"workflow_node.deploy.form.ucloud_ualb_snidomain.help": "",
|
||||
"workflow_node.deploy.form.ucloud_ucdn_domain_id.label": "UCloud UCDN domain ID",
|
||||
"workflow_node.deploy.form.ucloud_ucdn_domain_id.placeholder": "Please enter UCloud UCDN domain ID",
|
||||
"workflow_node.deploy.form.ucloud_ucdn_domain_id.tooltip": "For more information, see <a href=\"https://console.ucloud-global.com/ucdn\" target=\"_blank\">https://console.ucloud-global.com/ucdn</a>",
|
||||
@@ -960,8 +974,8 @@
|
||||
"workflow_node.deploy.form.volcengine_alb_listener_id.label": "VolcEngine ALB listener ID",
|
||||
"workflow_node.deploy.form.volcengine_alb_listener_id.placeholder": "Please enter VolcEngine ALB listener ID",
|
||||
"workflow_node.deploy.form.volcengine_alb_listener_id.tooltip": "For more information, see <a href=\"https://console.volcengine.com/alb\" target=\"_blank\">https://console.volcengine.com/alb</a>",
|
||||
"workflow_node.deploy.form.volcengine_alb_snidomain.label": "VolcEngine CLB SNI domain (Optional)",
|
||||
"workflow_node.deploy.form.volcengine_alb_snidomain.placeholder": "Please enter VolcEngine CLB SNI domain name",
|
||||
"workflow_node.deploy.form.volcengine_alb_snidomain.label": "VolcEngine ALB SNI domain (Optional)",
|
||||
"workflow_node.deploy.form.volcengine_alb_snidomain.placeholder": "Please enter VolcEngine ALB SNI domain name",
|
||||
"workflow_node.deploy.form.volcengine_alb_snidomain.help": "",
|
||||
"workflow_node.deploy.form.volcengine_cdn_domain.label": "VolcEngine CDN domain",
|
||||
"workflow_node.deploy.form.volcengine_cdn_domain.placeholder": "Please enter VolcEngine CDN domain name",
|
||||
|
||||
@@ -183,6 +183,7 @@
|
||||
"provider.tencentcloud_vod": "腾讯云 - 云点播 VOD",
|
||||
"provider.tencentcloud_waf": "腾讯云 - Web 应用防火墙 WAF",
|
||||
"provider.ucloud": "优刻得",
|
||||
"provider.ucloud_ualb": "优刻得 - 应用型负载均衡 ALB",
|
||||
"provider.ucloud_ucdn": "优刻得 - 内容分发 UCDN",
|
||||
"provider.ucloud_uclb": "优刻得 - 传统型负载均衡 CLB",
|
||||
"provider.ucloud_udnr": "优刻得 - 域名服务 UDNR",
|
||||
|
||||
@@ -908,6 +908,20 @@
|
||||
"workflow_node.deploy.form.tencentcloud_waf_instance_id.label": "腾讯云 WAF 实例 ID",
|
||||
"workflow_node.deploy.form.tencentcloud_waf_instance_id.placeholder": "请输入腾讯云 WAF 实例 ID",
|
||||
"workflow_node.deploy.form.tencentcloud_waf_instance_id.tooltip": "这是什么?请参阅 <a href=\"https://console.cloud.tencent.com/waf\" target=\"_blank\">https://console.cloud.tencent.com/waf</a>",
|
||||
"workflow_node.deploy.form.ucloud_ualb_region.label": "优刻得服务地域",
|
||||
"workflow_node.deploy.form.ucloud_ualb_region.placeholder": "优刻得 UALB 服务地域(例如:cn-bj2)",
|
||||
"workflow_node.deploy.form.ucloud_ualb_region.tooltip": "这是什么?请参阅 <a href=\"https://docs.ucloud.cn/api/summary/regionlist\" target=\"_blank\">https://docs.ucloud.cn/api/summary/regionlist</a>",
|
||||
"workflow_node.deploy.form.ucloud_ualb_resource_type.option.loadbalancer.label": "部署到指定负载均衡器下的全部 HTTPS 监听器",
|
||||
"workflow_node.deploy.form.ucloud_ualb_resource_type.option.listener.label": "部署到指定 HTTPS 监听器",
|
||||
"workflow_node.deploy.form.ucloud_ualb_loadbalancer_id.label": "优刻得 UALB 负载均衡器实例 ID",
|
||||
"workflow_node.deploy.form.ucloud_ualb_loadbalancer_id.placeholder": "请输入优刻得 UALB 负载均衡器实例 ID",
|
||||
"workflow_node.deploy.form.ucloud_ualb_loadbalancer_id.tooltip": "这是什么?请参阅 <a href=\"https://console.ucloud.cn/ulb/alb\" target=\"_blank\">https://console.ucloud.cn/ulb/alb</a>",
|
||||
"workflow_node.deploy.form.ucloud_ualb_listener_id.label": "优刻得 UALB 监听器 ID",
|
||||
"workflow_node.deploy.form.ucloud_ualb_listener_id.placeholder": "请输入优刻得 UALB 监听器 ID",
|
||||
"workflow_node.deploy.form.ucloud_ualb_listener_id.tooltip": "这是什么?请参阅 <a href=\"https://console.ucloud.cn/ulb/alb\" target=\"_blank\">https://console.ucloud.cn/ulb/alb</a>",
|
||||
"workflow_node.deploy.form.ucloud_ualb_snidomain.label": "优刻得 UALB 扩展域名(可选)",
|
||||
"workflow_node.deploy.form.ucloud_ualb_snidomain.placeholder": "请输入优刻得 UALB 扩展域名",
|
||||
"workflow_node.deploy.form.ucloud_ualb_snidomain.help": "提示:不填写时,将替换监听器的默认证书;否则,将替换扩展域名证书。",
|
||||
"workflow_node.deploy.form.ucloud_ucdn_domain_id.label": "优刻得 UCDN 域名 ID",
|
||||
"workflow_node.deploy.form.ucloud_ucdn_domain_id.placeholder": "请输入优刻得 UCDN 域名 ID",
|
||||
"workflow_node.deploy.form.ucloud_ucdn_domain_id.tooltip": "这是什么?请参阅 <a href=\"https://console.ucloud.cn/ucdn\" target=\"_blank\">https://console.ucloud.cn/ucdn</a>",
|
||||
|
||||
Reference in New Issue
Block a user